環境准備
在使用 service 之前,首先利用 Deployment 創建出 3 個 pod,注意要為 pod 設置 app=nginx-pod
的標簽
apiVersion: apps/v1 kind: Deployment # 類型為 deployment metadata: name: pc-deployment # deployment 的名稱 namespace: zouzou spec: replicas: 3 # 三個副本 selector: # 標簽選擇器 matchLabels: app: nginx-pod template: metadata: labels: # 標簽 app: nginx-pod spec: containers: - name: nginx image: nginx:1.14 ports: # 暴露容器的 80 端口 - containerPort: 80
創建 deployment
[root@dce-10-6-215-215 tmp]# kubectl create -f deployment.yaml deployment.apps/pc-deployment created
查看 pod 的詳情
[root@dce-10-6-215-215 tmp]# kubectl get pod -n zouzou -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx3-c5d7c9466-vnt9c 1/1 Running 0 24h 172.29.34.135 dce-10-6-215-200 <none> <none> pc-deployment-5bff7844cb-6n65j 1/1 Running 0 51s 172.29.190.159 dce-10-6-215-190 <none> <none> pc-deployment-5bff7844cb-vnvhs 1/1 Running 0 51s 172.29.34.223 dce-10-6-215-200 <none> <none> pc-deployment-5bff7844cb-z5ks7 1/1 Running 0 51s 172.29.34.255 dce-10-6-215-200 <none> <none>
為了方便后面的測試,修改下三台 pod 里 nginx 的 index.html 頁面
# 使用下面命令依次更改,注意要換成自己的 pod 名稱 kubectl exec -it pc-deployment-5bff7844cb-vnvhs -n zouzou /bin/sh echo "我是 172.29.34.223 的 pod" > /usr/share/nginx/html/index.html
修改完成之后,我們測試一下,看有沒有修改成功
ClusterIP 類型的 Service
默認的 Service 類型就是 ClusterIP,它只能在集群內部訪問
創建 service-clusterip.yaml 文件
apiVersion: v1 kind: Service # 類型為 Service metadata: name: service-clusterip # Service 的名稱 namespace: zouzou spec: selector: # 標簽選擇器,會和上面創建的 deployment.yaml 的 pod 關聯起來 app: nginx-pod clusterIP: 172.31.88.88 # service 的 ip 地址,如果不寫,默認會生成一個,注意這個地址不能寫,有個范圍的,我的是 172.31.0.0/16 type: ClusterIP # 類型為 Service 的 ClusterIP ports: - port: 8080 # Service 端口,自定義 targetPort: 80 # pod 端口,不寫默認是 80
注意:上面的 service-clusterip.yaml 只是創建一個 service,因為里面的選擇器為 app:nginx-pod,所以會和 deployment.yaml 里的 pod 關聯起來(因為 deployment.yaml 里的標簽也是 app:nginx-pod)
創建 service
# 創建 service [root@dce-10-6-215-215 tmp]# kubectl create -f service-clusterip.yaml service/service-clusterip created
查看 service
# 可以看到 CLUSTER-IP 就是我們設置的 IP 地址,端口是我們寫的 8080,svc 是 service 的簡寫 [root@dce-10-6-215-215 tmp]# kubectl get svc -n zouzou -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service-clusterip ClusterIP 172.31.88.88 <none> 8080/TCP 2m6s app=nginx-pod
查看 service 的詳細信息,可以看到我們的 Selector 選擇的是pod 的標簽為 app=nginx-pod 的 pod。還有個參數是 Session Affinity(Session 親和度),這里為 None,后面在說
還有一個很重要的是 Endpoints,里面有三個 ip 地址,意思就是這個 service 找到了三個 pod,當訪問 service 的時候,會轉發到這三個里面的其中一個上,其實這三個就是我們上面使用 deployment.yaml 創建的三個 pod
# 查看 service 的詳細信息 [root@dce-10-6-215-215 tmp]# kubectl describe svc service-clusterip -n zouzou Name: service-clusterip Namespace: zouzou Labels: <none> Annotations: <none> Selector: app=nginx-pod Type: ClusterIP IP: 172.31.88.88 IPFamily: IPv4 Port: <unset> 8080/TCP TargetPort: 80/TCP Endpoints: 172.29.190.159:80,172.29.34.223:80,172.29.34.255:80 # Endpoints 列表,里面就是當前 service 可以負載到的服務入口 Session Affinity: None # session 親和性 Events: <none>
查看 ipvs 的映射規則
我的有好多,這里找到 service 的 ip 對應的 ip。從下面可以看到,當我們訪問 172.31.88.88:8080 的時候,會采用輪詢的方式訪問下面的三個 ip(也就是我們的 pod),rr 是輪詢的意思
[root@dce-10-6-215-215 tmp]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 127.0.0.1:30001 rr -> 172.28.116.206:80 Masq 1 0 0 TCP 172.31.88.88:8080 rr # 主要看這個和下面的三個 -> 172.29.34.223:80 Masq 1 0 0 -> 172.29.34.255:80 Masq 1 0 0 -> 172.29.190.159:80 Masq 1 0 0 TCP 172.31.122.40:80 rr -> 172.28.116.205:80 Masq 1 0 0
循環訪問下我們的 service 地址,看下是不是采用輪詢的方式
從下面的結果可以看出來,確實是采用輪詢的方式來訪問了我們的 pod
使用域名進行訪問
Service域名格式:$(service name).$(namespace).svc.cluster.local
,其中 cluster.local 為指定的集群的域名
例如上面的就可以寫成
service-clusterip.zouzou.svc.cluster.local
Endpoints
Endpoint 是 kubernetes 中的一個資源對象,存儲在 etcd 中,用來記錄一個 service 對應的所有 pod 的訪問地址,它是根據 service 配置文件中 selector 描述產生的。
一個 Service 由一組 Pod 組成,這些 Pod 通過 Endpoints 暴露出來,Endpoints 是實現實際服務的端點集合。換句話說,service 和 pod 之間的聯系是通過 endpoints 實現的。
我們可以通過下面的命令查看 Endpoint
# 會返回所有的,因為我這里只有一個 service,所以只有一個 [root@dce-10-6-215-215 tmp]# kubectl get endpoints -n zouzou -o wide NAME ENDPOINTS AGE service-clusterip 172.29.190.159:80,172.29.34.223:80,172.29.34.255:80 20m
負載分發策略
對 Service 的訪問被分發到了后端的 Pod 上去,目前 kubernetes 提供了兩種負載分發策略:
-
如果不定義,默認使用 kube-proxy 的策略,比如隨機、輪詢
- 基於客戶端地址的會話保持模式,即來自同一個客戶端發起的所有請求都會轉發到固定的一個 Pod 上
此模式可以使在 spec 中添加 sessionAffinity: ClientIP
選項
修改 service-clusterip.yaml ,加上 sessionAffinity: ClientIP
apiVersion: v1 kind: Service # 類型為 Service metadata: name: service-clusterip # Service 的名稱 namespace: zouzou spec: sessionAffinity: ClientIP # 來自同一個客戶端發起的所有請求都會轉發到固定的一個 Pod 上 selector: # 標簽選擇器,會和上面創建的 deployment.yaml 的 pod 關聯起來 app: nginx-pod clusterIP: 172.31.88.88 # service 的 ip 地址,如果不寫,默認會生成一個 type: ClusterIP # 類型為 Service 的 ClusterIP ports: - port: 8080 # Service 端口,自定義 targetPort: 80 # pod 端口
在 apply 一下
# 也可以刪除 service,在創建 [root@dce-10-6-215-215 tmp]# kubectl apply -f service-clusterip.yaml service/service-clusterip configured
在來查看下 ipvs 的映射規則,可以看到在我們的 service 后面加了個 persistent,表示持久的,即某一個客戶端發起的請求都會分給一個 pod 上
[root@dce-10-6-215-215 tmp]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 127.0.0.1:30001 rr -> 172.28.116.206:80 Masq 1 0 0 TCP 172.31.88.88:8080 rr persistent 10800 -> 172.29.34.223:80 Masq 1 0 0 -> 172.29.34.255:80 Masq 1 0 0 -> 172.29.190.159:80 Masq 1 0 0 TCP 172.31.122.40:80 rr -> 172.28.116.205:80 Masq 1 0 0
在循環訪問下 service,看能不能分給一個固定的 pod
[root@dce-10-6-215-215 tmp]# while true;do curl 172.31.88.88:8080; sleep 5; done; 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod
在用我們的 node 節點訪問
[root@dce-10-6-215-200 ~]# while true;do curl 172.31.88.88:8080; sleep 5; done; 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod
從上面的結果可以看出,當我們設置了 sessionAffinity: ClientIP 后,當某個客戶端訪問 service 的時候,會將這個客戶端的請求分給一個固定的 pod
刪除 service
通過 yaml 文件刪除
kubectl delete -f service-clusterip.yaml
通過 service 的名稱刪除
kubectl delete svc service-clusterip -n zouzou