淺入Kubernetes(7):應用部署例項,Deployment、Service、ReplicaSet

痴者工良發表於2021-04-21

在本文之前,你需要閱讀:

  • 嘗試 kubeadm

https://www.cnblogs.com/whuanle/p/14679590.html

https://www.whuanle.cn/archives/1230

  • CKAD認證中的部署教程

https://www.cnblogs.com/whuanle/p/14679922.html

https://www.whuanle.cn/archives/1231

在此之前,需要使用 kubeadm 部署了 master 節點,然後 最好也部署一個 worker 節點(kubeadm join)。在本篇文章中,我們將部署一個 Nginx 例項,並學會 Deployment 配置、網路對映、副本集。

Deployment

Deployment 是 Kubernetes 提供的一種自我修復機制來解決機器故障維護的問題

當我們單獨使用 docker 部署應用時,為了應用掛了後能夠重啟,我們可以使用 --restart=always 引數,例如:

docker run -itd --restart=always -p 666:80 nginx:latest

但是這種方式只能單純重啟容器,並不具備從機器故障中恢復的能力。

Kubernetes Deployment 是一個配置,它可以指揮 Kubernetes 如何建立和更新你部署的應用例項,建立 Deployment 後,Kubernetes master 會將應用程式排程到叢集中的各個節點上。Kubernetes Deployment 提供了一種與眾不同的應用程式管理方法。

Deployment 的建立,有兩種方法,一種是直接使用命令建立,一種是通過 yaml,後面我們會介紹這兩種建立方法。

建立 Deployment

我們來部署一個 Nginx 應用。

kubectl create deployment nginx --image=nginx:latest

在 worker 節點上執行 docker ps,可以看到:

root@instance-2:~# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
fe7433f906a0   nginx     "/docker-entrypoint.…"   7 seconds ago    Up 6 seconds              k8s_nginx_nginx-55649fd747-wdrjj_default_ea41dcc4-94fe-47f9-a804-5b5b1df703e9_0

獲取所有 deployment :

kubectl get deployments
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           2m24s

使用 kubectl describe deployment nginx 可以獲得更加詳細的資訊。

使用 kubectl get events 可以獲得建立 Deployment 到部署容器過程的詳細事件記錄。

Successfully assigned default/nginx-55649fd747-wdrjj to instance-2
Pulling image "nginx:latest"
Successfully pulled image "nginx:latest" in 8.917597859s
Created container nginx
Started container nginx
Created pod: nginx-55649fd747-wdrjj
Scaled up replica set nginx-55649fd747 to 1

我們也可以使用 yaml 檔案建立 Deployment:

kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml

匯出 yaml

無論哪種部署方式,我們都可以從已經建立的 Deployment 匯出 yaml 檔案,使用 -o yaml 即可匯出(-o json 匯出json)。

kubectl get deployment nginx -o yaml
# 儲存到檔案
# kubectl get deployment nginx -o yaml > mynginx.yaml

然後終端會列印:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2021-04-21T00:37:13Z"
  generation: 1
  labels:
    app: nginx
  name: nginx
  namespace: default
... ...

我們可以嘗試把 yaml 匯出到 mynginx.yaml 檔案中,然後我們刪除這個 Deployment。

kubectl delete deployment ngin

然後利用匯出的 mynginx.yaml 再建立一個 Deployment。

kubectl apply -f mynginx.yaml

kubectl apply/create

當我們建立一個 deployment 時,kubectl createkubectl apply 效果是一樣的,但是 apply 還具有更新(update) 的功能。

kubectl apply 會在以前的配置、提供的輸入和資源的當前配置之間 找出三方差異,以確定如何修改資源,kubectl apply 命令將會把推送的版本與以前的版本進行比較,並應用你所做的更改, 但是不會自動覆蓋任何你沒有指定更改的屬性

另外還有 kubectl replacekubectl editkubectl replace 是破壞性更新/替換,容易導致問題;kubectl edit 可以更新 deployment。

根據 Kubernetes 官方的文件,應始終使用 kubectl applykubectl create --save-config 建立資源。

這裡再說一下建立 deployment 的區別。

如果使用 create 建立,命令格式:

kubectl create deployment {deployment的名字} --image={映象名稱}

如果使用 apply 命令建立,yaml 中需要指定一些資訊:

kind: Deployment
... ...
medatada:
    name:nginx
... ...
    spec:
      containers:
      - image: nginx:latest

然後執行 kubectl apply -f xxx.yaml 檔案。

一個是 kubectl create deployment ;另一個是 kubectl apply -f,在 yaml 中指定 kind: Deployment

有時我們不知道我們的建立命令或 yaml 是否正確,可以使用 --dry-run=client--dry-run=client 引數來預覽而不真正提交。

kubectl create deployment testnginx --image=nginx:latest --dry-run=client

在一些 k8s 認證中,我們沒時間一點點寫 yaml ,但是又需要定製,此時可以使用 --dry-run=client -o yaml ,既可以不生效 Deployment,又可以匯出 yaml 檔案。

kubectl create deployment testnginx --image=nginx:latest --dry-run=client -o yaml

除了 deployment,其它 kubernetes 物件也可以使用這種方法,格式是 kubectl {物件} {引數} --dry-run=client -o yaml

kubernetes 物件/資源,有 deployment、job、role、namespace 等。

