歡迎光臨
每天分享高質量文章

漫畫 | 小黃人學 Kubernetes Service

——3小時後——
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了(如下圖):
  1. kind: Service

  2. apiVersion: v1

  3. metadata:

  4.  name: frontend-svc

  5. spec:

  6.  selector:

  7.    app: frontend

  8.  ports:

  9.    - protocol: TCP

  10.      port: 80

  11.      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上,我們可以看到以下環境變數:

  1. REDIS_MASTER_SERVICE_HOST=172.17.0.6

  2. REDIS_MASTER_SERVICE_PORT=6379

  3. REDIS_MASTER_PORT=tcp://172.17.0.6:6379

  4. REDIS_MASTER_PORT_6379_TCP=tcp://172.17.0.6:6379

  5. REDIS_MASTER_PORT_6379_TCP_PROTO=tcp

  6. REDIS_MASTER_PORT_6379_TCP_PORT=6379

  7. 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 和 NodePort
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集群外再搭一個反向代理就可以更方便地進行訪問了。
  • NodePort和ClusterIP會被自動創建,外部的load balancer會自動路由上去

  • Service 會在一個靜態的端口上被暴露

  • 通過底層的cloud provider提供的load balancer來暴露到外網

LoadBalancer這個Service type只有在底層的基礎架構支持了自動創建load balancer的時候kubernetes才支持,比如Google Cloud Platform和aws。

ExternalName
ExternalName是一個特定的Service type,這種Service type沒有任何的selector也沒有任何宣告的endpoint。當在集群中訪問到這個Service 的時候,會傳回一個外部服務的CNAME。
這個service一般是用來讓一個外部的服務在集群內部可以訪問到的,比如我們有一個外部服務叫做my-database.example.com,那麼我們可以通過設置ExternalName型別的Service,讓內部的其它Service 通過my-database之類的名字訪問到這個服務。

ExternalIP
如果一個Service 可以路由到一個或者多個worker node上,那麼它可以被映射到一個ExternalIP地址。通過這個ExternalIP進入到集群的流量會被路由到其中一個endpoint上。
需要註意的是,ExternalIP並不是由k8s自動管理的,是由管理員手動設置路由到其中的一個node上的,ExternalIP可以和任意Service type來一起指定。
—-1小時後—-
本文轉載自公眾號:K8S中文社區,點擊查看原文

Kubernetes 實戰培訓

本次培訓內容包括:Docker容器的原理與基本操作;容器網絡與儲存解析;Kubernetes的架構與設計理念詳解;Kubernetes的資源物件使用說明;Kubernetes 中的開放接口CRI、CNI、CSI解析;Kubernetes監控、網絡、日誌管理;容器應用的開發流程詳解等,點擊識別下方二維碼加微信好友瞭解具體培訓內容

3月23日開始上課,點擊閱讀原文鏈接即可報名。
赞(0)

分享創造快樂