Contents

k8s doc reading: Concepts - Workload Management - deployments

/posts/20250620_k8s-doc-reading-workload-management-deployments/images/banner.jpeg

doc link

Deployment 是用來幫助執行 stateless 的 pod
stateless:

  • 在 pod 的 replica 之間 不存在任何關聯
  • pod 在 start/restart/stop 後也不存在前後關聯

簡單來說 每個 pod 都是個獨立運作的個體

舉例來說 web-server 就適合使用 deployment

Creating a Deployment

在前面我們使用 範例去新增一個 deployment

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

為了方便說明
我直接使用註解做講解
有一些功能尚未介紹到 就請大家邊看邊學 後面會再做深入介紹

apiVersion: apps/v1 # k8s 是跟 api server 溝通, api 版本會跟著 k8s 升級做異動, 因次升級務必做檢查
kind: Deployment # 告訴 k8s 要建立 deployment
metadata: 
  name: nginx-deployment
  labels: # k8s 在不同 resource 都是透過 labels 去建立關係 
    app: nginx
spec: # 開始定義 deployment 內容
  replicas: 3  # 宣告要建立一個 3 個 replica 的 ReplicaSet
  selector:    # ReplicaSet 的 labels
    matchLabels:
      app: nginx
  template:    # how ReplicaSet create pod
    metadata:
      labels:  # pod's labels
        app: nginx
    spec:  # 開始定義 pod 內容
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

實際操作可以使用官方提供的 manifest 新增一個 deployment

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

然後觀察狀態

$ k get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3   

deployment 就是其中一種 workload resource or 又稱 kind
nginx-deployment 稱之為 object

記得前面有提到, 我們不直接建立 pod 而是透過 workload resources
這個 yaml 是宣告建立一個 kind 是 deployment 的 object
.spec.template 則是建立 ReplicaSet, 另一個 workload resources
ReplicaSet 則會建立 pod

基本上我們不會直接使用 ReplicaSet

關係如下

flowchart TD A[Deployment] -- 控制與管理 --> B(ReplicaSet) B -- 建立並維持副本數量 --> C((Pod 1...n))

關於 label
k8s 的 label 是很重要的觀念
label 用於建立 k8s 不同 object 之間的關係
藉由指定 label 就可以到找對應的 object (一或多個)
這邊來說明這裡所用到的 label
.metadata.labels 是提供給要使用 deplyment 的人使用
舉例 只讓 kubectl 顯示符合 label 的 deplyment object

$ k get deplyment --selector=app=nginx
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           13m

.spec.selector.matchLabels 告訴 ReplicaSet 如何找到 pod 去納管

.spec.template.metadata.labels 指定建立 pod 時該有的 label

READY: 目標要三個 replica 並都已正常啟動 UP-TO-DATE: 顯示如果有任何 pod 已更新完成(如有進行 rolling update 可以觀察此項目)

如要觀察詳細資訊 就使用 describe

$ k describe deploy nginx-deployment 
Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Sat, 21 Jun 2025 00:53:33 +0000
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision: 2
Selector:               app=nginx
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:       app=nginx
  Annotations:  kubectl.kubernetes.io/restartedAt: 2025-06-21T00:58:03Z
  Containers:
   nginx:
    Image:         nginx:1.14.2
    Port:          80/TCP
    Host Port:     0/TCP
    Environment:   <none>
    Mounts:        <none>
  Volumes:         <none>
  Node-Selectors:  <none>
  Tolerations:     <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  nginx-deployment-647677fc66 (0/0 replicas created)
