ReplicaSet

ReplicaSet 的目的是在任何給定時間維護一組穩定的副本 Pod。通常,您會定義 Deployment,並讓該 Deployment 自動管理 ReplicaSet。

ReplicaSet 的目的是在任何給定時間維護一組穩定的副本 Pod。因此,它通常用於保證指定數量的相同 Pod 的可用性。

ReplicaSet 的運作方式

ReplicaSet 是使用欄位定義的,包括一個選擇器,用於指定如何識別它可以取得的 Pod、一個副本數量,指示它應該維護多少個 Pod,以及一個 Pod 範本,指定它應該建立以滿足副本數量標準的新 Pod 的資料。然後,ReplicaSet 透過根據需要建立和刪除 Pod 來實現其目的,以達到所需的數量。當 ReplicaSet 需要建立新的 Pod 時,它會使用其 Pod 範本。

ReplicaSet 透過 Pod 的 metadata.ownerReferences 欄位連結到其 Pod,該欄位指定目前物件的擁有者是哪個資源。ReplicaSet 取得的所有 Pod 在其 ownerReferences 欄位中都有其擁有的 ReplicaSet 的識別資訊。ReplicaSet 透過此連結得知其維護的 Pod 的狀態,並據此進行規劃。

ReplicaSet 透過使用其選擇器來識別要取得的新 Pod。如果有一個 Pod 沒有 OwnerReference 或 OwnerReference 不是 Controller,並且它符合 ReplicaSet 的選擇器,則該 ReplicaSet 將立即取得它。

何時使用 ReplicaSet

ReplicaSet 確保在任何給定時間都執行指定數量的 Pod 副本。但是,Deployment 是一個更高層級的概念,它可以管理 ReplicaSet,並提供 Pod 的宣告式更新以及許多其他有用的功能。因此,除非您需要自訂更新協調或根本不需要更新,否則我們建議使用 Deployment 而不是直接使用 ReplicaSet。

這實際上表示您可能永遠不需要操作 ReplicaSet 物件:改為使用 Deployment,並在 spec 區段中定義您的應用程式。

範例

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  # modify replicas according to your case
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: php-redis
        image: us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5

將此 Manifest 儲存到 frontend.yaml 並將其提交到 Kubernetes 叢集將建立已定義的 ReplicaSet 及其管理的 Pod。

kubectl apply -f https://kubernetes.dev.org.tw/examples/controllers/frontend.yaml

然後您可以取得目前部署的 ReplicaSet

kubectl get rs

並查看您建立的前端 ReplicaSet

NAME       DESIRED   CURRENT   READY   AGE
frontend   3         3         3       6s

您也可以檢查 ReplicaSet 的狀態

kubectl describe rs/frontend

您將看到類似以下的輸出

Name:         frontend
Namespace:    default
Selector:     tier=frontend
Labels:       app=guestbook
              tier=frontend
Annotations:  <none>
Replicas:     3 current / 3 desired
Pods Status:  3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  tier=frontend
  Containers:
   php-redis:
    Image:        us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age   From                   Message
  ----    ------            ----  ----                   -------
  Normal  SuccessfulCreate  13s   replicaset-controller  Created pod: frontend-gbgfx
  Normal  SuccessfulCreate  13s   replicaset-controller  Created pod: frontend-rwz57
  Normal  SuccessfulCreate  13s   replicaset-controller  Created pod: frontend-wkl7w

最後,您可以檢查啟動的 Pod

kubectl get pods

您應該會看到類似以下的 Pod 資訊

NAME             READY   STATUS    RESTARTS   AGE
frontend-gbgfx   1/1     Running   0          10m
frontend-rwz57   1/1     Running   0          10m
frontend-wkl7w   1/1     Running   0          10m

您也可以驗證這些 Pod 的擁有者參考是否設定為前端 ReplicaSet。若要執行此操作,請取得其中一個執行中 Pod 的 YAML

kubectl get pods frontend-gbgfx -o yaml

輸出將看起來與此類似,前端 ReplicaSet 的資訊設定在 metadata 的 ownerReferences 欄位中

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2024-02-28T22:30:44Z"
  generateName: frontend-
  labels:
    tier: frontend
  name: frontend-gbgfx
  namespace: default
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet
    name: frontend
    uid: e129deca-f864-481b-bb16-b27abfd92292
...

非範本 Pod 取得

雖然您可以建立裸 Pod 而沒有問題,但強烈建議您確保裸 Pod 沒有與您的其中一個 ReplicaSet 的選擇器相符的標籤。原因是 ReplicaSet 不僅限於擁有其範本指定的 Pod,它還可以以前幾節中指定的方式取得其他 Pod。

以前面的前端 ReplicaSet 範例,以及以下 Manifest 中指定的 Pod 為例

apiVersion: v1
kind: Pod
metadata:
  name: pod1
  labels:
    tier: frontend
spec:
  containers:
  - name: hello1
    image: gcr.io/google-samples/hello-app:2.0

---

apiVersion: v1
kind: Pod
metadata:
  name: pod2
  labels:
    tier: frontend
