一拳搞定 Kubernetes | 玩转 deployment
本文介绍通过 Kubernetes Deployment 对象如何去控制一个应用。
一、前言
学习目标:
- 创建一个 nginx deployment。
- 使用 kubectl 对 deployment 进行 CRUD。(结合 dashboard 图示)
- 使用 go 客户端进行上述操作。
默认已经安装了 kubernetes。如果没安装,请参考搭建 minikube
二、实战操作
2.1 准备 yaml 文件
按照任务创建一个运行 nginx:1.14.2 Docker 镜像的 Deployment:
1apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
2kind: Deployment
3metadata:
4 name: nginx-deployment
5 namespace: test
6spec:
7 selector:
8 matchLabels:
9 app: nginx
10 replicas: 2 # tells deployment to run 2 pods matching the template
11 template:
12 metadata:
13 labels:
14 app: nginx
15 spec:
16 containers:
17 - name: nginx
18 image: nginx:1.14.2
19 ports:
20 - containerPort: 80
文件说明:
- 在命名空间 test(由 .metadata.namespace 字段标明)创建名为 nginx-deployment(由 .metadata.name 字段标明)的 Deployment。
- 该 Deployment 创建两个(由 .spec.replicas 字段标明)Pod 副本。
- selector 字段定义 Deployment 如何查找要管理的 Pods。 在这里,你只需选择在 Pod 模板中定义的标签(app: nginx)。 不过,更复杂的选择规则是也可能的,只要 Pod 模板本身满足所给规则即可。
- template 字段包含以下子字段:
- Pod 被使用 labels 字段打上 app: nginx 标签。
- Pod 模板规约(即 .template.spec 字段)指示 Pods 运行一个 nginx 容器, 该容器运行版本为 1.14.2 的 nginx Docker Hub镜像。
- 创建一个容器并使用 name 字段将其命名为 nginx。
2.2 创建 Deployment
1. 运行 yaml 文件创建
也可以通过命令直接创建,参考minikube
1kubectl apply -f /XXX/document/note/Kubernetes/test/nginx/deployment.yaml
2. 查看 deployment 创建情况
1kubectl get deployments --namespace=test
输出:
1NAME READY UP-TO-DATE AVAILABLE AGE
2nginx-deployment 2/2 2 2 8d
输出字段说明:
- NAME 列出了集群中 Deployment 的名称。
- READY 显示应用程序的可用的 副本 数。显示的模式是“就绪个数/期望个数”。
- UP-TO-DATE 显示为了达到期望状态已经更新的副本数。
- AVAILABLE 显示应用可供用户使用的副本数。
- AGE 显示应用程序运行的时间。
3. 查看 Deployment 上线状态:
1kubectl rollout status deployment.v1.apps/nginx-deployment --namespace=test
输出:
1deployment "nginx-deployment" successfully rolled out
4. 查看 Deployment 创建的 ReplicaSet(rs):
1kubectl get rs --namespace=test
输出:
1NAME DESIRED CURRENT READY AGE
2nginx-deployment-6b5df77cd8 2 2 2 17h
3nginx-deployment-74f5bf7bd9 0 0 0 8d
4nginx-deployment-7c79566d49 0 0 0 17h
5nginx-deployment-865d6c94c9 0 0 0 17h
6nginx-deployment-fbb99c8b8 0 0 0 17h
输出字段说明:
- NAME 列出名字空间中 ReplicaSet 的名称;
- DESIRED 显示应用的期望副本个数,即在创建 Deployment 时所定义的值。 此为期望状态;
- CURRENT 显示当前运行状态中的副本个数;
- READY 显示应用中有多少副本可以为用户提供服务;
- AGE 显示应用已经运行的时间长度。
5. 展示 Deployment 的更多信息:
1kubectl describe deployment nginx-deployment --namespace=test
输出:
1Name: nginx-deployment
2Namespace: test
3CreationTimestamp: Thu, 01 Oct 2020 17:12:59 +0800
4Labels: <none>
5Annotations: deployment.kubernetes.io/revision: 3
6 kubectl.kubernetes.io/last-applied-configuration:
7 {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"nginx-deployment","namespace":"test"},"spec":{"replicas":...
8Selector: app=nginx
9Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
10StrategyType: RollingUpdate
11MinReadySeconds: 0
12RollingUpdateStrategy: 25% max unavailable, 25% max surge
13Pod Template:
14 Labels: app=nginx
15 Containers:
16 nginx:
17 Image: nginx:1.14.2
18 Port: 80/TCP
19 Host Port: 0/TCP
20 Limits:
21 memory: 200Mi
22 Requests:
23 memory: 100Mi
24 Environment: <none>
25 Mounts: <none>
26 Volumes: <none>
27Conditions:
28 Type Status Reason
29 ---- ------ ------
30 Available True MinimumReplicasAvailable
31 Progressing True NewReplicaSetAvailable
32OldReplicaSets: <none>
33NewReplicaSet: nginx-deployment-fbb99c8b8 (2/2 replicas created)
34Events:
35 Type Reason Age From Message
36 ---- ------ ---- ---- -------
37 Normal ScalingReplicaSet 5m6s deployment-controller Scaled up replica set nginx-deployment-865d6c94c9 to 1
38 Normal ScalingReplicaSet 3m43s deployment-controller Scaled down replica set nginx-deployment-74f5bf7bd9 to 1
39 Normal ScalingReplicaSet 3m43s deployment-controller Scaled up replica set nginx-deployment-fbb99c8b8 to 1
40 Normal ScalingReplicaSet 3m41s deployment-controller Scaled down replica set nginx-deployment-865d6c94c9 to 0
41 Normal ScalingReplicaSet 3m41s deployment-controller Scaled up replica set nginx-deployment-fbb99c8b8 to 2
42 Normal ScalingReplicaSet 3m38s deployment-controller Scaled down replica set nginx-deployment-74f5bf7bd9 to 0
输出字段说明:
- Events rs 根据 deployment 的配置控制 pod 的行为,可以看到当副本数变化时,旧的 rs 缩容到 0,新的 rs 扩容到 2(是从上往下的顺序执行,渐进式,结合下一个小贴士便于理解)。
6. 列出创建的 pods:
1kubectl get pods -l app=nginx --namespace=test
输出:
1NAME READY STATUS RESTARTS AGE
2nginx-deployment-fbb99c8b8-4lpwd 1/1 Running 0 5m28s
3nginx-deployment-fbb99c8b8-tpd4n 1/1 Running 0 5m26s
Deployment 可确保在更新时仅关闭一定数量的 Pod。默认情况下,它确保至少所需 Pods 75% 处于运行状态(最大不可用比例为 25%)。
Deployment 还确保仅所创建 Pod 数量只可能比期望 Pods 数高一点点。 默认情况下,它可确保启动的 Pod 个数比期望个数最多多出 25%(最大峰值 25%)。
7. 查看具体某个 pod 的信息:
1kubectl describe pod nginx-deployment-fbb99c8b8-4lpwd --namespace=test
输出:
1Name: nginx-deployment-fbb99c8b8-4lpwd
2Namespace: test
3Priority: 0
4Node: minikube/192.168.64.3
5Start Time: Fri, 09 Oct 2020 15:40:15 +0800
6Labels: app=nginx
7 pod-template-hash=fbb99c8b8
8Annotations: <none>
9Status: Running
10IP: 172.17.0.9
11IPs:
12 IP: 172.17.0.9
13Controlled By: ReplicaSet/nginx-deployment-fbb99c8b8
14Containers:
15 nginx:
16 Container ID: docker://16da80166234e8f7fdbb2e2bb7accbcc1841213cb2888af6463102675414c00d
17 Image: nginx:1.14.2
18 Image ID: docker-pullable://nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d
19 Port: 80/TCP
20 Host Port: 0/TCP
21 State: Running
22 Started: Fri, 09 Oct 2020 15:40:16 +0800
23 Ready: True
24 Restart Count: 0
25 Limits:
26 memory: 200Mi
27 Requests:
28 memory: 100Mi
29 Environment: <none>
30 Mounts:
31 /var/run/secrets/kubernetes.io/serviceaccount from default-token-pvdh5 (ro)
32Conditions:
33 Type Status
34 Initialized True
35 Ready True
36 ContainersReady True
37 PodScheduled True
38Volumes:
39 default-token-pvdh5:
40 Type: Secret (a volume populated by a Secret)
41 SecretName: default-token-pvdh5
42 Optional: false
43QoS Class: Burstable
44Node-Selectors: <none>
45Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
46 node.kubernetes.io/unreachable:NoExecute for 300s
47Events:
48 Type Reason Age From Message
49 ---- ------ ---- ---- -------
50 Normal Scheduled <unknown> default-scheduler Successfully assigned test/nginx-deployment-fbb99c8b8-4lpwd to minikube
51 Normal Pulled 6m31s kubelet, minikube Container image "nginx:1.14.2" already present on machine
52 Normal Created 6m31s kubelet, minikube Created container nginx
53 Normal Started 6m31s kubelet, minikube Started container nginx
千万别修改。
Deployment 控制器将 pod-template-hash 标签添加到 Deployment 所创建或收留的 每个 ReplicaSet 。
此标签可确保 Deployment 的子 ReplicaSets 不重叠。 标签是通过对 ReplicaSet 的 PodTemplate 进行哈希处理。 所生成的哈希值被添加到 ReplicaSet 选择算符、Pod 模板标签,并存在于在 ReplicaSet 可能拥有的任何现有 Pod 中。
8. 查看 ReplicaSet(rs)的更多信息
1kubectl describe rs nginx-deployment-6b5df77cd8 --namespace=test
输出:
1Name: nginx-deployment-6b5df77cd8
2Namespace: test
3Selector: app=nginx,pod-template-hash=6b5df77cd8
4Labels: app=nginx
5 pod-template-hash=6b5df77cd8
6Annotations: deployment.kubernetes.io/desired-replicas: 2
7 deployment.kubernetes.io/max-replicas: 3
8 deployment.kubernetes.io/revision: 7
9 deployment.kubernetes.io/revision-history: 5
10Controlled By: Deployment/nginx-deployment
11Replicas: 2 current / 2 desired
12Pods Status: 2 Running / 0 Waiting / 0 Succeeded / 0 Failed
13Pod Template:
14 Labels: app=nginx
15 pod-template-hash=6b5df77cd8
16 Containers:
17 nginx:
18 Image: nginx:1.19.3
19 Port: 80/TCP
20 Host Port: 0/TCP
21 Limits:
22 memory: 200Mi
23 Requests:
24 memory: 100Mi
25 Environment: <none>
26 Mounts: <none>
27 Volumes: <none>
28Events: <none>
主要是 selector 和 labels 加了 pod-template-hash 值,和上文 pod 中提到的 pod-template-hash 对应。
2.3 更新 deployment
更新镜像,把 nginx 从 1.14.2 升级到 1.19.3
1. 直接修改配置文件
1apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
2kind: Deployment
3metadata:
4 name: nginx-deployment
5 namespace: test
6spec:
7 selector:
8 matchLabels:
9 app: nginx
10 replicas: 2 # tells deployment to run 2 pods matching the template
11 template:
12 metadata:
13 labels:
14 app: nginx
15 spec:
16 containers:
17 - name: nginx
18 image: nginx:1.19.3
19 ports:
20 - containerPort: 80
再次执行 kubectl apply -f
指令。
2. 执行 kubectl 编辑命令
1kubectl --record deployment.apps/nginx-deployment set image \
2 deployment.v1.apps/nginx-deployment nginx=nginx:1.19.3 --namespace=test
或者
1kubectl set image deployment/nginx-deployment nginx=nginx:1.19.3 --record --namespace=test
或者
1kubectl edit deployment.v1.apps/nginx-deployment --namespace=test
2
3# 等价
4
5kubectl edit deployment/nginx-deployment --namespace=test
编辑效果:
查看新的 pods:
1kubectl get pods -l app=nginx --namespace=test
2
3NAME READY STATUS RESTARTS AGE
4nginx-deployment-6b5df77cd8-lf2cl 1/1 Running 0 69s
5nginx-deployment-6b5df77cd8-n52z6 1/1 Running 0 71s
可以看到和之前的名称都是不一样的。
dashboard可以直观看到:
2.4 删除 deployment
通过名称删除deployment:
1kubectl delete deployment nginx-deployment --namespace=test
2.5 改变副本数来弹性伸缩应用
关键参数 replicas
可以设置 pod 的数量,下面例子把 nginx 变成 4 个。
1. 直接修改配置文件
1apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
2kind: Deployment
3metadata:
4 name: nginx-deployment
5 namespace: test
6spec:
7 selector:
8 matchLabels:
9 app: nginx
10 replicas: 4 # tells deployment to run 2 pods matching the template
11 template:
12 metadata:
13 labels:
14 app: nginx
15 spec:
16 containers:
17 - name: nginx
18 image: nginx:1.19.3
19 ports:
20 - containerPort: 80
再次执行 kubectl apply -f
指令。
查看新的 pods:
1kubectl get pods -l app=nginx --namespace=test
2
3NAME READY STATUS RESTARTS AGE
4nginx-deployment-6b5df77cd8-5b28p 1/1 Running 0 65s
5nginx-deployment-6b5df77cd8-b24xd 1/1 Running 0 65s
6nginx-deployment-6b5df77cd8-lf2cl 1/1 Running 0 17m
7nginx-deployment-6b5df77cd8-n52z6 1/1 Running 0 17m
2. 执行 kubectl 编辑命令
1kubectl scale deployment/nginx-deployment --replicas=10 --namespace=test
扩展点(另起文章学习):
假设集群启用了Pod 的水平自动缩放, 你可以为 Deployment 设置自动缩放器,并基于现有 Pods 的 CPU 利用率选择 要运行的 Pods 个数下限和上限。
1kubectl autoscale deployment/nginx-deployment --min=10 --max=15 --cpu-percent=80 --namespace=test
3. 比例缩放实战
默认的配置
1spec:
2 strategy:
3 type: RollingUpdate
4 rollingUpdate:
5 maxUnavailable: 25%
6 maxSurge: 25%
Deployment 会在 .spec.strategy.type==RollingUpdate时,采取 滚动更新的方式更新 Pods。你可以指定 maxUnavailable 和 maxSurge 来控制滚动更新 过程。
- 最大不可用 .spec.strategy.rollingUpdate.maxUnavailable 是一个可选字段,用来指定 更新过程中不可用的 Pod 的个数上限。该值可以是绝对数字(例如,5),也可以是 所需 Pods 的百分比(例如,10%)。百分比值会转换成绝对数并去除小数部分。 如果 .spec.strategy.rollingUpdate.maxSurge 为 0,则此值不能为 0。 默认值为 25%。
- 最大峰值 .spec.strategy.rollingUpdate.maxSurge 是一个可选字段,用来指定可以创建的超出 期望 Pod 个数的 Pod 数量。此值可以是绝对数(例如,5)或所需 Pods 的百分比(例如,10%)。 如果 MaxUnavailable 为 0,则此值不能为 0。百分比值会通过向上取整转换为绝对数。 此字段的默认值为 25%。
更新 Deployment 使用新镜像,碰巧该镜像无法从集群内部解析。
1kubectl set image deployment/nginx-deployment nginx=nginx:sometag --namespace=test
输出:
1deployment.apps/nginx-deployment image updated
镜像更新使用新的 ReplicaSet nginx-deployment-86dc975d96
启动上线过程,但由于默认 maxUnavailable
的要求会被阻塞。检查上线状态:
1kubectl get rs --namespace=test
输出:
1NAME DESIRED CURRENT READY AGE
2nginx-deployment-6b5df77cd8 2 2 2 18h
3nginx-deployment-86dc975d96 1 1 0 112s
dashboard:
查看 deployment 创建情况
1kubectl get deploy --namespace=test
输出:
1NAME READY UP-TO-DATE AVAILABLE AGE
2nginx-deployment 2/2 1 2 8d
变更 Deployment 副本数到 10
1kubectl scale deployment/nginx-deployment --replicas=10 --namespace=test
输出:
1deployment.apps/nginx-deployment scaled
- 再次查看 deployment 创建情况
1kubectl get deploy --namespace=test
输出:
1NAME READY UP-TO-DATE AVAILABLE AGE
2nginx-deployment 8/10 5 8 8d
确认上线状态
1kubectl get rs --namespace=test
输出:
1NAME DESIRED CURRENT READY AGE
2nginx-deployment-6b5df77cd8 8 8 8 18h
3nginx-deployment-86dc975d96 5 5 0 6m56s
说明:
10 个 pod,25% 不可用,所以不能超过 3 个,10 - 2 = 8 个可用,25% 的最大值,就是 12.5,向上取整 13, 8 + 5 = 13。
2.6 回滚 deployment
回滚是 CI/CD 中重要的一个环节,在 kubernetes 面向镜像的无状态服务很好的支持了回滚这个操作。在学习这段内容之前我的做法是直接更新镜像到之前的版本。
默认情况下,Deployment 的所有上线记录都保留在系统中,以便可以随时回滚 (你可以通过修改修订历史记录限制来更改这一约束)。
回滚操作基于比例缩放实战
查看 pod
1kubectl get pod --selector app=nginx --namespace=test
输出:
1NAME READY STATUS RESTARTS AGE
2nginx-deployment-6b5df77cd8-6wx22 1/1 Running 0 24m
3nginx-deployment-6b5df77cd8-85q77 1/1 Running 0 24m
4nginx-deployment-6b5df77cd8-8jstb 1/1 Running 0 24m
5nginx-deployment-6b5df77cd8-lf2cl 1/1 Running 0 19h
6nginx-deployment-6b5df77cd8-lg2kz 1/1 Running 0 24m
7nginx-deployment-6b5df77cd8-n52z6 1/1 Running 0 19h
8nginx-deployment-6b5df77cd8-nxcrf 1/1 Running 0 24m
9nginx-deployment-6b5df77cd8-tt44h 1/1 Running 0 24m
10nginx-deployment-86dc975d96-d9pw7 0/1 ImagePullBackOff 0 24m
11nginx-deployment-86dc975d96-fx9nr 0/1 ImagePullBackOff 0 24m
12nginx-deployment-86dc975d96-lfhl4 0/1 ImagePullBackOff 0 24m
13nginx-deployment-86dc975d96-m252z 0/1 ImagePullBackOff 0 24m
14nginx-deployment-86dc975d96-p7zcg 0/1 ImagePullBackOff 0 31m
获取 Deployment 描述信息
1kubectl describe deployment nginx-deployment --namespace=test
输出:
1Name: nginx-deployment
2Namespace: test
3CreationTimestamp: Thu, 01 Oct 2020 17:12:59 +0800
4Labels: <none>
5Annotations: deployment.kubernetes.io/revision: 8
6 kubectl.kubernetes.io/last-applied-configuration:
7 {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"nginx-deployment","namespace":"test"},"spec":{"replicas":...
8Selector: app=nginx
9Replicas: 10 desired | 5 updated | 13 total | 8 available | 5 unavailable
10StrategyType: RollingUpdate
11MinReadySeconds: 0
12RollingUpdateStrategy: 25% max unavailable, 25% max surge
13Pod Template:
14 Labels: app=nginx
15 Containers:
16 nginx:
17 Image: nginx:sometag
18 Port: 80/TCP
19 Host Port: 0/TCP
20 Limits:
21 memory: 200Mi
22 Requests:
23 memory: 100Mi
24 Environment: <none>
25 Mounts: <none>
26 Volumes: <none>
27Conditions:
28 Type Status Reason
29 ---- ------ ------
30 Available True MinimumReplicasAvailable
31 Progressing False ProgressDeadlineExceeded
32OldReplicaSets: nginx-deployment-6b5df77cd8 (8/8 replicas created)
33NewReplicaSet: nginx-deployment-86dc975d96 (5/5 replicas created)
34Events:
35 Type Reason Age From Message
36 ---- ------ ---- ---- -------
37 Normal ScalingReplicaSet 34m deployment-controller Scaled up replica set nginx-deployment-86dc975d96 to 1
38 Normal ScalingReplicaSet 27m deployment-controller Scaled up replica set nginx-deployment-6b5df77cd8 to 9
39 Normal ScalingReplicaSet 27m deployment-controller Scaled up replica set nginx-deployment-86dc975d96 to 4
40 Normal ScalingReplicaSet 27m deployment-controller Scaled down replica set nginx-deployment-6b5df77cd8 to 8
41 Normal ScalingReplicaSet 27m deployment-controller Scaled up replica set nginx-deployment-86dc975d96 to 5
2.6.1 检查 deployment 上线历史
检查 Deployment 修订历史
1kubectl rollout history deployment/nginx-deployment --namespace=test
输出:
1deployment.apps/nginx-deployment
2REVISION CHANGE-CAUSE
31 <none>
42 <none>
53 <none>
66 <none>
77 <none>
88 <none>
CHANGE-CAUSE 的内容是从 Deployment 的 kubernetes.io/change-cause 注解复制过来的。 复制动作发生在修订版本创建时。你可以通过以下方式设置 CHANGE-CAUSE 消息:
- 使用 kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause=“image updated to 1.9.1” 为 Deployment 添加注解。
- 追加 –record 命令行标志以保存正在更改资源的 kubectl 命令。
- 手动编辑资源的清单。
查看修订历史的详细信息
1kubectl rollout history deployment/nginx-deployment --revision=8 --namespace=test
1deployment.apps/nginx-deployment with revision #8
2Pod Template:
3 Labels: app=nginx
4 pod-template-hash=86dc975d96
5 Containers:
6 nginx:
7 Image: nginx:sometag
8 Port: 80/TCP
9 Host Port: 0/TCP
10 Limits:
11 memory: 200Mi
12 Requests:
13 memory: 100Mi
14 Environment: <none>
15 Mounts: <none>
16 Volumes: <none>
2.6.2 回滚到之前的修订版本
假定现在你已决定撤消当前上线并回滚到以前的修订版本
1kubectl rollout undo deployment.v1.apps/nginx-deployment --namespace=test
2
3# 指定版本
4kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2 --namespace=test
输出:
1deployment.apps/nginx-deployment rolled back
查看 deployment 运行情况
1kubectl get deployments --namespace=test
输出:
1NAME READY UP-TO-DATE AVAILABLE AGE
2nginx-deployment 10/10 10 10 8d
获取 Deployment 描述信息
1kubectl describe deployment nginx-deployment --namespace=test
输出:
1Name: nginx-deployment
2Namespace: test
3CreationTimestamp: Thu, 01 Oct 2020 17:12:59 +0800
4Labels: <none>
5Annotations: deployment.kubernetes.io/revision: 9
6 kubectl.kubernetes.io/last-applied-configuration:
7 {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"nginx-deployment","namespace":"test"},"spec":{"replicas":...
8Selector: app=nginx
9Replicas: 10 desired | 10 updated | 10 total | 10 available | 0 unavailable
10StrategyType: RollingUpdate
11MinReadySeconds: 0
12RollingUpdateStrategy: 25% max unavailable, 25% max surge
13Pod Template:
14 Labels: app=nginx
15 Containers:
16 nginx:
17 Image: nginx:1.19.3
18 Port: 80/TCP
19 Host Port: 0/TCP
20 Limits:
21 memory: 200Mi
22 Requests:
23 memory: 100Mi
24 Environment: <none>
25 Mounts: <none>
26 Volumes: <none>
27Conditions:
28 Type Status Reason
29 ---- ------ ------
30 Available True MinimumReplicasAvailable
31 Progressing True NewReplicaSetAvailable
32OldReplicaSets: <none>
33NewReplicaSet: nginx-deployment-6b5df77cd8 (10/10 replicas created)
34Events:
35 Type Reason Age From Message
36 ---- ------ ---- ---- -------
37 Normal ScalingReplicaSet 43m deployment-controller Scaled up replica set nginx-deployment-86dc975d96 to 1
38 Normal ScalingReplicaSet 37m deployment-controller Scaled up replica set nginx-deployment-6b5df77cd8 to 9
39 Normal ScalingReplicaSet 37m deployment-controller Scaled up replica set nginx-deployment-86dc975d96 to 4
40 Normal ScalingReplicaSet 37m deployment-controller Scaled down replica set nginx-deployment-6b5df77cd8 to 8
41 Normal ScalingReplicaSet 37m deployment-controller Scaled up replica set nginx-deployment-86dc975d96 to 5
42 Normal ScalingReplicaSet 2m11s deployment-controller Scaled down replica set nginx-deployment-86dc975d96 to 0
43 Normal ScalingReplicaSet 2m11s deployment-controller Scaled up replica set nginx-deployment-6b5df77cd8 to 10
三、API操作
client-go 内容也比较多,这里尽量简单介绍。
3.1 创建 deployment
运行 client-go 示例
1func TestCreateDeployment(t *testing.T) {
2 c := getClient()
3 n := "test"
4
5 deployment := &appsv1.Deployment{
6 ObjectMeta: metav1.ObjectMeta{
7 Name: "nginx-deployment",
8 Namespace: n,
9 },
10 Spec: appsv1.DeploymentSpec{
11 Replicas: int32Ptr(4),
12 Selector: &metav1.LabelSelector{
13 MatchLabels: map[string]string{
14 "app": "nginx",
15 },
16 },
17 Template: apiv1.PodTemplateSpec{
18 ObjectMeta: metav1.ObjectMeta{
19 Labels: map[string]string{
20 "app": "nginx",
21 },
22 },
23 Spec: apiv1.PodSpec{
24 Containers: []apiv1.Container{
25 {
26 Name: "nginx",
27 Image: "nginx:1.19.3",
28 Ports: []apiv1.ContainerPort{
29 {
30 ContainerPort: 80,
31 },
32 },
33 },
34 },
35 },
36 },
37 },
38 }
39
40 result, err := c.AppsV1().Deployments(n).Create(context.Background(), deployment, metav1.CreateOptions{})
41 assert.NoError(t, err)
42 t.Logf("create deployment result : %v", result)
43}
查看部署情况
- 查看 deployment
1kubectl get deployments --namespace=test
输出:
1NAME READY UP-TO-DATE AVAILABLE AGE
2nginx-deployment 4/4 4 4 3m4s
- 查看 pod
1kubectl get pods -l app=nginx --namespace=test
输出:
1NAME READY STATUS RESTARTS AGE
2nginx-deployment-669d59f9b4-7lgz2 1/1 Running 0 5m29s
3nginx-deployment-669d59f9b4-jmj25 1/1 Running 0 5m29s
4nginx-deployment-669d59f9b4-kswqx 1/1 Running 0 5m29s
5nginx-deployment-669d59f9b4-sb5xm 1/1 Running 0 5m29s
- 查看 rs
1kubectl get rs --namespace=test
输出:
1NAME DESIRED CURRENT READY AGE
2nginx-deployment-669d59f9b4 4 4 4 5m18s
3.3 查看 deployment
运行 client-go 示例
1func TestGetDeployment(t *testing.T) {
2 c := getClient()
3 n := "test"
4
5 result, err := c.AppsV1().Deployments(n).Get(context.TODO(), "nginx-deployment", metav1.GetOptions{})
6 assert.NoError(t, err)
7 t.Logf("get deployment result : %v", result)
8}
3.2 更新 deployment
运行 client-go 示例
1func TestUpdateDeployment(t *testing.T) {
2 c := getClient()
3 n := "test"
4
5 retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
6 // Retrieve the latest version of Deployment before attempting update
7 // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver
8 result, getErr := c.AppsV1().Deployments(n).Get(context.TODO(), "nginx-deployment", metav1.GetOptions{})
9 if getErr != nil {
10 t.Errorf("Failed to get latest version of Deployment: %v", getErr)
11 }
12
13 result.Spec.Replicas = int32Ptr(2) // reduce replica count
14 result.Spec.Template.Spec.Containers[0].Image = "nginx:1.14.2" // change nginx version
15 _, updateErr := c.AppsV1().Deployments(n).Update(context.TODO(), result, metav1.UpdateOptions{})
16 return updateErr
17 })
18
19 if retryErr != nil {
20 t.Errorf("Update failed: %v", retryErr)
21 }
22}
注意下 RetryOnConflict
说明:
1// RetryOnConflict is used to make an update to a resource when you have to worry about
2// conflicts caused by other code making unrelated updates to the resource at the same
3// time. fn should fetch the resource to be modified, make appropriate changes to it, try
4// to update it, and return (unmodified) the error from the update function. On a
5// successful update, RetryOnConflict will return nil. If the update function returns a
6// "Conflict" error, RetryOnConflict will wait some amount of time as described by
7// backoff, and then try again. On a non-"Conflict" error, or if it retries too many times
8// and gives up, RetryOnConflict will return an error to the caller.
一句话总结就是:当你担心有冲突的时候使用,保障出现冲突错误会自动重试一定的次数直到成功。
查看部署情况
- 查看 deployment
1kubectl get deployments --namespace=test
输出:
1NAME READY UP-TO-DATE AVAILABLE AGE
2nginx-deployment 2/2 2 2 25m
- 查看 pod
1kubectl get pods -l app=nginx --namespace=test
输出:
1NAME READY STATUS RESTARTS AGE
2nginx-deployment-574b87c764-2vlqk 1/1 Running 0 5m4s
3nginx-deployment-574b87c764-5p9br 1/1 Running 0 5m7s
- 查看 rs
1kubectl get rs --namespace=test
输出:
1NAME DESIRED CURRENT READY AGE
2nginx-deployment-574b87c764 2 2 2 5m20s
3nginx-deployment-669d59f9b4 0 0 0 25m
3.4 删除 deployment
运行 client-go 示例
1func TestDeleteDeployment(t *testing.T) {
2 c := getClient()
3 n := "test"
4
5 deletePolicy := metav1.DeletePropagationForeground
6 if err := c.AppsV1().Deployments(n).Delete(context.TODO(), "nginx-deployment", metav1.DeleteOptions{
7 PropagationPolicy: &deletePolicy,
8 }); err != nil {
9 t.Error(err)
10 }
11}
四、补充信息
4.1 Deployment 动态更新
Deployment 控制器每次注意到新的 Deployment 时,都会创建一个 ReplicaSet 以启动所需的 Pods。 如果更新了 Deployment,则控制标签匹配 .spec.selector 但模板不匹配 .spec.template 的 Pods 的现有 ReplicaSet 被缩容。最终,新的 ReplicaSet 缩放为 .spec.replicas 个副本, 所有旧 ReplicaSets 缩放为 0 个副本。
当 Deployment 正在上线时被更新,Deployment 会针对更新创建一个新的 ReplicaSet 并开始对其扩容,之前正在被扩容的 ReplicaSet 会被翻转,添加到旧 ReplicaSets 列表 并开始缩容。
例如,假定你在创建一个 Deployment 以生成 nginx:1.14.2 的 5 个副本,但接下来 更新 Deployment 以创建 5 个 nginx:1.16.1 的副本,而此时只有 3 个nginx:1.14.2 副本已创建。在这种情况下,Deployment 会立即开始杀死 3 个 nginx:1.14.2 Pods, 并开始创建 nginx:1.16.1 Pods。它不会等待 nginx:1.14.2 的 5 个副本都创建完成 后才开始执行变更动作。
4.2 更改标签选择
通常不鼓励更新标签选择算符。建议你提前规划选择算符。 在任何情况下,如果需要更新标签选择算符,请格外小心,并确保自己了解 这背后可能发生的所有事情。
- 添加选择算符时要求使用新标签更新 Deployment 规约中的 Pod 模板标签,否则将返回验证错误。 此更改是非重叠的,也就是说新的选择算符不会选择使用旧选择算符所创建的 ReplicaSet 和 Pod, 这会导致创建新的 ReplicaSet 时所有旧 ReplicaSet 都会被孤立。
- 选择算符的更新如果更改了某个算符的键名,这会导致与添加算符时相同的行为。
- 删除选择算符的操作会删除从 Deployment 选择算符中删除现有算符。 此操作不需要更改 Pod 模板标签。现有 ReplicaSet 不会被孤立,也不会因此创建新的 ReplicaSet, 但请注意已删除的标签仍然存在于现有的 Pod 和 ReplicaSet 中。
4.3 ReplicaSet 介绍
首先可以看到 nginx 的变化如下图:
扩容到四个节点后:
五、参考
https://kubernetes.io/zh/docs/tasks/run-application/run-stateless-application-deployment/
https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/
https://kubernetes.io/zh/docs/tasks/administer-cluster/access-cluster-api/
https://github.com/kubernetes/client-go
https://kubernetes.io/zh/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/