k8s中幾個基本概念的理解,pod,service,deployment,ingress的使用場景

2022-09-11 18:02:43

k8s 總體概覽

前言

學習 k8s 之前首先對 k8s 中具體的元件做個簡單的瞭解。

Pod

Pod 是 k8s 中叢集部署應用和服務的最小單元,一個 pod 中可以部署多個容器。

Pod 的設計理念是支援多個容器在一個 Pod 中共用網路地址和檔案系統,可以通過程序間通訊和檔案共用這種簡單高效的方式組合完成服務。Pod 對多容器的支援是 K8 最基礎的設計理念。

副本控制器(Replication Controller,RC)

RC 是 k8s 叢集中最早的保證 Pod 高可用的 API 物件。它的作用就是保證叢集中有指定數目的 pod 執行。

當前執行的 pod 數目少於指定的數目,RC 就會啟動新的 pod 副本,保證執行 pod 數量等於指定數目。

當前執行的 pod 數目大於指定的數目,RC 就會殺死多餘的 pod 副本。

副本集(Replica Set,RS)

RS 是新一代 RC,提供同樣的高可用能力,區別主要在於 RS 後來居上,能支援更多種類的匹配模式。副本集物件一般不單獨使用,而是作為 Deployment 的理想狀態引數使用。

部署(Deployment)

Deployment 提供了一種對 Pod 和 ReplicaSet 的管理方式,每一個 Deployment 都對應叢集中的一次部署,是非常常見的 Kubernetes 物件。

Deployment 是一個比 RS 應用模式更廣的 API 物件,可以用來建立一個新的服務,更新一個新的服務,也可以用來捲動升級一個服務。

捲動升級一個服務,捲動升級一個服務,實際是建立一個新的 RS,然後逐漸將新 RS 中副本數增加到理想狀態,將舊 RS 中的副本數減小到 0 的複合操作;這樣一個複合操作用一個 RS 是不太好描述的,所以用一個更通用的 Deployment 來描述。

服務(Service)

RC、RS 和 Deployment 只是保證了支撐服務的微服務 Pod 的數量。但是沒有解決如何存取這些服務的問題。

一個 Pod 只是一個執行服務的範例,隨時可能在節點上停止,然後再新的節點上用一個新的 IP 啟動一個新的 Pod,因此不能使用確定的 IP 和埠號提供服務。這對於業務來說,就不能根據 Pod 的 IP 作為業務排程。kubernetes 就引入了 Service 的概 念,它為 Pod 提供一個入口,主要通過 Labels 標籤來選擇後端Pod,這時候不論後端 Pod 的 IP 地址如何變更,只要 Pod 的 Labels 標籤沒變,那麼 業務通過 service 排程就不會存在問題。

同時 service 對繫結的 Pod 提供了負載均衡的功能,我們業務直接使用 service 即可。

當宣告Service的時候,會自動生成一個cluster IP,這個IP是虛擬IP。我們就可以通過這個IP來存取後端的Pod,當然,如果叢集設定了DNS服務,比如現在 的CoreDNS,那麼也可以通過Service的名字來存取,它會通過DNS自動解析Service的IP地址。

Service 對外暴露服務的方式

1、ClusterIP (預設) :在叢集的內部 IP 上公開 Service 。這種型別使得 Service 只能從叢集記憶體取,一般這種型別的 Service 上層會掛一個 Ingress,通過 Ingress 暴露服務;

2、NodePort:在每個選定 Node 的相同埠上公開 Service,使用 <NodeIP>:<NodePort> 即可從叢集外部存取 Service;

3、LoadBalancer:使用雲廠商的 K8S 叢集,即可使用這種方式的暴露 Service,自建的服務一般不支援。使用 LoadBalancer ,會生成一個 IP 地址,通過這個即可存取 Service, 通知這個 IP 也是高可用的;

4、ExternalName: 通過返回帶有該名稱的 CNAME 記錄,使用任意名稱(由 spec 中的externalName指定)公開 Service。不使用代理。這種型別需要kube-dns的v1.7或更高版本。

什麼是 CNAME:這種記錄允許您將多個名字對映到同一臺計算機。

例如:當您擁有多個域名需要指向同一伺服器IP,此時您就可以將一個域名做A記錄指向伺服器IP,然後將其他的域名做別名(即CNAME)到A記錄的域名上;那麼當您的伺服器IP地址變更時,您就可以不必對一個一個域名做更改指向了,只需要更改A記錄的那個域名到伺服器新IP上,其他做別名(即CNAME)的那些域名的指向將自動更改到新的IP地址上(以上操作均需要在DNS處執行)。

ingress

Ingress 是反向代理規則,用來規定 HTTP/S 請求應該被轉發到哪個 Service 上,比如根據請求中不同的 Host 和 url 路徑讓請求落到不同的 Service 上。