NewReplicaSet:   nginx-deployment-756d74bd9 (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  5m59s  deployment-controller  Scaled up replica set nginx-deployment-647677fc66 from 0 to 3
  Normal  ScalingReplicaSet  89s    deployment-controller  Scaled up replica set nginx-deployment-756d74bd9 from 0 to 1
  Normal  ScalingReplicaSet  88s    deployment-controller  Scaled down replica set nginx-deployment-647677fc66 from 3 to 2
  Normal  ScalingReplicaSet  88s    deployment-controller  Scaled up replica set nginx-deployment-756d74bd9 from 1 to 2
  Normal  ScalingReplicaSet  87s    deployment-controller  Scaled down replica set nginx-deployment-647677fc66 from 2 to 1
  Normal  ScalingReplicaSet  87s    deployment-controller  Scaled up replica set nginx-deployment-756d74bd9 from 2 to 3
  Normal  ScalingReplicaSet  86s    deployment-controller  Scaled down replica set nginx-deployment-647677fc66 from 1 to 0

Updating a Deployment

這邊操作有印象即可
實務來說 我們不會這樣使用
通常會使用 IaC 來進行操作

修改 image tag

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
deployment.apps/nginx-deployment image updated

這時 deployment 會幫我們進行 rolling update
非常的簡單
那如果我設定有問題的 image 呢?

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.16.123
deployment.apps/nginx-deployment image updated

你還是會看到 deployment 顯示 image updated
但是去看 pod 的狀態

$ k get pod 
NAME                                READY   STATUS         RESTARTS   AGE
nginx-deployment-7d7b5bf757-vqm98   0/1     ErrImagePull   0          15s
nginx-deployment-85c89744b4-ddc2p   1/1     Running        0          2m4s
nginx-deployment-85c89744b4-t7qss   1/1     Running        0          105s
nginx-deployment-85c89744b4-wsdzg   1/1     Running        0          104s

$ k get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     1            3           12m

因為這 tag 並不存在
因此 pod STATUS 為 ErrImagePull
deployment 會因為 pod 起不來 因此沒有繼續更新
在新的 pod 尚未能運作前, deployment 並不會把舊的 pod 停掉
因此一個簡易的 canary deploy 就出現了

但也要注意一件事當我們對 deplyment set image 時
並不會拿到一個 fail 的狀態
因為會需要不斷的使用 get pod 觀察 update 狀態
這個問題可以透過 argoCD 解決

另外從 flow 來看 deployment 會先建立另一個 ReplicaSet
並逐步調整兩個 ReplicaSet 的 pod 數量
藉此來 rolling upgrade

graph TD A[Deployment] -- 控制與管理 --> B1(ReplicaSet) A[Deployment] -- 控制與管理 --> B2(ReplicaSet) B1 -- 建立並維持副本數量 --> C1(("tag 1.16.1 Pod 1...n-x")) B2 -- 建立並維持副本數量 --> C2(("tag 1.16.2 Pod 1...x"))

這樣也能夠理解 為什麼中間還要再過一層 ReplicaSet 了

Rolling Back a Deployment update

這邊操作有印象即可
實務來說 我們不會這樣使用
通常會使用 IaC 來進行操作

k8s 會紀錄你的變更紀錄 (預設 10 份)
你可以使用

# get update revision
kubectl rollout history deployment/nginx-deployment

# get detail update revision
kubectl rollout history deployment/nginx-deployment --revision=2

# Rolling Back to a Previous Revision 
kubectl rollout undo deployment/nginx-deployment --to-revision=2

Scaling a Deployment

如何修改範例的 replica 數量
可以使用

kubectl scale deployment/nginx-deployment --replicas=10

但平常我們都會採用 auto scale
因此人工 scale 只有在特殊狀況使用

比如說我想暫時把 deploymnet 停了
就可以使用 --replicas=0 而不必 delete replica

kubectl scale deployment/nginx-deployment --replicas=0

Failed Deployment

前面有故意將 images tag 改為 1.16.123
並看到 pod 出現 ErrImagePull
如果你使用 k describe pod 可以看到更多細節

這邊就不贅述所有狀態了
基本上養成善用 describe 來進行 debug 就是了

update Strategy

預設情況下 k8s 採用 RollingUpdate
也就是逐步更新
可以使用 Recreate
來一次行更新所有 pod

Rolling Update Deployment strategy

RollingUpdate 可以修改他的行為
default 情況下是

maxUnavailable: default 25%
允許 pod stop 的量
可以用絕對值 or 百分比

當開始 rolling upgrade 時
舊的 replica 會馬上停掉 25%

maxSurge: default 25%
允許 pod start 的量
可以用絕對值 or 百分比

當開始 rolling upgrade 時
新增的 replica 會先啟動 25%

因此只要控制 maxUnavailable, maxSurge 即可控制 rolling upgrade 的流程