ReplicaSet
ReplicaSet 副本控制器容客。用 Deployments 控制 ReplicaSet 冀泻,用 ReplicaSet 控制 Pod 的副本數(shù)量桃序。
ReplicaSet 的作用是維護集群中 Pod 數(shù)量的穩(wěn)定棒假。
工作原理
ReplicaSet 是通過一組字段來定義的溯职,包括一個用來可識別可獲得的 Pod 集合的運算符,一個用來標明應(yīng)該維護的副本個數(shù)帽哑,一個用來指定應(yīng)該創(chuàng)建新 Pod 以滿足副本個數(shù)條件時要使用的 Pod 模板谜酒。每個 ReplicaSet 都通過根據(jù)需要創(chuàng)建和刪除 Pod 以使得副本個數(shù)達到期望值,進而實現(xiàn)其存在價值妻枕。當(dāng) ReplicaSet 需要創(chuàng)建新 Pod 時僻族,會使用所提供的 Pod 模板。
ReplicaSet 通過 Pod 上的 metadata.ownerReferences 字段連接到附屬 Pod 屡谐,該字段給出當(dāng)前對象的屬主資源述么。ReplicaSet 所獲得的 Pod 都在其 ownerReferences 字段中包含了屬主 ReplicaSet 的標識信息。正是通過這一連接愕掏,ReplicaSet 知道它所維護的 Pod 集合的狀態(tài)度秘,并據(jù)此計劃其操作行為。
如何使用
雖然 ReplicaSet 可以獨立使用饵撑,但它主要被 Deployments 用作協(xié)調(diào) Pod 創(chuàng)建剑梳、刪除和更新的機制。當(dāng)創(chuàng)建 Deployments 時滑潘,會自動創(chuàng)建 ReplicaSet 垢乙。
創(chuàng)建一個 ReplicaSet
vim replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: nginx
tier: frontend
spec:
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: nginx
image: nginx
kubectl create -f replicaset.yaml
可以看到
replicaset.apps/frontend created
查看
kubectl get all
NAME READY STATUS RESTARTS AGE
pod/frontend-4t9sl 1/1 Running 0 28s
pod/frontend-c85k7 1/1 Running 0 28s
pod/frontend-j4vd9 1/1 Running 0 28s
NAME DESIRED CURRENT READY AGE
replicaset.apps/frontend 3 3 3 28s
可以看到,創(chuàng)建了一個 replicaset 和 三個 Pod 语卤。這時如果刪除一個 Pod 追逮,那么 replicaset 會維持三個 Pod 蓖租,所以會創(chuàng)建一個新的 Pod 。
Deployment
一個 Deployment 控制器為 Pods 和 ReplicaSet 提供聲明式的更新能力羊壹。
Deployment 的使用場景
- 創(chuàng)建 Deployment 以將 ReplicaSet 上線蓖宦。ReplicaSet 在后臺創(chuàng)建 Pods 。檢查 ReplicaSet 的上線狀態(tài)油猫,查看是否成功稠茂。
- 通過更新 Deployment 的 PodTemplateSpec ,聲明 Pod 的新狀態(tài)情妖。新的 RepicaSet 會被創(chuàng)建睬关,Deployment 以受控速率將 Pod 從舊 ReplicaSet 遷移到新 ReplicaSet 。每個新的 ReplicaSet 都會更新 Deployment 的修訂版本毡证。
- 如果 Deployment 的當(dāng)前狀態(tài)不穩(wěn)定电爹,回滾到較早的 Deployment 版本。每次回滾都會更新 Deployment 的修訂版本料睛。
- 擴大 Deployment 規(guī)模以承擔(dān)更多負載丐箩。
- 暫停 Deployment 以應(yīng)用對 PodTemplateSpec 所做的多項修改,然后恢復(fù)其執(zhí)行以啟動新的上線版本恤煞。
- 使用 Deployment 狀態(tài)來判斷上線過程是否出現(xiàn)停滯屎勘。
- 清理不再需要的 ReplicaSet 。
創(chuàng)建 Deployment
vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
# deployment 的名稱
name: nginx-deployment
labels:
app: nginx
spec:
# deployment 由 replicas 指定創(chuàng)建 pod 的數(shù)量
replicas: 3
# deployment 匹配要管理的 Pods
selector:
# 根據(jù)標簽匹配
matchLabels:
app: nginx
# pod 模板
template:
metadata:
# 標簽居扒,deployment 會根據(jù)這個標簽來匹配要管理的 pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
創(chuàng)建
kubectl apply -f deployment.yaml
kubectl get all
可以看到概漱,創(chuàng)建了三個 pod
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-66b6c48dd5-h85lf 1/1 Running 0 3m3s
pod/nginx-deployment-66b6c48dd5-rtm28 1/1 Running 0 3m3s
pod/nginx-deployment-66b6c48dd5-xxjcm 1/1 Running 0 3m3s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-deployment 3/3 3 3 3m3s
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deployment-66b6c48dd5 3 3 3 3m3s
調(diào)整 pod 的數(shù)量,只需要修改 replicas
字段的值喜喂。
有狀態(tài)的應(yīng)用 StatefulSets
StatefulSet 是用來管理有狀態(tài)應(yīng)用的工作負載 API 對象瓤摧。
StatefulSet 用來管理 Deployment 和擴展一組 Pod ,并且能為這些 Pod 提供序號和唯一性保證玉吁。和 Deployment 相同的是照弥,StatefulSet 管理了基于相同容器定義的一組 Pod。不同的是诈茧,StatefulSet 為每個 Pod 維護了一個固定的 ID 产喉。這些 Pod 是基于相同的聲明來創(chuàng)建的捂掰,但是不能相互替換敢会,無論怎么調(diào)度,每個 Pod 都有一個永久不變的 ID 这嚣。
StatefulSet 和其他控制器使用相同的工作模式鸥昏。
vim statefulset.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
name: datadir1
labels:
type: local
spec:
storageClassName: my-storage-class
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/tmp/data1"
---
kind: PersistentVolume
apiVersion: v1
metadata:
name: datadir2
labels:
type: local
spec:
storageClassName: my-storage-class
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/tmp/data2"
---
kind: PersistentVolume
apiVersion: v1
metadata:
name: datadir3
labels:
type: local
spec:
storageClassName: my-storage-class
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/tmp/data3"
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: registry.cn-beijing.aliyuncs.com/qingfeng666/nginx:latest
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: my-storage-class
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
創(chuàng)建
kubectl apply -f statefulset.yaml
kubectl get all
可以看到
NAME READY STATUS RESTARTS AGE
pod/web-0 1/1 Running 0 2m2s
pod/web-1 1/1 Running 0 119s
pod/web-2 1/1 Running 0 116s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/nginx ClusterIP None <none> 80/TCP 2m2s
NAME READY AGE
statefulset.apps/web 3/3 2m2s
查看 pod
kubectl get pod web-0 -o widr
可以看到
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-0 1/1 Running 0 8m26s 10.244.1.72 node1 <none> <none>
DaemonSet 后臺任務(wù)
DaemonSet 確保所有(或者某些)節(jié)點上運行一個 Pod 副本。當(dāng)有節(jié)點加入集群時姐帚,也會為它們新增一個 Pod 吏垮。當(dāng)有節(jié)點從集群移除時,這些 Pod 也會被回收。刪除 DaemonSet 將會刪除它所創(chuàng)建的所有 Pod 膳汪。
DaemonSet 的典型用法
- 在集群的每個節(jié)點上運行 Daemon 唯蝶,比如 glusterd 或 ceph
- 在每個節(jié)點上運行日志收集 Daemon ,比如 flunentd 或 logstash
- 在每個節(jié)點上運行監(jiān)控 Daemon 遗嗽,比如 Prometheus Node Exporter 或 collected
編寫 DaemonSet Spec
創(chuàng)建 DaemonSet
vim daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: registry.cn-beijing.aliyuncs.com/qingfeng666/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
創(chuàng)建
kubectl apply -f daemonset.yaml
可以看到
daemonset.apps/fluentd-elasticsearch created
查看運行的 daemonset
kubectl -n kube-system get po -o wide | grep fluentd
可以看到
fluentd-elasticsearch-7b8jx 1/1 Running 0 5m32s 10.244.0.22 master <none> <none>
fluentd-elasticsearch-wfm9v 1/1 Running 0 5m32s 10.244.2.12 node2 <none> <none>
fluentd-elasticsearch-x2mn9 1/1 Running 0 5m32s 10.244.1.78 node1 <none> <none>
Daemon Pods 是如何調(diào)度的
DaemonSet 確保所有符合條件的節(jié)點都運行該 Pod 的一個副本粘我。通常,運行 Pod 的節(jié)點有 kubernetes 調(diào)度器選擇痹换。不過 DaemonSet Pods 由 DaemonSet 控制器創(chuàng)建和調(diào)度征字。這就帶來了以下問題:
- Pod 行為的不一致性。正常 Pod 在被創(chuàng)建后等待調(diào)度時處于 Pending 狀態(tài)娇豫,DaemonSet Pod 創(chuàng)建后不會處于 pending 狀態(tài)下
- Pod 搶占由默認調(diào)度器處理匙姜。啟用搶占后,DaemonSet 控制器將不再不考慮 Pod 優(yōu)先級和搶占的情況下制定調(diào)度決策
ScheduleDaemonSetPods 允許使用默認調(diào)度器而不是 DaemonSet 控制器來調(diào)度 DaemonSets 冯痢,方法是將 NodeAffinity 條件不是 .spec.nodeName 條件添加到 DaemonSet Pods 氮昧。默認調(diào)度器接下來將 Pod 綁定到模板主機。如果 DaemonSet Pod 的節(jié)點親和性配置已存在浦楣,則被替換郭计。DaemonSet 控制器僅在創(chuàng)建或修改 DaemonSet Pod 時執(zhí)行這些操作,并且不會更改 DaemonSet 的 .spec.template 椒振。
與 Daemon Pods 通信
與 DaemonSet 中的 Pod 通信的幾種模式
- NodeIP 和已知端口:DaemonSet 中的 Pod 可以使用 hostPort 昭伸,從而可以通過節(jié)點 IP 訪問到 Pod∨煊客戶端能通過某種方法獲取節(jié)點 IP 列表庐杨,并且基于此也可以獲取到響應(yīng)的端口。
- DNS:創(chuàng)建具有相同 Pod 選擇器的無頭服務(wù)通過使用 endpoints 資源或從 DNS 中檢索到多個 A 記錄來發(fā)現(xiàn) DaemonSet夹供。
- Service:創(chuàng)建具有相同 Pod 選擇器的服務(wù)灵份,并使用該服務(wù)隨機訪問到某個節(jié)點上的守護進程(沒有辦法訪問到特定節(jié)點)
更新 DaemonSet
如果節(jié)點的標簽被修改,DaemonSet 將立刻向新匹配上的節(jié)點添加 Pod 哮洽,同時刪除不匹配的節(jié)點上的 Pod填渠。
和 Deployments 的區(qū)別
DaemonSet 和 Deployment 非常類似,它們都能創(chuàng)建 Pod鸟辅,并且 Pod 中的進程都不希望被終止(比如 web 服務(wù)器氛什、存儲服務(wù)器)。建議為無狀態(tài)的服務(wù)使用 Deployment 匪凉,比如前段服務(wù)枪眉。對于這些服務(wù)而言,對副本的數(shù)量進行擴容再层、縮容贸铜、平滑升級堡纬,比精確控制 Pod 運行在某個主機上要重要的多。當(dāng)需要 Pod 副本總是運行在全部或特定主機上蒿秦,并需要它們先于其他 Pod 啟動時烤镐,應(yīng)該使用 DaemonSet。
Job
Job 會創(chuàng)建一個或多個 Pod 棍鳖,并確保指定數(shù)量的 Pod 成功終止职车。隨著 Pod 成功結(jié)束,Job 跟蹤記錄成功完成的 Pod 個數(shù)鹊杖。當(dāng)數(shù)量達到指定的成功個數(shù)閾值時悴灵,任務(wù)(即 Job)結(jié)束。刪除 Job 的操作會清除所創(chuàng)建的所有 Pod骂蓖。
Job 可以用來執(zhí)行一次或多次有限次數(shù)的积瞒,或者定期每天執(zhí)行的業(yè)務(wù)。
定義一個 job 登下,計算 π 到小數(shù)點后100位茫孔,并將結(jié)果打印出來
vim job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(100)"]
restartPolicy: Never
backoffLimit: 4
kubectl apply -f job.yaml
可以看到
job.batch/pi created
kubectl get job
可以看到
NAME COMPLETIONS DURATION AGE
pi 0/1 46s 46s
kubectl describe pod pi-h9ww5
可以看到
Name: pi-h9ww5
Namespace: default
Priority: 0
Node: node2/192.168.190.133
Start Time: Thu, 25 Mar 2021 15:15:26 +0800
Labels: controller-uid=16ba5e81-8b9e-4515-904b-013535baa2a6
job-name=pi
Annotations: <none>
Status: Succeeded
IP: 10.244.2.14
IPs:
IP: 10.244.2.14
Controlled By: Job/pi
Containers:
pi:
Container ID: docker://573f0764e80f87bd457a06ff81c65d3982b6478a452d6ad3535718601bc9eb1a
Image: registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26
Image ID: docker-pullable://registry.cn-beijing.aliyuncs.com/google_registry/perl@sha256:97821e418498785bb995b2c7609841ac57df0cc0156a761875db60403be0e1d8
Port: <none>
Host Port: <none>
Command:
perl
-Mbignum=bpi
-wle
print bpi(100)
State: Terminated
Reason: Completed
Exit Code: 0
Started: Thu, 25 Mar 2021 15:18:38 +0800
Finished: Thu, 25 Mar 2021 15:18:38 +0800
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-c9dkq (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
default-token-c9dkq:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-c9dkq
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m36s default-scheduler Successfully assigned default/pi-h9ww5 to node2
Normal Pulling 3m36s kubelet Pulling image "registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26"
Normal Pulled 26s kubelet Successfully pulled image "registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26" in 3m10.737708126s
Normal Created 25s kubelet Created container pi
Normal Started 25s kubelet Started container pi
從所有 pod 里面選擇 jobname 是 pi 的 pod
pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath='{.items[*].metadata.name}')
echo $pods
可以看到
pi-h9ww5
kubectl logs pi-h9ww5
可以看到
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068