spec:
  containers:
  - name: hello2
    image: gcr.io/google-samples/hello-app:1.0

由於這些 Pod 沒有 Controller(或任何物件)作為其擁有者參考,並且符合前端 ReplicaSet 的選擇器,因此它們將立即被其取得。

假設您在前前端 ReplicaSet 部署並設定其初始 Pod 副本以滿足其副本計數要求後建立 Pod

kubectl apply -f https://kubernetes.dev.org.tw/examples/pods/pod-rs.yaml

新的 Pod 將被 ReplicaSet 取得,然後立即終止,因為 ReplicaSet 將超過其所需的計數。

擷取 Pod

kubectl get pods

輸出顯示新的 Pod 要么已終止,要么正在終止過程中

NAME             READY   STATUS        RESTARTS   AGE
frontend-b2zdv   1/1     Running       0          10m
frontend-vcmts   1/1     Running       0          10m
frontend-wtsmm   1/1     Running       0          10m
pod1             0/1     Terminating   0          1s
pod2             0/1     Terminating   0          1s

如果您先建立 Pod

kubectl apply -f https://kubernetes.dev.org.tw/examples/pods/pod-rs.yaml

然後建立 ReplicaSet,但是

kubectl apply -f https://kubernetes.dev.org.tw/examples/controllers/frontend.yaml

您應該會看到 ReplicaSet 已取得 Pod,並且僅根據其 spec 建立新的 Pod,直到其新 Pod 的數量和原始 Pod 的數量與其所需的計數相符。擷取 Pod 時

kubectl get pods

將在其輸出中顯示

NAME             READY   STATUS    RESTARTS   AGE
frontend-hmmj2   1/1     Running   0          9s
pod1             1/1     Running   0          36s
pod2             1/1     Running   0          36s

透過這種方式,ReplicaSet 可以擁有一組非同質的 Pod

撰寫 ReplicaSet Manifest

與所有其他 Kubernetes API 物件一樣,ReplicaSet 需要 apiVersionkindmetadata 欄位。對於 ReplicaSet,kind 始終為 ReplicaSet。

當控制平面為 ReplicaSet 建立新的 Pod 時,ReplicaSet 的 .metadata.name 是命名這些 Pod 的基礎的一部分。ReplicaSet 的名稱必須是有效的 DNS 子網域 值,但這可能會為 Pod 主機名稱產生意外的結果。為了獲得最佳相容性,名稱應遵循 DNS 標籤 的更嚴格規則。

ReplicaSet 也需要 .spec 區段

Pod 範本

.spec.template 是一個 Pod 範本,也需要適當位置的標籤。在我們的 frontend.yaml 範例中,我們有一個標籤:tier: frontend。請注意不要與其他控制器的選擇器重疊,以免它們嘗試採用此 Pod。

對於範本的 重新啟動策略 欄位 .spec.template.spec.restartPolicy,唯一允許的值是 Always,這是預設值。

Pod 選擇器

.spec.selector 欄位是一個 標籤選擇器。如 先前 討論的,這些是用於識別要取得的潛在 Pod 的標籤。在我們的 frontend.yaml 範例中,選擇器是

matchLabels:
  tier: frontend

在 ReplicaSet 中,.spec.template.metadata.labels 必須符合 spec.selector,否則會被 API 拒絕。

副本數

您可以透過設定 .spec.replicas 來指定應同時執行的 Pod 數量。ReplicaSet 將建立/刪除 Pod 以符合此數量。

如果您未指定 .spec.replicas,則預設值為 1。

使用 ReplicaSet

刪除 ReplicaSet 及其 Pod

若要刪除 ReplicaSet 及其所有 Pod,請使用 kubectl delete垃圾收集器預設會自動刪除所有相依的 Pod。

當使用 REST API 或 client-go 程式庫時,您必須在 -d 選項中將 propagationPolicy 設定為 BackgroundForeground。例如

kubectl proxy --port=8080
curl -X DELETE  'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
  -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
  -H "Content-Type: application/json"

僅刪除 ReplicaSet

您可以使用 kubectl delete 並搭配 --cascade=orphan 選項來刪除 ReplicaSet,而不會影響其任何 Pod。當使用 REST API 或 client-go 程式庫時,您必須將 propagationPolicy 設定為 Orphan。例如

kubectl proxy --port=8080
curl -X DELETE  'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
  -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
  -H "Content-Type: application/json"

一旦原始 ReplicaSet 被刪除,您可以建立一個新的 ReplicaSet 來取代它。只要新舊 .spec.selector 相同,新的 ReplicaSet 就會採用舊的 Pod。然而,它不會盡力使現有的 Pod 符合新的、不同的 Pod 範本。若要以受控方式將 Pod 更新為新的規格,請使用 Deployment,因為 ReplicaSet 不直接支援滾動更新。

從 ReplicaSet 隔離 Pod

您可以透過變更 Pod 的標籤,從 ReplicaSet 中移除 Pod。此技術可用於將 Pod 從服務中移除,以進行偵錯、資料復原等。以這種方式移除的 Pod 將會自動被取代(假設副本數沒有同時變更)。

