Service 是kubernetes中一個很重要的,也是很有用的概念,可以透過Service來將pod進行分組,並提供外網的訪問endpoint。在這個過程中還有比如kube-proxy提供了對Service的訪問。
但pod是一個短暫存在的東西,很可能突然掛瞭然後重啟,這時候ip地址就會改變,所以pod的ip地址並不是靜態的。比如說:
使用者在這張圖裡面透過ip地址訪問到了4個pod,突然其中有一個pod掛了,然後controller又起了一個pod:
這時候使用者就訪問不到了,因為使用者不知道新的ip地址是多少。
Kubernetes為瞭解決這個問題,提供了一個高層的抽象,叫做Service。Service從邏輯上把pod進行分組,並且設定訪問的策略。一般我們是透過label和selector來達到分組的目的的。
透過selector(app=frontend和app=db),我們就可以把這些pod分為兩個邏輯組了。
這個時候,我們再給這兩個邏輯組加上一個名稱,比如frontend-svc和db-svc,就是Service了(如下圖):
kind: Service
apiVersion: v1
metadata:
name: frontend-svc
spec:
selector:
app: frontend
ports:
- protocol: TCP
port: 80
targetPort: 5000
在這個物件模型中,我們建立了一個叫做frontend-svc的Service,這個Service選擇了所有的app=frontend的pod。在預設情況下,每個Service都會有一個cluster內部可以訪問到的ip地址,也被稱為ClusterIP:
當轉發請求的時候,我們可以選擇pod上的標的埠,比如在我們的例子裡面,frontend-svc透過80埠來接受使用者的請求,然後轉發到pod的5000埠。如果標的埠沒有被顯式宣告,那麼會預設轉發到Service接受請求的埠(和service埠一樣)。
一個pod、ip地址和標的埠的元組代表了一個Service的endpoint,比如在這個例子裡面,frontend-svc有3個endpoints,分別是10.0.1.3:5000, 10.0.1.4:5000和10.0.1.5:5000。
所有的worker node都有一個後臺任務,叫做kube-proxy。這個kube-proxy會檢測API Server上對於Service和endpoint的新增或者移除。對於每個新的Service,在每個node上,kube-proxy都會設定相應的iptables的規則來記錄應該轉發的地址。當一個service被刪除的時候,kube-proxy會在所有的pod上移除這些iptables的規則。
我現在已經知道,Service是和kubernetes進行溝通的主要方式,那麼我們就需要有一個辦法來在執行的時候能夠對已有的服務進行發現。請問Kubernetes是如何實現?
方法一: 每個pod在worker node上啟動的時候,kubelet都會透過環境變數把所有目前可用的Service的資訊傳進去。舉個例子,我們有一個叫做redis-master的Service,這個service expose了6379的埠,並且ClusterIP是172.17.0.6,那麼在一個新建立的pod上,我們可以看到以下環境變數:
REDIS_MASTER_SERVICE_HOST=172.17.0.6
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://172.17.0.6:6379
REDIS_MASTER_PORT_6379_TCP=tcp://172.17.0.6:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=172.17.0.6
如果使用這個解決方案,我們必須非常小心啟動服務的順序,因為pod不會獲得自己啟動之後的service的env。
方法二: Kubernetes有一些dns的addon,這些addon會自動為所有Service建立一個類似my-svc.my-namespace.svc.cluster.local的dns解析,並且在同一個Namespace裡面的Service 可以直接用Service name進行訪問。這是最為推薦的方法。
-
是否只能在cluster內部訪問
-
是否同時可以被cluster內部和外部訪問
-
是否是對映到一個叢集外的entity上
可訪問的範圍由Service 的型別決定,Service 的型別可以在建立Service 的時候宣告。
ClusterIP是預設的Service type,一個Service 透過ClusterIP來獲取自己的Virtual IP,這個IP是用來和別的service通訊的,只能在叢集內部被訪問。
NodePort的Service type除了會建立一個ClusterIP之外,還會把所有worker node上的一個30000-32767之間的埠對映到這個Service ,比如假設32233埠對映到了frontend-svc,那麼不管我們連線到哪個worker node,我們都會被轉發到Service 分配的ClusterIP——172.17.0.4。
預設情況下,當expose到有一個nodeport的時候,kubernetes master會自動隨機選擇一個30000-32767之間的port,當然,我們自己也可以手動指定這個port。
NodePort的這個Service type在我們想要讓外網訪問我們服務的時候非常有用,使用者透過訪問node上指定的port就可以訪問到這個Service 。管理員可以在Kubernetes叢集外再搭一個反向代理就可以更方便地進行訪問了。
LoadBalancer這個Service type只有在底層的基礎架構支援了自動建立load balancer的時候kubernetes才支援,比如Google Cloud Platform和aws。
ExternalName是一個特定的Service type,這種Service type沒有任何的selector也沒有任何宣告的endpoint。當在叢集中訪問到這個Service 的時候,會傳回一個外部服務的CNAME。
這個service一般是用來讓一個外部的服務在叢集內部可以訪問到的,比如我們有一個外部服務叫做my-database.example.com,那麼我們可以透過設定ExternalName型別的Service,讓內部的其它Service 透過my-database之類的名字訪問到這個服務。
如果一個Service 可以路由到一個或者多個worker node上,那麼它可以被對映到一個ExternalIP地址。透過這個ExternalIP進入到叢集的流量會被路由到其中一個endpoint上。
需要註意的是,ExternalIP並不是由k8s自動管理的,是由管理員手動設定路由到其中的一個node上的,ExternalIP可以和任意Service type來一起指定。
本次培訓內容包括:Docker容器的原理與基本操作;容器網路與儲存解析;Kubernetes的架構與設計理念詳解;Kubernetes的資源物件使用說明;Kubernetes 中的開放介面CRI、CNI、CSI解析;Kubernetes監控、網路、日誌管理;容器應用的開發流程詳解等,點選識別下方二維碼加微信好友瞭解具體培訓內容。
長按二維碼向我轉賬
受蘋果公司新規定影響,微信 iOS 版的贊賞功能被關閉,可透過二維碼轉賬支援公眾號。