Ingress Controller 就是一個反向代理程式,它負責解析 Ingress 的反向代理規則,如果 Ingress 有增刪改的變動,所有的 Ingress Controller 都會及時更新自己相應的轉發規則,當 Ingress Controller 收到請求後就會根據這些規則將請求轉發到對應的 Service。

Kubernetes 並沒有自帶 Ingress Controller,它只是一種標準,具體實現有多種,需要自己單獨安裝,常用的是 Nginx Ingress ControllerTraefik Ingress Controller

一個叢集中可以有多個 Ingress Controller, 在Ingress 中可以指定使用哪一個 Ingress Controller

k8s

Ingress Controller 是部署在叢集中的,怎麼讓 Ingress Controller 本身能夠被外面存取到呢?

1、Ingress Controller 用 Deployment 方式部署,給它新增一個 Service,型別為 LoadBalancer,這樣會自動生成一個 IP 地址,通過這個 IP 就能存取到了,並且一般這個 IP 是高可用的(前提是叢集支援 LoadBalancer,通常雲服務提供商才支援,自建叢集一般沒有);

2、使用 hostPort;

  • 1、Ingress Controller 用 DaemonSet 方式部署,使用叢集內部的某個或某些節點作為邊緣節點,給 node 新增 label 來標識,使用 nodeSelector 繫結到邊緣節點,保證每個邊緣節點啟動一個 Ingress Controller 範例,用 hostPort 直接在這些邊緣節點宿主機暴露埠,然後我們可以存取邊緣節點中 Ingress Controller 暴露的埠,這樣外部就可以存取到 Ingress Controller 了;

  • 2、使用非親緣性策略,使需要部署 Ingress Controller 的節點,每個節點都有一個 Ingress Controller 部署,然後用 hostPort 直接在這些邊緣節點宿主機暴露埠,我們就能通過這些節點的 IP 和 hostPort來存取 Ingress Controller 了。

不過使用 hostPort 這種方式,我們還需要再上面部署一層負載均衡。

什麼是 hostPort

這是一種直接定義 Pod 網路的方式。

hostPort 是直接將容器的埠與所排程的節點上的埠路由,這樣使用者就可以通過宿主機的 IP 加上來存取 Pod 了,比如:

apiVersion: v1
kind: Pod
metadata:
  name: influxdb
spec:
  containers:
    - name: influxdb
      image: influxdb
      ports:
        - containerPort: 8086
          hostPort: 8086

節點(Node)

k8s 中通過將容器放入到節點 Node 上執行的 Pod 中來執行工作負載。 k8s 中的計算能力就是由 node 提供。

節點可以是物理機也可以是虛擬機器器,取決於叢集的設定,通常 k8s 叢集中,有越多的 node 節點,意味著有更強的計算能力。

名稱空間(Namespace)

名稱空間為 Kubernetes 叢集提供虛擬的隔離作用,Kubernetes 叢集初始有兩個名稱空間,分別是預設名稱空間 default 和系統名稱空間 kube-system,除此以外,管理員可以可以建立新的名稱空間滿足需要。

名稱空間適用於存在很多跨多個團隊或專案的使用者的場景。對於只有幾到幾十個使用者的叢集,根本不需要建立或考慮名稱空間。

k8s 中的部署過程

這裡用一個簡單的栗子來看下,看下 k8s 中應用的部署過程。

1、建立名稱空間

$ kubectl create namespace study-k8s

2、使用 deployment 部署 pod

$ cat go-web.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: go-web
  name: go-web
  namespace: study-k8s
spec:
  replicas: 5
  selector:
    matchLabels:
      app: go-web
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: go-web
    spec:
      containers:
      - image: liz2019/test-docker-go-hub
        name: go-app-container
        resources: {}
status: {}

執行

$ kubectl apply -f go-web.yaml  -n study-k8s

$ kubectl get pods  -n study-k8s
NAME                      READY   STATUS    RESTARTS   AGE
go-web-59f7dc559c-g2hjg   1/1     Running   0          5h21m
go-web-59f7dc559c-g6p8k   1/1     Running   0          5h21m
go-web-59f7dc559c-l4fgm   1/1     Running   0          5h21m
go-web-59f7dc559c-lqvpj   1/1     Running   0          5h21m
go-web-59f7dc559c-rrdjp   1/1     Running   0          5h21m

$ kubectl describe deployment nginx-deploy  -n  study-k8s
Name:                   go-web
Namespace:              study-k8s
CreationTimestamp:      Wed, 07 Sep 2022 15:33:58 +0800
Labels:                 app=go-web
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=go-web
Replicas:               5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=go-web
  Containers:
   go-app-container:
    Image:        liz2019/test-docker-go-hub
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   go-web-59f7dc559c (5/5 replicas created)
Events:          <none>

