首頁 > 軟體

瞭解Kubernetes中的Service和Endpoint

2022-04-01 13:04:02

Srevice

Service 是將執行在一組 Pods 上的應用程式公開為網路服務的抽象方法。如果我們使用 Deployment 部署 pod,則可以以 Deployment 為物件建立 Service。

在 K8S 中,每個 Pod 都有其自己唯一的 ip 地址,而 Service 可以為多個 Pod(一組)提供相同的 DNS 名,並且可以在他們直接進行負載均衡。

假如有一組 nginx pod,如果 nginx 動態伸縮改變或因為某些原因 ip/埠發生改變,那麼其 ip 和 埠都不是固定的,而且我們很難確定它新擴容的 pod 的地址是什麼,又萬一 pod 被刪除,ip 不再可用。

又假如一組 pod 稱為前端,如 web 服務,另一組 pod 稱為後端,例如 mysql。那麼 前端 如何查詢並跟蹤要連線的 ip 地址,以便前端可以使用工作負載的後端部分?

這真是 Service 要解決的問題。Kubernetes Service 定義了一種抽象:邏輯上的一組 Pod,一種可以存取它們的策略 —— 通常稱為微服務。當使用 Service 為一組 pod (Deployment 的方式建立的)建立服務時,無論我們建立了多少個 pod 副本,這些 pod 怎麼變化,前端不需要關心它們呼叫了哪個後端副本,而且不需要知道後端 pod 的狀態也不需要跟蹤 pod。Service 把前後端的這種關聯抽象化,把它們解耦了。

Service 的建立及現象

現在按照下面的命令快速建立 pod,pod 將會在各個節點中部署執行。

kubectl create deployment nginx --image=nginx:latest --replicas=3
kubectl expose deployment nginx --type=LoadBalancer --port=80

然後執行命令檢視 Service:

kubectl get services

也就是說外部存取埠是 30424。

NAME         TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1        <none>        443/TCP        3d6h
nginx        LoadBalancer   10.101.132.236   <pending>     80:30424/TCP   39s

這時,我們可以通過公網和埠存取這個 Service。

我們可以檢視此 Service 的 yaml 檔案:

kubectl get service nginx -o yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2021-04-23T07:40:35Z"
  labels:
    app: nginx
  name: nginx
  namespace: default
  resourceVersion: "369738"
  uid: 8dc49805-2fc8-4407-adc0-8e31dc24fa79
spec:
  clusterIP: 10.101.132.236
  clusterIPs:
  - 10.101.132.236
  externalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - nodePort: 30424
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer: {}

有了標準的 yaml 檔案模板,我們可以很方便地修改並客製化一個 Service。

我們檢視通過 Deployment 建立的 pod:

kubectl get pods -o wide
NAME                        IP              NODE       NOMINATED NODE   READINESS GATES
nginx-55649fd747-9fzlr    192.168.56.56    instance-2   <none>           <none>
nginx-55649fd747-ckhrw    192.168.56.57    instance-2   <none>           <none>
nginx-55649fd747-ldzkf    192.168.23.138   instance-1   <none>           <none>

注:pod 在哪個節點中執行,我們是不一樣的。

當我們通過外部網路存取時,Service 會自動提供其中一個 pod 給我們,但是這個過程較為複雜,我們這裡先將表面現象。

               ------------
               |          |
--- 公網ip -->  |   pod1   |
               |   pod2  |
               |   pod3  |
               ------------

然後我們通過命令檢視 iptables 設定:

iptables-save

然後查詢 random 關鍵字:

你可以看到有三個 default/nginx, 第一個 pod 被存取的機會都是 0.33333...,然後 2/3 的概率中,2/3 的 0.5 的概率選擇第二個 pod,剩下的 1/3 概率選擇第三個 pod。

如果要存取 pod,可以以任意部署了 nginx pod 的節點的 ip 進行存取。由於 master 不能部署 pod,所以不能通過 master 的 ip 進行存取。

當然,它並不是直接都是 0.33333.. 這樣的,iptables 的規則有點複雜,這裡難以講清楚,我們只需要知道 外網能夠存取 Service,而 Service 通過 iptable 為我們轉發流量。即使 Deployment 部署的 pod 不在同一個節點上, k8s 的 dns 服務等會正確處理的,我們不需要手動設定這些網路。

Service 定義

在上一小節中,介紹了 Service 的建立方法(kubectl expose ...),也介紹了其依賴的 iptables,這裡將繼續學習 Service 的定義方法。

因為之前我們是通過 Deployment 進行操作,直接為一個 deployment 中的 pod (副本)統一對映。當然我們也可以為不同的 pod 進行網路對映。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 6666
      targetPort: 80

這裡我們使用了 selector 選擇器,一般 pod 的 Label 都會有 app,表示此 pod 的名稱(一般是映象名稱)。port、targetPort 分別是 pod 埠、提供給外界存取的埠。

