Pod 已經成功運行起來了,可是有兩個問題。html
一是這些 Pod 沒法從集羣外部直接訪問到,二是 Pod 出現故障自愈後,IP 會發生變化。前端
如何解決這兩個問題,這裏有一個很是重要的概念:Servicenode
Service 是由 kube-proxy 組件加上 iptables/LVS 共同實現。
說白了就是經過 kube-proxy 生成了一堆 iptables 規則,經過 iptables 規則來轉發數據。linux
iptables 轉發:nginx
LVS轉發:算法
建立 Pod 和 默認Service,進行默認工做狀態的測試。後端
先建立3個 Podapi
cat nginx.yaml微信
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80
建立一個默認類型的 Service,名稱爲 nginx-service網絡
cat nginx-service.yaml
apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - port: 80 targetPort: 80 protocol: TCP
port: 80
是 service 在集羣內部的VIP端口
targetPort: 80
是 Pod 的端口
執行建立
kubectl apply -f nginx.yaml kubectl apply -f nginx-service.yaml
查看運行狀況
[root@master01 ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-d46f5678b-cldf4 1/1 Running 0 21m 192.10.137.153 work03 <none> <none> nginx-deployment-d46f5678b-lnxh9 1/1 Running 0 21m 192.10.205.252 work01 <none> <none> nginx-deployment-d46f5678b-th8xq 1/1 Running 0 21m 192.10.75.89 work02 <none> <none> [root@master01 ~]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service ClusterIP 192.20.150.26 <none> 80/TCP 13m
查看名稱爲 nginx-service 的 service 成功掛載的後端 Pod
[root@master01 ~]# kubectl get endpoints nginx-service NAME ENDPOINTS AGE nginx-service 192.10.137.153:80,192.10.205.252:80,192.10.75.89:80 14m
能夠看到咱們建立的名爲 nginx-service 的 Service 後端掛載了3個 Pod
給3個 Pod 寫入內容,訪問 Pod 時返回自身的主機名
kubectl exec nginx-deployment-d46f5678b-cldf4 -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; kubectl exec nginx-deployment-d46f5678b-lnxh9 -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; kubectl exec nginx-deployment-d46f5678b-th8xq -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html';
咱們訪問 Service IP 看看
[root@master01 ~]# curl 192.20.150.26 nginx-deployment-d46f5678b-th8xq [root@master01 ~]# curl 192.20.150.26 nginx-deployment-d46f5678b-cldf4 [root@master01 ~]# curl 192.20.150.26 nginx-deployment-d46f5678b-lnxh9
能夠看到 Service 成功將請求代理到了後端的一組 Pod,而且進行了流量的分配。
這是 Service 的默認工做類型,只能在集羣所屬的節點上訪問到,離開集羣后沒法被訪問到。
這種工做類型叫作 ClusterIP。
上一節能夠看到,Service 默認不對集羣外部提供服務,那麼如何才能在集羣外部訪問到呢,有三種方案。
Service 中配置能夠 externalIPs,IP 爲本集羣中 work 節點宿主機 IP。
apiVersion: v1 kind: Service 。。。 。。。 spec: 。。。 。。。 externalIPs: - 192.168.10.16 - 192.168.10.17
在 192.168.10.16/17 上執行 ss -lntp 能夠看到 Service 定義的暴露端口。
在集羣外部訪問 192.168.10.16/17 上 Service 暴露的端口便可。
改造 nginx-service.yaml,增長一行 type: NodePort
cat nginx-service.yaml
apiVersion: v1 kind: Service metadata: name: nginx-service spec: type: NodePort selector: app: nginx ports: - port: 80 targetPort: 80 protocol: TCP
建立 service
kubectl apply -f nginx-service.yaml
查看運行狀況
[root@master01 ~]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service NodePort 192.20.167.221 <none> 80:30913/TCP 13m
參數 PORT(S) 80:30913/TCP,其中 30913 就是用來集羣外部訪問的端口。
能夠訪問任何一臺物理宿主機的 ip:30913 來訪問到 Pod。
30913 是 K8S 從固定範圍 30000-32767 中選擇的,也能夠經過參數 nodePort 指定固定端口。
可選擇範圍能夠經過 kube-apiserver 的 –service-node-port-range 參數來修改。
[root@master01 ~]# ss -nltp | grep 30913 LISTEN 0 128 *:30913 *:*
能夠看到宿主機上監聽了 30913 端口。
測試
在沒有運行 K8S 集羣的機器上訪問 K8S 宿主機 [root@192-168-10-18 ~]# curl 192.168.10.12:30913 nginx-deployment-d46f5678b-2pmts [root@192-168-10-18 ~]# curl 192.168.10.12:30913 nginx-deployment-d46f5678b-zv8m4 [root@192-168-10-18 ~]# curl 192.168.10.12:30913 nginx-deployment-d46f5678b-2pmts
能夠看到從集羣外部能夠成功訪問到 Pod 中內容,而且爲隨機分配。
原理
kube-proxy 在宿主機上建立了 iptables 規則,對宿主機 IP:30913 的訪問將被轉發到 Service IP,而後 Service 再經過本身的 iptables 規則分發到 Pod
NodePort 方式中,若是要正式對外提供服務,咱們須要在集羣外部再建立一個高可用的負載均衡器,以方便把流量轉發到宿主機開放的端口上,若是宿主機開放端口發生了變動,咱們須要手工修改前端負載均衡器。
公有云的 LoadBalancer 自動化了這一過程。
LoadBalancer 這種方式應用於公有云,提交一個 type: LoadBalancer 的 Service 建立申請後,公有云會幫咱們建立一個負載均衡器,該負載均衡器會把請求直接分發給 Pod,同時 Pod IP 發生變化後,會自動更新到負載均衡器上。
經過指定 spec.clusterIP 的值爲 "None" 能夠建立 Headless Service。
Headless Service 不會分配 Cluster IP,kube-proxy 不會處理它們, 並且平臺也不會爲它們進行負載均衡和路由。
定義了 selector 的無頭服務,Endpoint 控制器會在 API 中建立 Endpoints 記錄, 而且修改 DNS 配置返回 A 記錄,經過這個地址,請求能夠直接到達 Service 的後端 Pod 上。
Service 對 IP 信息易變的 Pod 提供了服務發現、負載均衡等管理功能,同時提供了外部訪問的能力,從而使外部用戶可以穩定的訪問到運行在集羣內部的 Pod 提供的服務。
上面說的三種工做方式有以下問題:
這些問題致使沒法直接應用於生產環境中。
若是想提供給自建集羣的生產環境使用,須要在 Service 前面再加一層 Ingress Controller。
微信公衆號:zuolinux_com