Deployment 為 Pod 和 Replica Set 提供宣告式更新。所以可以看到建立的 Deployment 裡面就同時也建立好了 Replica Set

3、為服務建立 service

上面我們建立了一組 Pod ,接下來,我們藉助於 service 來實現對這些 Pod 的存取。

$ cat go-web-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: go-web-svc
  labels:
    run: go-web-svc
spec:
  selector:
    app: go-web
  ports:
    - protocol: TCP
      port: 8000
      targetPort: 8000
      name: go-web-http

執行

$ kubectl apply -f go-web-svc.yaml -n study-k8s

$  kubectl get svc -n study-k8s
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
go-web-svc   ClusterIP   10.233.9.188   <none>        8000/TCP   37s

$ kubectl describe svc go-web-svc  -n  study-k8s
Name:              go-web-svc
Namespace:         study-k8s
Labels:            run=go-web-svc
Annotations:       <none>
Selector:          app=go-web
Type:              ClusterIP
IP:                10.233.9.188
Port:              go-web-http  8000/TCP
TargetPort:        8000/TCP
Endpoints:         10.233.111.104:8000,10.233.111.105:8000,10.233.111.106:8000 + 2 more...
Session Affinity:  None
Events:            <none>

可以看到 service 已經建立完成。

4、設定 ingress 的轉發策略

service 已經建立成功了,接下來我們使用 ingress

$ cat go-web-ingress.yaml    
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: go-web-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: www.go-web.com
    http:
      paths:
      - path: /index
        pathType: Prefix
        backend:
          service:
            name: go-web-svc
            port:
              number: 8000

部署 ingress

$ kubectl apply -f go-web-ingress.yaml -n study-k8s

$ kubectl get ingress -n study-k8s
NAME             CLASS    HOSTS            ADDRESS         PORTS   AGE
go-web-ingress   <none>   www.go-web.com   11.11.111.113   80      107s

通過 ingress 存取

$ curl '11.11.111.113:80/index' \
--header 'Host: www.go-web.com'

<h1>hello world</h1><div>你好</div>%

也可以在本地新增 host,通過域名存取

$ sudo vi /etc/hosts

// 根據ingress部署的iP
11.11.111.113 www.liz-test.com
k8s

總結

1、Pod 是 k8s 中叢集部署應用和服務的最小單元;

2、RC 是 k8s 叢集中最早的保證 Pod 高可用的 API 物件。它的作用就是保證叢集中有指定數目的 pod 執行;

3、RS 是新一代 RC,提供同樣的高可用能力,是目前主要使用的物件;

4、Deployment 提供了一種對 Pod 和 ReplicaSet 的管理方式,RS 的使用都是結合 Deployment 來完成的。

5、一般使用 Deployment 來捲動升級一個服務,捲動升級一個服務,實際是建立一個新的 RS,然後逐漸將新 RS 中副本數增加到理想狀態,將舊 RS 中的副本數減小到 0 的複合操作;這樣一個複合操作用一個 RS 是不太好描述的,所以用一個更通用的 Deployment 來描述。

6、RC、RS 和 Deployment 只是保證了支撐服務的微服務 Pod 的數量。但是沒有解決如何存取這些服務的問題。一個 Pod 只是一個執行服務的範例,隨時可能在節點上停止,然後再新的節點上用一個新的 IP 啟動一個新的 Pod,因此不能使用確定的 IP 和埠號提供服務。這對於業務來說,就不能根據 Pod 的 IP 作為業務排程。kubernetes 就引入了 Service 的概 念,它為 Pod 提供一個入口,主要通過 Labels 標籤來選擇後端Pod,這時候不論後端 Pod 的 IP 地址如何變更,只要 Pod 的 Labels 標籤沒變,那麼 業務通過 service 排程就不會存在問題。

7、Service 是後端真實服務的抽象,一個 Service 可以代表多個相同的後端服務;

8、Ingress 是反向代理規則,用來規定 HTTP/S 請求應該被轉發到哪個 Service 上,比如根據請求中不同的 Host 和 url 路徑讓請求落到不同的 Service 上;

參考

【Kubernetes 的設計理念】https://jimmysong.io/kubernetes-handbook/concepts/concepts.html
【Kubernetes中文檔案】http://docs.kubernetes.org.cn/
【通俗理解Kubernetes中Service、Ingress與Ingress Controller的作用與關係】https://cloud.tencent.com/developer/article/1167282
【CNAME記錄】https://zh.m.wikipedia.org/zh-hans/CNAME記錄
【CNAME】https://baike.baidu.com/item/CNAME/9845877
【k8s中幾個基本概念的理解】https://boilingfrog.github.io/2022/09/11/k8s總體概覽/