本節開始學習 Service。
咱們不該該指望 Kubernetes Pod 是健壯的,而是要假設 Pod 中的容器極可能由於各類緣由發生故障而死掉。Deployment 等 controller 會經過動態建立和銷燬 Pod 來保證應用總體的健壯性。換句話說,Pod 是脆弱的,但應用是健壯的。html
每一個 Pod 都有本身的 IP 地址。當 controller 用新 Pod 替代發生故障的 Pod 時,新 Pod 會分配到新的 IP 地址。這樣就產生了一個問題:node
若是一組 Pod 對外提供服務(好比 HTTP),它們的 IP 頗有可能發生變化,那麼客戶端如何找到並訪問這個服務呢?後端
Kubernetes 給出的解決方案是 Service。api
Kubernetes Service 從邏輯上表明瞭一組 Pod,具體是哪些 Pod 則是由 label 來挑選。Service 有本身 IP,並且這個 IP 是不變的。客戶端只須要訪問 Service 的 IP,Kubernetes 則負責創建和維護 Service 與 Pod 的映射關係。不管後端 Pod 如何變化,對客戶端不會有任何影響,由於 Service 沒有變。服務器
來看個例子,建立下面的這個 Deploymentapp
apiVersion: apps/v1beta1 kind: Deployment metadata: name: httpd spec: replicas: 3 template: metadata: labels: run: httpd spec: containers: - name: httpd image: httpd ports: - containerPort: 80
咱們啓動了三個 Pod,運行 httpd 鏡像,label 是 run: httpd
,Service 將會用這個 label 來挑選 Pod。負載均衡
Pod 分配了各自的 IP,這些 IP 只能被 Kubernetes Cluster 中的容器和節點訪問。ide
接下來建立 Service,其配置文件以下:post
[root@k8s-master k8s]# cat httpd-service.yml apiVersion: v1 kind: Service metadata: name: httpd-service spec: selector: run: httpd ports: - protocal: TCP port: 8080 targetPort: 80
① v1
是 Service 的 apiVersion
。學習
② 指明當前資源的類型爲 Service
。
③ Service 的名字爲 httpd-service
。
④ selector
指明挑選那些 label 爲 run: httpd
的 Pod 做爲 Service 的後端。
⑤ 將 Service 的 8080 端口映射到 Pod 的 80 端口,使用 TCP 協議。
執行 kubectl apply
建立 Service httpd-service
。
httpd-service
分配到一個 CLUSTER-IP 10.111.195.121
。能夠經過該 IP 訪問後端的 httpd Pod。
根據前面的端口映射,這裏要使用 8080 端口。另外,除了咱們建立的 httpd-service
,還有一個 Service kubernetes
,Cluster 內部經過這個 Service 訪問 kubernetes API Server。
經過 kubectl describe
能夠查看 httpd-svc
與 Pod 的對應關係。Endpoints中的地址正好和前面的建立的3個pod的地址相對應
Service Cluster IP 是一個虛擬 IP,是由 Kubernetes 節點上的 iptables 規則管理的。
能夠經過 iptables-save
命令打印出當前節點的 iptables 規則,由於輸出較多,這裏只截取與httpd-service Cluster IP 10.111.195.121
相關的信息
這兩條規則的含義是:
若是 Cluster 內的 Pod(源地址來自 10.244.0.0/16)要訪問 httpd-service
,則容許。
其餘源地址訪問 httpd-service
,跳轉到規則KUBE-SVC-X2P42VLQEZCHLPKZ。
KUBE-SVC-X2P42VLQEZCHLPKZ 規則以下:
1/3 的機率跳轉到規則 KUBE-SEP-XXIX5IS7GC2GUSM2
1/3 的機率(剩下 2/3 的一半)跳轉到規則 KUBE-SEP-LXY54WDLWY2BJFLU
1/3 的機率跳轉到規則 KUBE-SEP-R7HFCFW5PWEDBIAO
上面的轉發規則經過DNAT目標地址轉換來實現請求轉發
iptables 將訪問 Service 的流量轉發到後端 Pod,並且使用相似輪詢的負載均衡策略。
另外須要補充一點:Cluster 的每個節點都配置了相同的 iptables 規則,這樣就確保了整個 Cluster 都可以經過 Service 的 Cluster IP 訪問 Service。
每一個節點均可以經過統一clusterIP 來訪問,並且自動實現了應用之間的負載均衡。
在 Cluster 中,除了能夠經過 Cluster IP 訪問 Service,Kubernetes 還提供了更爲方便的 DNS 訪問。
kubeadm 部署時會默認安裝 kube-dns 組件。
kube-dns 是一個 DNS 服務器。每當有新的 Service 被建立,kube-dns 會添加該 Service 的 DNS 記錄。Cluster 中的 Pod 能夠經過 <SERVICE_NAME>.<NAMESPACE_NAME>
訪問 Service。
好比能夠用 httpd-service.default
訪問 Service httpd-service
。
如上所示,咱們在一個臨時的 busybox Pod 中驗證了 DNS 的有效性。另外,因爲這個 Pod 與 httpd-service
同屬於 default
namespace,能夠省略 default
直接用 httpd-service
訪問 Service。
若是要訪問其餘 namespace 中的 Service,就必須帶上 namesapce 了。kubectl get namespace
查看已有的 namespace。
在 kube-public
中部署 Service httpd2-service
,配置以下:
apiVersion: apps/v1beta1 kind: Deployment metadata: name: httpd2 namespace: kube-public spec: replicas: 3 template: metadata: labels: run: httpd2 spec: containers: - name: httpd2 image: httpd ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: httpd2-service namespace: kube-public spec: selector: run: httpd2 ports: - protocol: TCP port: 8080 targetPort: 80
查看 kube-public
的 Service:
除了 Cluster 內部能夠訪問 Service,不少狀況咱們也但願應用的 Service 可以暴露給 Cluster 外部。Kubernetes 提供了多種類型的 Service,默認是 ClusterIP。
ClusterIP
Service 經過 Cluster 內部的 IP 對外提供服務,只有 Cluster 內的節點和 Pod 可訪問,這是默認的 Service 類型,前面實驗中的 Service 都是 ClusterIP。
NodePort
Service 經過 Cluster 節點的靜態端口對外提供服務。Cluster 外部能夠經過 <NodeIP>:<NodePort>
訪問 Service。
LoadBalancer
Service 利用 cloud provider 特有的 load balancer 對外提供服務,cloud provider 負責將 load balancer 的流量導向 Service。目前支持的 cloud provider 有 GCP、AWS、Azur 等。
下面咱們來實踐 NodePort,Service httpd-service
的配置文件修改以下:
添加 type: NodePort
,從新建立 httpd-service
。
Kubernetes 依然會爲 httpd-svc
分配一個 ClusterIP,不一樣的是:
EXTERNAL-IP
爲 nodes
,表示可經過 Cluster 每一個節點自身的 IP 訪問 Service。
PORT(S)
爲 8080:31650
8080
是 ClusterIP 監聽的端口,32312
則是節點上監聽的端口。Kubernetes 會從 30000-32767 中分配一個可用的端口,每一個節點都會監聽此端口並將請求轉發給 Service。
下面測試 NodePort 是否正常工做。
經過三個節點 IP + 31650 端口都可以訪問 httpd-servicee
。
接下來咱們深刻探討一個問題:Kubernetes 是如何將 <NodeIP>:<NodePort>
映射到 Pod 的呢?
與 ClusterIP 同樣,也是藉助了 iptables。與 ClusterIP 相比,每一個節點的 iptables 中都增長了下面兩條規則
規則的含義是:訪問當前節點 32312
端口的請求會應用規則 KUBE-SVC-X2P42VLQEZCHLPKZ ,內容爲:
其做用就是負載均衡到每個 Pod。
NodePort 默認是的隨機選擇,不過咱們能夠用 nodePort
指定某個特定端口
如今配置文件中就有三個 Port 了:nodePort
是節點上監聽的端口。port
是 ClusterIP 上監聽的端口。targetPort
是 Pod 監聽的端口。
最終,Node 和 ClusterIP 在各自端口上接收到的請求都會經過 iptables 轉發到 Pod 的 targetPort
。
應用新的 nodePort
並驗證:
nodePort: 30000
已經生效了。