還有一個地方也說一下,kubectl get xxx 時,帶不帶 s 都沒關係,例如 kubectl get nodes / kubectl get node 都是一樣的。

不過,一般從語義上,我們獲取全部物件時,可以使用 kubectl get nodes,獲取具體的物件時,可以使用 kubectl get node nginx。類似的,kubectl describe nodeskubectl describe node nginx。實際上加不加 s 都一樣。

網路埠對映和更新 Deployment

對於 docker,我們要對映埠時,可以使用 docker ... -p 6666:80 ,那麼對於 deployment 部署容器應用,我們怎麼處理呢?

我們可以看一下 https://k8s.io/examples/controllers/nginx-deployment.yaml 檔案,

    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

這裡我們不直接使用這個 yaml 檔案,繼續使用之前的 yaml 檔案,我們首先部署一個 nginx。

kubectl apply -f mynginx.yaml

然後修改 mynginx.yaml 檔案,找到 image: nginx:latest,在後面加上埠對映。

    spec:
      containers:
      - image: nginx:latest
        imagePullPolicy: Always
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP
... ...
注:在裡面加上了
        ports:
        - containerPort: 80
          protocol: TCP
          這三行。

然後刪除兩行欄位:

  resourceVersion: "109967"
  uid: e66201e3-a740-4c1c-85f5-a849db40a0fd

因為這兩個欄位限定了版本和 uid ,這樣替換或更新的時候,可以對 nginx 的 deployment 直接操作。

檢視 deployment、pod:

kubectl get deployment,pod
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           5m44s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-55649fd747-9vfrx   1/1     Running   0          5m44s

然後我們建立 service。

kubectl expose deployment nginx

或者指定埠:

kubectl expose deployment nginx --port=80 --target-port=8000

檢視 service:

kubectl get services
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   24h
nginx        ClusterIP   10.101.245.225   <none>        80/TCP    5m57s

檢視 埠:

kubectl get ep
NAME         ENDPOINTS          AGE
kubernetes   10.170.0.2:6443    25h
nginx        192.168.56.24:80   17m

檢視 Pod 資訊資訊:

kubectl describe pod nginx | grep Node:
Node:         instance-2/10.170.0.4

因為 deployment 部署的 應用/pod ,不會在 master 上,不同 Node 是不能訪問的。

使用 kubectl get serviceskubectl get ep 查詢的 ip ,我們可以在 worker 節點上直接訪問。

例如筆者查詢出來的 ip,可以在 worker 中這樣訪問。

curl 192.168.56.24:80
curl 10.101.245.225:80

ReplicaSet

我們執行 kubectl get deployments 命令,輸出:

NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           38m
  • NAME 列出了叢集中 Deployment 的名稱。
  • READY 顯示應用程式的可用的 副本 數。顯示的模式是“就緒個數/期望個數”。
  • UP-TO-DATE 顯示為了達到期望狀態已經更新的副本數。
  • AVAILABLE 顯示應用可供使用者使用的副本數。
  • AGE 顯示應用程式執行的時間。

副本

因為容器化應用中,根據雲原生12因素的方法論和核心思想,一個 Processes 應當是無狀態的,任何持久化的資料都要儲存在後端服務中。因此,A 映象,啟動 N 個 docker 容器,埠為 801、802、803...,他們其實都是一樣的,我們訪問哪個容器,最終提供的服務都是一致的。

但是,如果我們把這些容器放到不同 Node 中,再通過 k8s ,就可以為多個例項之間分配流量,即負載均衡。

在 Deployment 中,可以通過指定 yaml 檔案的 .spec.replicas 欄位或者以命令引數 --replicas= 設定副本數量。

ReplicaSet

“ReplicaSet 的目的是維護一組在任何時候都處於執行狀態的 Pod 副本的穩定集合。 因此,它通常用來保證給定數量的、完全相同的 Pod 的可用性。”

感興趣的讀者可以看文件:https://kubernetes.io/zh/docs/concepts/workloads/controllers/replicaset/

在前面,我們已經建立了 nginx ,接下來我們在這個 deployment 中修改副本數。

kubectl scale deployment nginx --replicas=3

然後等幾秒後執行 kubectl get deployments 檢視結果。

NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3     3            3           3h15m

執行 kubectl get pod -o wide 可以輸出資訊的 pod 資訊 。

NAME       READY   STATUS   ESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
nginx-581   1/1     Running   0     3h11m   192.168.56.24   instance-2   <none>           <none>
nginx-582   1/1     Running   0     3m30s   192.168.56.25   instance-2   <none>           <none>
nginx-583   1/1     Running   0     3m30s   192.168.56.26   instance-2   <none>           <none>
# 注,筆者刪除了Name的部分名稱

可以看到 這幾個 pod 都分配在 instance-2 這個節點上,因為我只有一臺 worker 節點伺服器,如果多建立幾臺節點伺服器,k8s 會自動分配到不同的節點中。什麼的輸出也可以看到,每個 pod 都有自己的 ip 地址。

當我們使用 kubectl delete xxx 刪除 pod 時,Deployment 會自動保持三個副本集,所以會自動啟用新的 pod 。

執行 kubectl get ep 可以看到不同 pod 暴露的 埠。

NAME         ENDPOINTS                                            AGE
kubernetes   10.170.0.2:6443                                      28h
nginx        192.168.56.24:80,192.168.56.25:80,192.168.56.26:80   3h15m

相關文章