擴展 ReplicaSet

只要更新 .spec.replicas 欄位,就可以輕鬆地向上或向下擴展 ReplicaSet。ReplicaSet 控制器確保所需數量的 Pod 與符合的標籤選擇器可用且可運作。

在縮減規模時,ReplicaSet 控制器會透過排序可用的 Pod 來選擇要刪除哪些 Pod,以根據以下一般演算法優先縮減 Pod 的規模

  1. Pending(和無法排程)的 Pod 會優先縮減規模
  2. 如果設定了 controller.kubernetes.io/pod-deletion-cost 註解,則具有較低值的 Pod 將優先。
  3. 節點上具有較多副本數的 Pod 優先於節點上具有較少副本數的 Pod。
  4. 如果 Pod 的建立時間不同,則較晚建立的 Pod 優先於較早建立的 Pod(建立時間會以整數對數尺度分組)。

如果以上所有條件都相同,則選擇是隨機的。

Pod 刪除成本

功能狀態: Kubernetes v1.22 [beta]

使用 controller.kubernetes.io/pod-deletion-cost 註解,使用者可以設定在縮減 ReplicaSet 規模時,優先移除哪些 Pod 的偏好設定。

註解應設定在 Pod 上,範圍為 [-2147483648, 2147483647]。它代表刪除 Pod 相較於屬於相同 ReplicaSet 的其他 Pod 的成本。具有較低刪除成本的 Pod 優先於具有較高刪除成本的 Pod 刪除。

對於未設定此註解的 Pod,其隱含值為 0;允許負值。無效值將被 API 伺服器拒絕。

此功能為 Beta 版且預設啟用。您可以使用 kube-apiserver 和 kube-controller-manager 中的 功能閘道 PodDeletionCost 來停用它。

使用案例範例

應用程式的不同 Pod 可能具有不同的利用率。在縮減規模時,應用程式可能偏好移除利用率較低的 Pod。為了避免頻繁更新 Pod,應用程式應在發出縮減規模之前更新一次 controller.kubernetes.io/pod-deletion-cost(將註解設定為與 Pod 利用率成比例的值)。如果應用程式本身控制縮減規模,這會有效;例如,Spark 部署的驅動程式 Pod。

ReplicaSet 作為水平 Pod 自動擴充程式目標

ReplicaSet 也可以作為水平 Pod 自動擴充程式 (HPA) 的目標。也就是說,ReplicaSet 可以由 HPA 自動擴充。以下是以我們在前一個範例中建立的 ReplicaSet 為目標的 HPA 範例。

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: frontend-scaler
spec:
  scaleTargetRef:
    kind: ReplicaSet
    name: frontend
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

將此 manifest 儲存到 hpa-rs.yaml 並提交到 Kubernetes 叢集,應會建立定義的 HPA,該 HPA 會根據複製 Pod 的 CPU 使用率自動擴充目標 ReplicaSet。

kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml

或者,您可以使用 kubectl autoscale 命令來完成相同的操作(而且更簡單!)

kubectl autoscale rs frontend --max=10 --min=3 --cpu-percent=50

ReplicaSet 的替代方案

Deployment 是一個可以擁有 ReplicaSet 的物件,並透過宣告式伺服器端滾動更新來更新它們及其 Pod。雖然 ReplicaSet 可以獨立使用,但如今它們主要由 Deployment 使用,作為協調 Pod 建立、刪除和更新的機制。當您使用 Deployment 時,您不必擔心管理它們建立的 ReplicaSet。Deployment 擁有並管理它們的 ReplicaSet。因此,當您需要 ReplicaSet 時,建議使用 Deployment。

裸 Pod

與使用者直接建立 Pod 的情況不同,ReplicaSet 會取代因任何原因被刪除或終止的 Pod,例如節點故障或破壞性節點維護(例如核心升級)。因此,即使您的應用程式只需要單一 Pod,我們也建議您使用 ReplicaSet。可以將其視為類似於程序監管程式,只是它監管多個節點上的多個 Pod,而不是單一節點上的個別程序。ReplicaSet 將本機容器重新啟動委派給節點上的某些代理程式,例如 Kubelet。

Job

對於預期會自行終止的 Pod(即批次工作),請使用 Job 而不是 ReplicaSet。

DaemonSet

對於提供機器層級功能的 Pod(例如機器監控或機器記錄),請使用 DaemonSet 而不是 ReplicaSet。這些 Pod 的生命週期與機器的生命週期相關聯:Pod 需要在其他 Pod 啟動之前在機器上執行,並且在機器準備好重新啟動/關閉時可以安全地終止。

ReplicationController

ReplicaSet 是 ReplicationController 的後繼者。兩者用途相同且行為相似,但 ReplicationController 不支援 標籤使用者指南 中描述的基於集合的選擇器需求。因此,ReplicaSet 優於 ReplicationController。

接下來是什麼

最後修改時間:2024 年 6 月 18 日下午 6:53 PST:新增 LogarithmicScaleDown 功能閘道的文件 (76ec4489c1)