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 需要 apiVersion
、kind
和 metadata
欄位。對於 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 拒絕。
注意事項
如果兩個 ReplicaSet 指定相同的.spec.selector
,但 .spec.template.metadata.labels
和 .spec.template.spec
欄位不同,則每個 ReplicaSet 都會忽略另一個 ReplicaSet 建立的 Pod。副本數
您可以透過設定 .spec.replicas
來指定應同時執行的 Pod 數量。ReplicaSet 將建立/刪除 Pod 以符合此數量。
如果您未指定 .spec.replicas
,則預設值為 1。
使用 ReplicaSet
刪除 ReplicaSet 及其 Pod
若要刪除 ReplicaSet 及其所有 Pod,請使用 kubectl delete
。垃圾收集器預設會自動刪除所有相依的 Pod。
當使用 REST API 或 client-go
程式庫時,您必須在 -d
選項中將 propagationPolicy
設定為 Background
或 Foreground
。例如
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 的規模
- Pending(和無法排程)的 Pod 會優先縮減規模
- 如果設定了
controller.kubernetes.io/pod-deletion-cost
註解,則具有較低值的 Pod 將優先。 - 節點上具有較多副本數的 Pod 優先於節點上具有較少副本數的 Pod。
- 如果 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 刪除順序。
- 使用者應避免頻繁更新註解,例如根據指標值更新註解,因為這樣做會在 API 伺服器上產生大量的 Pod 更新。
使用案例範例
應用程式的不同 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(建議)
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。
接下來是什麼
- 了解 Pod。
- 了解 Deployment。
- 使用 Deployment 執行無狀態應用程式,這依賴 ReplicaSet 才能運作。
ReplicaSet
是 Kubernetes REST API 中的頂層資源。閱讀 ReplicaSet 物件定義以了解 ReplicaSet 的 API。- 閱讀關於 PodDisruptionBudget 以及如何使用它在干擾期間管理應用程式可用性。