欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Kubernetes Service之ClusterIP

程序员文章站 2024-03-11 10:41:31
...

转载自麦兜搞ip的博客Kubernetes Service之ClusterIP

Kubernetes Service ClusterIP

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

创建Deployment

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

这个Deployment有四个Replica。

$ more deployment_python_http.yml
apiVersion:  apps/v1
kind: Deployment
metadata:
  name: service-test
spec:
  replicas: 4
  selector:
    matchLabels:
      app: service_test_pod
  template:
    metadata:
      labels:
        app: service_test_pod
    spec:
      containers:
      - name: simple-http
        image: python:2.7
        imagePullPolicy: IfNotPresent
        command: ["/bin/bash"]
        args: ["-c", "echo \"<p>Hello from $(hostname)</p>\" > index.html; python -m SimpleHTTPServer 8080"]
        ports:
        - name: http
          containerPort: 8080
$ kubectl create -f deployment_python_http.yml
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上了,不知道大家明白没有。