當我們不通過 Deployment 或者 job 等物件處理 pod 時,可以通過 selector 來選擇合適的 pod。

Service 能夠將一個接收 容器或者 pod 的埠 targetPort 對映到任意的 port 埠,port 是外部可以存取的埠。 如果使用 kubectl expose 去對映埠,會預設隨機提供一個 30xxx 埠。而使用 yaml ,預設情況下,targetPort 將被設定為與 port 欄位相同的值。

Endpoint slices

”端點切片(Endpoint Slices) 提供了一種簡單的方法來跟蹤 Kubernetes 叢集中的網路端點 (network endpoints)。它們為 Endpoints 提供了一種可伸縮和可拓展的替代方案。“

在 Kubernetes 中,EndpointSlice 包含對一組網路端點的參照。 指定選擇器後控制面會自動為設定了 選擇算符 的 Kubernetes 服務建立 Endpoint。

也就是說建立 Service(帶選擇運運算元) 會自動建立 Endpiont。

我們檢視預設名稱空間的 endpoint:

kubectl get endpoints
NAME         ENDPOINTS                                            AGE
kubernetes   10.170.0.2:6443                                      3d7h
nginx        192.168.56.24:80,192.168.56.25:80,192.168.56.26:80   59m

這些都是 pod 的 ip 和埠,也就是說,通過 Endpoint 我們跟蹤 Kubernetes 叢集中的網路端點 (network endpoints)變得更加任意。不過這樣解釋是很難明白的,筆者翻了很多次資料,一點點試錯才搞懂。接下來我們一步步來上手操作,然後一點點理解這些操作的含義。

建立 Endpoint、Service

接下來我們手動建立 Service 和 Endpoint 和 ,需要先建立 Service ,再建立 Endpoint (這兩者建立順序可以隨意)。

Service

我們先刪除之前建立的 service。

kubectl delete service nginx

編寫 service.yaml 檔案內容如下如下:

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
    - protocol: TCP
      port: 6666
      targetPort: 80

應用這個 Service:

kubectl apply -f service.yaml

檢視 service :

kubectl get services
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   3d12h
nginx        ClusterIP   10.98.113.242   <none>        6666/TCP    6s

由於此 Service 沒有對映任何 pod 等,因此沒有任何用處,但是此時已經可以給開發人員一個交待了,或者說確定下 nginx 的 Service 埠和地址。至於真正的 nginx 服務,後面再確定。建立 Service 和 Endpoint 的順序是任意的,只是這裡我們提出抽象,先約定 埠,再提供服務,所以先建立 Service。

建立應用

我們隨便找臺 worker 或者 master 節點,建立一個 nginx 容器:

docker run -itd -p 80:80 nginx:latest

為什麼不用 pod,直接建立容器?因為我們處於開發階段,如果把 nginx 改成 mysql,我們要 Debug 呢?測試自己的資料庫呢?要模擬資料呢?我們在生產時再通過 Deployment 建立應用,但是此時我們可以使用自己的資料庫或者本地應用。

官方檔案說:

  • 希望在生產環境中使用外部的資料庫叢集,但測試環境使用自己的資料庫。
  • 希望服務指向另一個 名稱空間(Namespace) 中或其它叢集中的服務。
  • 你正在將工作負載遷移到 Kubernetes。 在評估該方法時,你僅在 Kubernetes 中執行一部分後端。

總之,我們建立了 Service,可以提供了抽象,至於怎麼提供這個服務,我們可以使用 pod ,也可以直接使用命令執行機器上的二進位制程式,也可以通過 docker 提供。而且 mysql 可能是在外部服務提供的,或者 mysql 直接部署在宿主機上,而不使用容器和 pod,我們可以通過 Endpoint 來跟蹤 mysql 服務的埠。

然後查詢這個容器的 ip,:

docker inspect {容器id} | grep IPAddress

筆者得到的是:"IPAddress": "172.17.0.2",可以試試 curl 172.17.0.2 ,看看是否能夠存取 nginx,如果沒問題我們來進行下一步。

建立 Endpoint

建立一個 endpoint.yaml 檔案,內容如下(注意替換ip為你容器存取ip):

apiVersion: v1
kind: Endpoints
metadata:
  name: nginx
subsets:
  - addresses:
      - ip: 172.17.0.2
    ports:
      - port: 80

然後應用 yaml:

kubectl apply -f endpoint.yaml

檢視 endpoint:

kubectl get endpoints
# 不能填寫成 endpoint

然後存取 Service 的 ip:

curl 10.99.142.242:6666

也可以通過公網存取此 IP。

如果 Endpoint 需要跟蹤多個 ip (多個 pod 或者容器或者應用),可以使用:

  - addresses:
      - ip: 172.17.0.2
      - ip: 172.17.0.3
      - ip: 172.17.0.4
      ... ...

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com