在了解了k8s的基本原理以後,還是有一些疑惑,就是k8s 中部署的服務如何對外提供服務,pod與pod是如何通信的,k8s内部的服務又是如何做負載均衡的。一個pod挂了,再重新開機拉起來一個pod,是如何加入負載均衡中的,為什麼它拉起來就能提供服務?
直到我了解了k8s中的service,這一切才得到答案。
service是什麼
其實就是k8s中的服務注冊與負載均衡。
最終能夠實作,提供一個唯一的位址,供我們來通路位址,而不需要具體的去了解,這個服務起的Pod的ip是什麼。
怎麼去使用 service呢
其實 k8s 其實可以這樣了解,它就是依賴 yaml的,基本上你能想到的所有的問題,它都是通過配置檔案來完成的,學習k8s的使用,其實就是學習這些yaml配置的含義。就這麼簡單。
看一下對一個service的聲明:其中粉色的框,就就已經說明了這是一個service,然後紅色框,就是通過selector的方式,選出來,名字叫做MyApp的Pod。然後綠色框,代表的是對外提供的端口号。然後整體都有依賴k8s的域名解析的子產品。使用者想要通路這個服務,通路 my-service 就可以通路到服務。9376就是MyApp這個pod提供服務的端口,其實這裡就像是nginx的一個路由映射。你想要通路9376這個端口的服務,并沒有直接通路9376這個端口,而是走了service這一層類似與流量網關做了端口映射。

