k8s工作负载资源之deployment
首先我们要理解:一个应用跑在k8s集群上了,那么这个应用就是一个工作负载(workloads)。
在k8s中会用pod的来承载这个应用,那么负责管理这个pod的东西就叫工作负载资源(workload resources)。
我们可以简单理解为是这样的:
工作负载资源又支持jj自定义或使用第三方资源,这里我们先认识内置的,k8s内置工作负载资源包含如下:
- deployment
- replicaset
- statefulset
- daemonset
- jobs
- cronjob
- TTL Controller for Finished Resources
- ReplicationController (逐步被ReplicaSet替代)
那让我们从最常用的deployment开始吧。
一个 Deployment 为 Pods和 ReplicaSets提供声明式的更新能力,我们从下面几个方面开始上手:
- 创建 Deployment 将 ReplicaSet 上线。 ReplicaSet 在后台创建 Pods。 检查 ReplicaSet 的上线状态,查看其是否成功。
- **通过更新 Deployment 的 Pod模板(TemplateSpec),声明 Pod 的新状态 。 **新的 ReplicaSet 会被创建,Deployment 以受控速率将 Pod 从旧 ReplicaSet 迁移到新 ReplicaSet。 每个新的 ReplicaSet 都会更新到 Deployment 的修订版本。
- 如果 Deployment 与你的预期不符,可以回滚到较早的 Deployment 版本。 每次回滚都会更新到 Deployment 修订的新版本。
- 通过Deployment 扩大应用规模承担更多负载。
- 暂停 Deployment ,对 PodTemplateSpec 做修改然后恢复执行,让pod更新到新版本。
deployment创建
说了这么多还不如手动写一个deployment的yml声明实在(如果你喜欢json也可以是json格式,本质上还是将yml转换为json格式请求的api)。
下面deployment创建了一个replicaset,这个replicaset将会启动三个nginx的pod:
nginx-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-web
image: nginx:latest
ports:
- containerPort: 80
通过kubectl apply 将声明文件转换为api提交给apiserver
$ kubectl apply -f nginx-deployment.yml
deployment.apps/nginx-deployment created
查看deployment资源创建的对象nginx-deployment(这里的对象与编程语言中对象同义)
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 67m
查看nginx-deplyment创建的replicat对象nginx-deployment-767cf44bff
$kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-767cf44bff 3 3 3 68m
最后是nginx-deployment-767cf44bff创建的三个pod对象
$ kubectl get pod
NAMESPACE NAME READY STATUS RESTARTS AGE
default nginx-deployment-767cf44bff-9fj8q 1/1 Running 0 13m
default nginx-deployment-767cf44bff-f746l 1/1 Running 0 13m
default nginx-deployment-767cf44bff-ktbzl 1/1 Running 0 13m
也可以通过rollout status 查看 Deployment 上线状态。
$kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out
这就是deployment资源创建对象的关系图:
现在我们主要来看一下创建的这个nginx-deployment声明。
我们把yml文件分为两个大部分(红色):
-
属性。
apiVersion
- 创建该对象所使用的 Kubernetes API 的版本kind
- 想要创建的对象的类别metadata
- 帮助唯一性标识对象的一些数据,包括一个name
字符串、UID 和可选的namespace
-
规格 spec(specification)
replicas
- 期望的pod副本数量selector
- pod标签选择器template
- pod模板
我们在selector中匹配包含
app=nginx
标签的pod,pod模板中又为新创建的pod打上app=nginx
的标签,这样就形成了控制闭环。
我们通过可以show-labels查看pod的标签
$ kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-767cf44bff-9fj8q 1/1 Running 0 81m app=nginx,pod-template-hash=767cf44bff
nginx-deployment-767cf44bff-f746l 1/1 Running 0 81m app=nginx,pod-template-hash=767cf44bff
nginx-deployment-767cf44bff-ktbzl 1/1 Running 0 81m app=nginx,pod-template-hash=767cf44bff
为什么pod中又有一个pod-template-hash
标签?
eployment 控制器将 pod-template-hash
标签添加到 Deployment 所创建的每一个 ReplicaSet 中。我们来看一下rs的selector描述:
$ kubectl describe rs
Name: nginx-deployment-767cf44bff
Namespace: default
Selector: app=nginx,pod-template-hash=767cf44bff
pod-template-hash 标签是通过对 ReplicaSet 的 PodTemplate
进行哈希处理,此标签可确保 Deployment 的子 ReplicaSets 不冲突,所生成的哈希值被添加到 ReplicaSet的selector、Pod 模板labels、以及 ReplicaSet 旗下的任何 Pod 中。这样deployment下的replicaset只能控制自己的pod。恩,妙哉。
不同工作负载资源所创建的对象,spec是不同的。比如在Deployment中spec可以包含如下字段,这个可以在Kubernetes API中找到。
大多数字段都包含了一个默认值,除非有特殊需求,大多数时候很难被用到。如果需要的时候你再谷歌一下也不迟。到这里deployment工作负载的第一个用例已经成了。
deployment更新
仅当 Deployment Pod 模板(即 .spec.template
字段)发生改变时,例如模板的标签或容器镜像被更新, 才会触发 Deployment 上线。
其他更新(如对 Deployment 执行扩缩容的操作)不会触发上线动作。
- 我们可以通过
kubectl set
命令更新现有工作负责资源
$ kubectl set image deployment/nginx-deployment nginx-web=nginx:1.17 --record
deployment.apps/nginx-deployment image updated
--record
用于记录kubectl对资源的操作。便于后期需要时回滚。下面会说到。
kubectl set -h 查询set支持更新的内容。
Available Commands:
- env Update environment variables on a pod template
- image Update image of a pod template
resources Update resource requests/limits on objects with pod templates - selector Set the selector on a resource
- serviceaccount Update ServiceAccount of a resource
- subject Update User, Group or ServiceAccount in a RoleBinding/ClusterRoleBinding
- 使用
kubectl edit
编辑deployment后自动更新
$ kubectl edit deployment/nginx-deployment --record
deployment.apps/nginx-deployment edited
- 直接更新deployment yml文件
个人觉得最好的方式是更新yml声明文件,通过kubectl apply 应用即可,这样你只要管理好你的的nginx-deployment.yml做到心中有数
当我们更新后查看rs状态,此时deployment 创建了一个新的nginx-deployment replicaset并投入使用。
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-64f9765d86 4 4 4 4h11m
nginx-deployment-6cf9cc9c9d 0 0 0 5h6m
这里顺便看一下deployment中pod滚动更新策略
我们可以通过kubectl describe deployment 查看RollingUpdateStrategy字段,即在滚动更新时最大不可用pod数为1/4,最大可用pod数为期望副本数1.25倍(多25%)。
RollingUpdateStrategy: 25% max unavailable, 25% max surge
假如我们将 deployment_A 中4个副本(pod)更新到deployment_B(也是4副本),其中的某个数据pod状态如下
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-64f9765d86-c9rlj 0/1 ContainerCreating 0 2s
nginx-deployment-64f9765d86-wngmx 0/1 ContainerCreating 0 2s
nginx-deployment-7fcdcb4b75-lmsmm 1/1 Running 0 4h6m
nginx-deployment-7fcdcb4b75-m99tx 1/1 Terminating 0 4h5m
nginx-deployment-7fcdcb4b75-tghb2 1/1 Running 0 4h5m
nginx-deployment-7fcdcb4b75-xfs2m 1/1 Running 0 4h6m
即只有1个在停止,正在创建2个新pod(即将有5个可用),详细滚动过程可通过kubectl descibe deployment
中events查看。
尽量不要更新模板中labels,会造成pod孤立。在某些API版本已经被禁止了。
deployment回滚
deployment回滚和更新一样,Pod 模板部分会被回滚。
我们通过 rollout history 来查看某个deployment的历史版本。即之前通过--record
所记录的。
$ kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 kubectl apply --filename=nginx-deployment.yml --record=true
4 kubectl apply --filename=nginx-deployment.yml --record=true
5 kubectl set image deployment/nginx-deployment nginx-web=nginx:1.17 --record=true
9 kubectl edit deployment/nginx-deployment --record=true
10 kubectl edit deployment/nginx-deployment --record=true
回滚到第5个版本。
$ kubectl rollout undo deployment/nginx-deployment --to-revision=5
deployment.apps/nginx-deployment rolled back
或者直接回滚到上一个版本。
$ kubectl rollout undo deployment/nginx-deployment
还是如前面所说,回滚只一种更工程化的说法,其实回滚也是一种更新,yml声明依然是核心。所以我们更应该关注的对deployment的yml文件的版本控制。
deployment缩放
缩放控制的是.spec.replicas
,也可通过scale命令操作。
$ kubectl scale deployment/nginx-deployment --replicas=6
deployment.apps/nginx-deployment scaled
水平自动缩放本为暂不涉及,后面文章会详细讨论。可以参考:Horizontal Pod Autoscaler
deployment暂停与恢复
我们可以在触发更新之前暂停 Deployment,然后做多个修改之后再恢复,进行一次性上线。
还是我们之前的deployment
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 4/4 4 4 30m
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-64f9765d86 4 4 4 30m
暂停deployment
$ kubectl rollout pause deployment/nginx-deployment
error: deployments.apps "nginx-deployment" is already paused
对nginx-deployment做一些更新
- 直接修改yml文件,更新镜像为nginx:1.17,并通过kubectl apply应用更改。
- 通过set做资源限制。
$ kubectl set resources deployment/nginx-deployment -c=nginx-web --limits=cpu=50m,memory=100Mi
deployment.apps/nginx-deployment resource requirements updated
此时我们查看rs副本状态,查看deployment版本信息
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-64f9765d86 4 4 4 40m
$ kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
可以看到还是之前的rs,deployment并没有将我们的修改应用到对象中。
现在我们将deployment通过Resume恢复
$ kubectl rollout resume deployment/nginx-deployment
deployment.apps/nginx-deployment resumed
查看rs状态
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-64f9765d86 3 3 3 41m
nginx-deployment-7f4447656b 2 2 0 4s
这会deployment已恢复,并应用了对资源对象的更新。
参考:
k8s官方文档Deployment