linux运维、架构之路-K8s通过Service访问Pod

一、通过Service访问Pod

         每个Pod都有自己的IP地址,当Controller用新的Pod替换发生故障的Pod时,新Pod会分配到新的IP地址,例如:有一组Pod对外提供HTTP服务,它们的IP很可能发生变化,那么客户端如何找到并访问这个服务呢,Service由此而生。Service从逻辑上代表了一组Pod,具体是哪些则由label来挑选,Service有自己的IP,并且这个IP是不变的,客户端只需要访问Service IP,无论后端Pod如何变化,对客户端访问不会有任何影响,k8s负责建立和维护Service与Pod映射关系。

1、创建Service

①创建示例文件

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: httpd
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: httpd     #Service将会用这个label来挑选Pod
    spec:
      containers:
      - name: httpd
        image: httpd
        ports:
        - containerPort: 80

②创建一个Httpd的Deployment应用

[root@k8s-node1 ~]# kubectl apply -f httpd.yaml 
deployment.extensions "httpd" created

[root@k8s-node1 ~]# kubectl get pod -o wide
NAME                    READY     STATUS    RESTARTS   AGE       IP            NODE
httpd-fcdb8b4d8-bzsq8   1/1       Running   0          2m        10.2.72.180   192.168.56.12
httpd-fcdb8b4d8-k5ds9   1/1       Running   0          2m        10.2.72.182   192.168.56.12
httpd-fcdb8b4d8-ks4qq   1/1       Running   0          2m        10.2.72.181   192.168.56.12

上图Pod分配了各自的IP,这些IP只能被k8s集群中的容器和节点访问

[root@k8s-node2 ~]# curl 10.2.72.180
<html><body><h1>It works!</h1></body></html>

③创建Service文件

apiVersion: v1      #Service的apiVersion
kind: Service       #资源类型
metadata:
  name: httpd-svc   #Service的名字
spec:
  selector: 
    app: httpd      #标签选择,挑选哪些label为app: httpd的Pod作为Service的后端
  ports:
  - protocol: TCP   #将Service的8080端口映射到Pod的80端口,使用TCP协议
    port: 8080
    targetPort: 80

④创建Service并查看

[root@k8s-node1 ~]# kubectl apply -f httpd-svc.yaml 
service "httpd-svc" created

[root@k8s-node1 ~]# kubectl get service
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
httpd-svc    ClusterIP   10.1.168.37   <none>        8080/TCP   7s
kubernetes   ClusterIP   10.1.0.1      <none>        443/TCP    8d

httpd-svc分配到一个集群IP,可以通过该IP访问后端的Pod

[root@k8s-node2 ~]# curl 10.1.168.37:8080
<html><body><h1>It works!</h1></body></html>

⑤查看httpd-svc和Pod的对应关系

[root@k8s-node1 ~]# kubectl describe service httpd-svc 
Name:              httpd-svc
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"httpd-svc","namespace":"default"},"spec":{"ports":[{"port":8080,"protocol":"TC...
Selector:          app=httpd
Type:              ClusterIP
IP:                10.1.168.37
Port:              <unset>  8080/TCP
TargetPort:        80/TCP
Endpoints:         10.2.72.180:80,10.2.72.181:80,10.2.72.182:80
Session Affinity:  None
Events:            <none>

Service的Cluster IP是通过iptables映射到Pod中

2、DNS访问Service

①k8s集群中的DNS服务

[root@k8s-node1 ~]# kubectl get deployment --namespace=kube-system 
NAME                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
coredns                2         2         2            2           4d
heapster               1         1         1            1           4d

coredns插件是一个DNS服务,当有新的Service被创建,就会添加到DNS记录,集群中的Pod可以通过SERVICE_NAME访问Service

②创建示例

[root@k8s-node1 ~]# kubectl run busybox --rm -it --image=busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # 
/ # 
/ # 
/ # 
/ # 
/ # wget httpd-svc.default:8080
Connecting to httpd-svc.default:8080 (10.1.168.37:8080)
saving to 'index.html'
index.html           100% |*************************************************************************|    45  0:00:00 ETA
'index.html' saved

同一个命名空间下,busybox Pod可以直接通过httpd-svc访问Service,这也验证了DNS的效性。

不同命名空间下,访问Service需要带上namespace,

wget httpd-svc.demon:8080

二、外网访问Service

  • 1、ClusterIP
  • Service通过Cluster内部的IP对外提供服务,只有集群内的节点和Pod可以访问,这是默认的Service类型
  • 2、NodePort
  • Service通过Cluster节点的静态端口对外提供服务,Cluster外部可以通过NodeIP:访问Service
  • 3、LoadBalancer
  • Service 利用cloud provider特有的load balancer对外提供服务,cloud provider负责将load balancer的流量导向Service,目前支持GCP、AWS、Azur等

1、NodePort

①创建示例文件

apiVersion: v1
kind: Service
metadata:
  name: httpd-svc
spec:
  type: NodePort
  selector: 
    app: httpd
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80

②创建并查看

[root@k8s-node1 ~]# kubectl apply -f httpd-svc.yaml 
service "httpd-svc" created
[root@k8s-node1 ~]# kubectl get svc httpd-svc 
NAME        TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
httpd-svc   NodePort   10.1.186.145   <none>        8080:57643/TCP   12s

1、EXTERNAL-IP为nodes,表示可以通过Cluster每个节点自身的IP访问Service
2、PORT(S) 8080:57643,8080是ClusterIP监听的端口,57643刚是节点上监听的端口,k8s默认会从30000~32767这个范围内分配一个可用的端口,每个节点都会监听此端口,并将请求转发给Service

③测试NodePort

[root@k8s-node1 ~]# curl 192.168.56.12:57643
<html><body><h1>It works!</h1></body></html>

NodePort与ClusterIP一样,也是通过iptables规则实现,负载均衡到每一个Pod,NodePort默认的是随机选择,也可以指定某个固定端口

apiVersion: v1
kind: Service
metadata:
  name: httpd-svc
spec:
  type: NodePort
  selector: 
    app: httpd
  ports:
  - protocol: TCP
    nodePort: 30000        #指节点上监听的端口
    port: 8080             #指ClusterIP上监听的端口
    targetPort: 80         #指Pod监听的端口

Node和ClusterIP在各自端口上接收到的请求都会通过iptables转发到Pod的targetPort

posted @ 2019-12-12 17:59  闫新江  阅读(1269)  评论(0编辑  收藏  举报