转载来自:https://www.imooc.com/article/39964

    Kubernetes Service ClusterIP
    Kubernetes的service有三种类型:ClusterIP,NodePort,LoadBalancer,今天我们来看看ClusterIP。

    创建Deployment
    首先我们先创建一个Deployment,这个Deployment是一个Python实现的HTTP服务,请求这个Web Server的时候,会发回给我们这个server的hostname(如果是container,那就是container的hostname)。
    这个Deployment有四个Replica。

    1. $ more deployment_python_http.yml
    2. apiVersion: apps/v1
    3. kind: Deployment
    4. metadata:
    5. name: service-test
    6. spec:
    7. replicas: 4
    8. selector:
    9. matchLabels:
    10. app: service_test_pod
    11. template:
    12. metadata:
    13. labels:
    14. app: service_test_pod
    15. spec:
    16. containers:
    17. - name: simple-http
    18. image: python:2.7
    19. imagePullPolicy: IfNotPresent
    20. command: ["/bin/bash"]
    21. args: ["-c", "echo \"<p>Hello from $(hostname)</p>\" > index.html; python -m SimpleHTTPServer 8080"]
    22. ports:
    23. - name: http
    24. containerPort: 8080
    25. $ kubectl create -f deployment_python_http.yml
    26. deployment.apps "service-test" created

    创建完我们看到pod是这样的;

    $ kubectl get pod -o wide
    NAME                            READY     STATUS    RESTARTS   AGE       IP          NODE
    service-test-54b5b4b547-8l9s4   1/1       Running   0          1m        10.36.0.0   ks8-node2
    service-test-54b5b4b547-c2t85   1/1       Running   0          1m        10.36.0.1   ks8-node2
    service-test-54b5b4b547-nxn9z   1/1       Running   0          1m        10.40.0.1   k8s-node1
    service-test-54b5b4b547-vlpff   1/1       Running   0          1m        10.40.0.0   k8s-node1
    

    这四个pod IP我们都可以在k8s cluster任意一个节点上访问,每一个都会返回自己的container name。

    $ curl 10.36.0.0:8080
    <p>Hello from service-test-54b5b4b547-8l9s4</p>
    


    创建Service
    通过kubectl expose给刚才这个deployment创建一个service,端口绑定为8088.

    kubectl expose deployment service-test --port 8088 --target-port=8080
    service "service-test" exposed
    

    这样,就给我们生成了一个类型为ClusterIP的service,这个service有一个Cluster IP,其实就一个VIP。

    kubectl get service -o wide
    NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE       SELECTOR
    kubernetes     ClusterIP   10.96.0.1       <none>        443/TCP    1d        <none>
    service-test   ClusterIP   10.101.90.210   <none>        8088/TCP   11s       app=service_test_pod
    

    首先我们可以通过这个Cluster IP加端口8088访问我们的deployment。

    $ for i in `seq 4`; do curl 10.101.90.210:8088; done
    <p>Hello from service-test-54b5b4b547-nxn9z</p>
    <p>Hello from service-test-54b5b4b547-vlpff</p>
    <p>Hello from service-test-54b5b4b547-vlpff</p>
    <p>Hello from service-test-54b5b4b547-nxn9z</p>
    

    并且我们发现,这个VIP实现了负载均衡,每次返回的hostname不同。

    VIP和负载均衡的实现
    为什么我们访问VIP就能访问我们的四个pod,并且还做了负载均衡呢?下面我们就看一下,
    其实呢,我们刚才创建这个deployment,service的时候,k8s集群下面的几个部件参与了相关的工作。

    • apiserver kubectl命令向apiserver发送创建service的命令,apiserver接收到请求以后将数据存储到etcd中。
    • kube-proxy kubernetes的每个节点中都有一个叫做kube-proxy的进程,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables中。
    • iptables 使用NAT等技术将virtualIP的流量转至endpoint中。

    那么IPtable到底是如何转发我们的流量的呢,我们到任意一台k8s节点运行 sudo iptables -L -v -n -t nat
    首先找到我们的ClusterIP 10.101.90.210,发现他在一个iptables chain中

    Chain KUBE-SERVICES (2 references)
     pkts bytes target     prot opt in     out     source               destination
        0     0 KUBE-MARK-MASQ  tcp  --  *      *      !172.100.0.0/16       10.101.90.210        /* default/service-test: cluster IP */ tcp dpt:8088
        0     0 KUBE-SVC-LY73ZDGF4KGO4YFJ  tcp  --  *      *       0.0.0.0/0            10.101.90.210        /* default/service-test: cluster IP */ tcp dpt:8088
    

    这个chain类似一个链条,那么访问10.101.90.210:8088的流量到底怎么被转发了呢,我们需要看一下 KUBE-SVC-LY73ZDGF4KGO4YFJ 这个Chain, 找到这个chain

    Chain KUBE-SVC-LY73ZDGF4KGO4YFJ (1 references)
     pkts bytes target     prot opt in     out     source               destination
        0     0 KUBE-SEP-YOQWVZZ4NQDNEBVN  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/service-test: */ statistic mode random probability 0.25000000000
        0     0 KUBE-SEP-WHOFXZ2VQXEUUKVO  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/service-test: */ statistic mode random probability 0.33332999982
        0     0 KUBE-SEP-3TBKTCTGJZ27RFOH  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/service-test: */ statistic mode random probability 0.50000000000
        0     0 KUBE-SEP-6LDVTIHDBDOU3D3G  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/service-test: */
    

    这个Chain比较有意思,过来的流量它按照随机的概率,分别以0.25000000000, 0.33332999982,0.50000000000的概率,转发到这三个Chain,这三个Chain其实就是我们的pod,那为啥有一个pod不会被转发呢,这个应该是负载均衡的配置,最大几个负载均衡的问题。
    我们随便拿出一个

    Chain KUBE-SEP-WHOFXZ2VQXEUUKVO (1 references)
     pkts bytes target     prot opt in     out     source               destination
        0     0 KUBE-MARK-MASQ  all  --  *      *       10.36.0.1            0.0.0.0/0            /* default/service-test: */
        0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/service-test: */ tcp to:10.36.0.1:8080
    

    好的,那经过这么一转发,我们的流量就可以转发到正确的pod上了,不知道大家明白没有。
    作者:麦兜搞IT
    链接:https://www.imooc.com/article/39964
    来源:慕课网
    本文原创发布于慕课网 ,转载请注明出处,谢谢合作