在 Kubernetes 中 Service 主要有4種不同的類型,其中的 ClusterIP 是最基礎的,如下圖所示:
當我們創建一個 NodePort 的 Service 時,它也會創建一個 ClusterIP,而如果你創建一個 LoadBalancer,它就會創建一個 NodePort,然后創建一個 ClusterIP
此外我們還需要明白 Service 是指向 pods 的,Service 不是直接指向 Deployments 或 ReplicaSets,而是直接使用 labels 標簽指向 Pod,這種方式就提供了極大的靈活性,因為通過什么方式創建的 Pod 其實并不重要。接下來我們通過一個簡單的例子開始,我們用不同的 Service 類型來逐步擴展,看看這些 Service 是如何建立的。
No Services
最開始我們沒有任何的 Services。
我們有兩個節點,一個 Pod,節點有外網(4.4.4.1、4.4.4.2)和內網(1.1.1.1、1.1.1.2)的 IP 地址,pod-python 這個 Pod 只有一個內部的 IP 地址。
現在我們添加第二個名為 pod-nginx 的 Pod,它被調度在 node-1 節點上。在 Kubernetes 中,所有的 Pod 之間都可以通過 Pod 的 IP 進行通信,不管它們運行在哪個節點上。這意味著 pod-nginx 可以使用其內部IP 1.1.1.3 來 ping 和連接 pod-python 這個 Pod。
現在如果 pod-python 掛掉了重新創建了一個新的 pod-python 出來(本文不涉及如何管理和控制 pods),重新分配了一個新的 1.1.1.5 的 Pod IP 地址,這個時候 pod-nginx 就無法再達到 1.1.1.3 這個之前的地址了,為了防止這種情況發生,我們就需要創建一個 Service 服務了!
?
ClusterIP
和上面同樣的場景,但是我們創建了一個名為 service-python 類型為 ClusterIP 的 Service 服務,一個 Service 并不像 Pod 那樣運行在一個特定的節點上,這里我們可以假設一個 Service 只是在整個集群內部的內存中可用就可以了。
pod-nginx 可以安全地連接到 1.1.10.1 這個 ClusterIP 或直接通過 dns 名service-python 進行通信,并被重定向到后面一個可用的 Pod 上去。
現在我們來稍微擴展下這個示例,啟動3個 python 實例,現在我們來顯示所有 Pod 和 Service 內部 IP 地址的端口。
集群內部的所有 Pods 都可以通過?http://1.1.10.1:3000
?或者?http://service-python:3000
?來訪問到后面的 python pods 的443端口。
service-python?這個 Service ?是隨機或輪詢的方式來轉發請求的,這個就是 ClusterIP Service 的作用,它通過一個名稱和一個 IP 讓集群內部的 Pods 可用。
上圖中的 service-python 這個 Service 可以用下面的 yaml 文件來創建:
apiVersion:?v1
kind:?Service
metadata:name:?service-python
spec:ports:-?port:?3000protocol:?TCPtargetPort:?443selector:run:?pod-pythontype:?ClusterIP
創建后,可以用?kubectl get svc
?命令來查看:
NodePort
現在我們想讓 ClusterIP Service 可以從集群外部進行訪問,為此我們需要把它轉換成 NodePort 類型的 Service,在我們的例子中,我們只需要簡單修改上面的?service-python?這個 Service 服務即可:
apiVersion:?v1
kind:?Service
metadata:name:?service-python
spec:ports:-?port:?3000protocol:?TCPtargetPort:?443nodePort:?30080selector:run:?pod-pythontype:?NodePort
更新完成后,如下圖所示:
這意味著我們的內部的?service-python?這個 Service 現在也可以通過30080 端口從每個節點的內部和外部 IP 地址進行訪問了。
集群內部的 Pod 也可以通過內網節點 IP 連接到 30080 端口。
運行?kubectl get svc
?命令來查看這個 NodePort 的 Service,可以看到同樣有一個 ClusterIP,只是類型和額外的節點端口不同。在內部,NodePort 服務仍然像之前的 ClusterIP 服務一樣。
LoadBalancer
如果我們希望有一個單獨的 IP 地址,將請求分配給所有的外部節點IP(比如使用 round robin),我們就可以使用 LoadBalancer 服務,所以它是建立在 NodePort 服務之上的。
一個 LoadBalancer 服務創建了一個 NodePort 服務,NodePort 服務創建了一個 ClusterIP 服務。我們也只需要將服務類型更改為 LoadBalancer 即可。
apiVersion:?v1
kind:?Service
metadata:name:?service-python
spec:ports:-?port:?3000protocol:?TCPtargetPort:?443nodePort:?30080selector:run:?pod-pythontype:?LoadBalancer
LoadBalancer 服務所做的就是創建一個 NodePort 服務,此外,它還會向托管 Kubernetes 集群的提供商發送一條消息,要求設置一個指向所有外部節點 IP 和特定 nodePort 端口的負載均衡器,當然前提條件是要提供商支持。
現在運行?kubectl get svc
?可以看到新增了 external-IP 和 LoadBalancer 的類型。
LoadBalancer 服務仍然像和以前一樣在節點內部和外部 IP 上打開 30080 端口。
ExternalName
最后是 ExternalName 服務,這個服務和前面的幾種類型的服務有點分離。它創建一個內部服務,其端點指向一個 DNS 名。
我們假設 pod-nginx 運行在 Kubernetes 集群中,但是 python api 服務在集群外部。
這里?pod-nginx?這個 Pod 可以直接通過 http://remote.server.url.com 連接到外部的 python api 服務上去,但是如果我們考慮到以后某個時間節點希望把這個 python api 服務集成到 Kubernetes 集群中去,還不希望去更改連接的地址,這個時候我們就可以創建一個 ExternalName 類型的 Service 服務了。
對應的 YAML 資源清單文件如下所示:
kind:?Service
apiVersion:?v1
metadata:name:?service-python
spec:ports:-?port:?3000protocol:?TCPtargetPort:?443type:?ExternalNameexternalName:?remote.server.url.com
現在?pod-nginx?就可以很方便地通過?http://service-python:3000
?進行通信了,就像使用 ClusterIP 服務一樣,當我們決定將 python api 這個服務也遷移到我們 Kubernetes 集群中時,我們只需要將服務改為 ClusterIP 服務,并設置正確的標簽即可,其他都不需要更改了。
到這里我們就用 13 張圖將 Kubernetes 中的 Service 解釋得明明白白清清楚楚真真切切了。
原文鏈接:https://medium.com/swlh/kubernetes-services-simply-visually-explained-2d84e58d70e5
本文轉載自:「K8s 技術圈」,原文:https://tinyurl.com/y5v5hcuk,版權歸原作者所有
?
?
?