具體的應用是通過,一個包含上邊内容的 yaml檔案,然後使用指令建立這個網關服務;
- kubectl apply -f service.yaml
或者是用這個指令來建立,結果都一樣
- kubectl created -f service.yaml
檢視建立的結果
- kubectl discribe service
結果如下:
注意看紅框的ip位址,其實就是通過我們上邊的配置的service的yaml,去查找了名字叫做 MyApp的Pod,并且找到了三個。
最後是一個這樣的關系:其中172.29.3.27 是service 的ip,這是被自動配置設定的一個ip。另外service關注的是叫做 MyApp的Pod,而不是具體ip是哪個的pod,這樣pod并沒有和service綁定,它銷毀了,沒有關系,那麼service隻看到另外兩個pod ,如果再加進來兩個pod,也一樣。
如何通路service呢
經過上邊的步驟,其實一個service已經被建立出來了,但是具體如何去通路它呢?方式有三種
- 上邊建立的service其實是被配置設定了一個ip的,同一個叢集内,可以通過這個ip起通路到。
- 第二種方式直接通路服務名,依靠 DNS 解析,就是同一個 namespace 裡 pod 可以直接通過 service 的名字去通路到剛才所聲明的這個 service。不同的 namespace 裡面,我們可以通過 service 名字加“.”,然後加 service 所在的哪個 namespace 去通路這個 service,例如我們直接用 curl 去通路,就是 my-service:80 就可以通路到這個 service。
- 第三種是通過環境變量通路,在同一個 namespace 裡的 pod 啟動時,K8s 會把 service 的一些 IP 位址、端口,以及一些簡單的配置,通過環境變量的方式放到 K8s 的 pod 裡面。在 K8s pod 的容器啟動之後,通過讀取系統的環境變量比讀取到 namespace 裡面其他 service 配置的一個位址,或者是它的端口号等等。比如在叢集的某一個 pod 裡面,可以直接通過 curl $ 取到一個環境變量的值,比如取到 MY_SERVICE_SERVICE_HOST 就是它的一個 IP 位址,MY_SERVICE 就是剛才我們聲明的 MY_SERVICE,SERVICE_PORT 就是它的端口号,這樣也可以請求到叢集裡面的 MY_SERVICE 這個 service。
我你家青睐于第二種方式。第二種方式是依賴k8s的域名解析的。而第一種banding了ip,service一旦挂掉了,就很麻煩了。
## 可以告訴k8s不用給service配置設定ip,這樣就隻能走域名解析了
向叢集外暴露 Service
前面介紹的都是在叢集裡面 node 或者 pod 去通路 service,service 怎麼去向外暴露呢?怎麼把應用實際暴露給公網去通路呢?這裡 service 也有兩種類型去解決這個問題,一個是 NodePort,一個是 LoadBalancer。
- NodePort 的方式就是在叢集的 node 上面(即叢集的節點的主控端上面)去暴露節點上的一個端口,這樣相當于在節點的一個端口上面通路到之後就會再去做一層轉發,轉發到虛拟的 IP 位址上面,就是剛剛主控端上面 service 虛拟 IP 位址。
- LoadBalancer 類型就是在 NodePort 上面又做了一層轉換,剛才所說的 NodePort 其實是叢集裡面每個節點上面一個端口,LoadBalancer 是在所有的節點前又挂一個負載均衡。比如在阿裡雲上挂一個 SLB,這個負載均衡會提供一個統一的入口,并把所有它接觸到的流量負載均衡到每一個叢集節點的 node pod 上面去。然後 node pod 再轉化成 ClusterIP,去通路到實際的 pod 上面。
service的架構設計
最後是對 K8s 設計的一個簡單的分析以及實作的一些原理。
我先用一句話來描述,一個關鍵點,其實用到了k8s的一個核心點DNS,DNS去關注Pod 的生命狀态。可以這樣了解,就像是美團,會有很多商戶入住,然後你打開美團,想要訂酒店,然後美團孤給你提供符合你意向的酒店,美團會主動的維護這個關系,定時的問,你們這家酒店還開不開了,倒閉了,美團就會把這個酒店下架。如果酒店又開了分店,那就同樣添加到清單中來。
Kubernetes 服務發現架構
如上圖所示,K8s 服務發現以及 K8s Service 是這樣整體的一個架構。
K8s 分為 master 節點和 worker 節點:
- master 裡面主要是 K8s 管控的内容;
- worker 節點裡面是實際跑使用者應用的一個地方。
在 K8s master 節點裡面有 APIServer,就是統一管理 K8s 所有對象的地方,所有的元件都會注冊到 APIServer 上面去監聽這個對象的變化,比如說我們剛才的元件 pod 生命周期發生變化,這些事件。
這裡面最關鍵的有三個元件:
- 一個是 Cloud Controller Manager,負責去配置 LoadBalancer 的一個負載均衡器給外部去通路;
- 另外一個就是 Coredns,就是通過 Coredns 去觀測 APIServer 裡面的 service 後端 pod 的一個變化,去配置 service 的 DNS 解析,實作可以通過 service 的名字直接通路到 service 的虛拟 IP,或者是 Headless 類型的 Service 中的 IP 清單的解析;
- 然後在每個 node 裡面會有 kube-proxy 這個元件,它通過監聽 service 以及 pod 變化,然後實際去配置叢集裡面的 node pod 或者是虛拟 IP 位址的一個通路。
實際通路鍊路是什麼樣的呢?比如說從叢集内部的一個 Client Pod3 去通路 Service,就類似于剛才所示範的一個效果。Client Pod3 首先通過 Coredns 這裡去解析出 ServiceIP,Coredns 會傳回給它 ServiceName 所對應的 service IP 是什麼,這個 Client Pod3 就會拿這個 Service IP 去做請求,它的請求到主控端的網絡之後,就會被 kube-proxy 所配置的 iptables 或者 IPVS 去做一層攔截處理,之後去負載均衡到每一個實際的後端 pod 上面去,這樣就實作了一個負載均衡以及服務發現。
對于外部的流量,比如說剛才通過公網通路的一個請求。它是通過外部的一個負載均衡器 Cloud Controller Manager 去監聽 service 的變化之後,去配置的一個負載均衡器,然後轉發到節點上的一個 NodePort 上面去,NodePort 也會經過 kube-proxy 的一個配置的一個 iptables,把 NodePort 的流量轉換成 ClusterIP,緊接着轉換成後端的一個 pod 的 IP 位址,去做負載均衡以及服務發現。這就是整個 K8s 服務發現以及 K8s Service 整體的結構。