3.3 Deployments(部署)
Deployments控制器(Deployment controller,Deployment应该也是控制器的一种吧)提供了Pod和ReplicaSets的声明式更新。在Deployment对象中,可以描述对应的desired state,Deployments controller将会已可控的频率去改变实际状态变成desired state,可以定义Deployments创建新的ReplicaSets,或者移除已有的Deployments并让新的Deployment接管已有的Pod。类似的,不推荐直接管理ReplicaSets,而应该通过操纵Deployment对象去管理。
【使用场景】
- 创建Deployment,用于推出副本集:副本集子在幕后创建,检查推出的状态是否成功;
- 声明Pod的新状态:更新Deployment的Pod模板规约PodTemplateSpec,一个新的ReplicationSet将会被创建,Deployment管理将Pod以一个可控的速度移到新的副本集中,每个新的副本集都会更新Deployment的修改。
- 回滚Deployment的早期版本:如果当前的Deployment的状态不稳定,每个回滚更新Deployment;
- 扩大Deployment以方便更多的负载;
- 暂停Deployments以对其podTemplatespec应用多个修复程序,然后恢复Deployments以启动新的滚动;
- 使用Deployment的状态作为滚动卡住的标识;
- 清理不再需要的老的ReplicaSets;
【创建Deployment】
Deployment需要一个apiVersion
、kind
、metadata
字段,当然也需要.spec
的东西了,其中.spec.template
和.spec.selector
是必需的,.spec.strategy
表示替换旧Pod的策略,.spec.strategy.type
可以设置为Recreate
(在新Pod创建之前杀死所有已有的Pod)或RollingUpdate
(默认值,可以指定maxUnavailable
和maxSurge
控制升级进程)。
下面是创建一个Nginx的Deployment的实例,3个Pod副本:
apiVersion: apps/v1
kind: Deployment
metadata:
# Deployment的名字
name: nginx-deployment
labels:
app: nginx
spec:
# Pod的副本数,默认为1,可缺省
replicas: 3
# 定义了Deployment发现Pod的标签选择器
selector:
# 这里的选择器必须和下面的template.metadata.labels一样!否则api不接受该请求
matchLabels:
# 选择那些带有 app: nginx 标签的Pod进行管理
app: nginx
# Pod的创建模板
template:
metadata:
# Pod的标签
labels:
app: nginx
spec:
containers:
# 指定运行容器的名字为 nginx
- name: nginx
# 指定镜像版本
image: nginx:1.7.9
ports:
# 指定容器端口
- containerPort: 80
注:matchLabels
也是键值对,如果内部只有一对{key: value},就和matchExpressions
一样。
创建上述的Deployment可以使用kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
,查看集群中的Deployments:
# 获取默认命名空间中的deployments
kubectl get deployments
# 结果
NAME READY UP-TO-DATE AVAILABLE AGE
curl 1/1 1 1 16d
jenkins 1/1 1 1 12d
my-nginx 0/0 0 0 16d
返回的结果有如下字段:
NAME
:即Deployment的名字;READY
:是x/x
的格式,其实就是旧版的CURRENT
和DESIRED
参数,前者表示当前正在运行副本的数量(即.status.replicas
),后者表示期待的副本数量,就是创建Deployment定义的.spec.replicas
那个数字;UP-TO-DATE
:表示已经更新到desired state的Pod的数量,通过.status.updatedReplicas
值获取;AVAILABLE
:表示用户可得APP副本的数目,通过.status.availableReplicas
获取;AGE
:表示应用运行的时间;
上述的值都可以从Deployment的规约中得到,查看Deployment的推出状态信息,可以通过kubectl rollout status deployment.v1.apps/nginx-deployment
,也可以查看由Deployment创建的副本集(ReplicaSet):kubectl get rs
,如下的一些形式:
# 查看副本集
kubectl get rs
# 结果
NAME DESIRED CURRENT READY AGE
curl-66959f6557 1 1 1 16d
jenkins-7958858b5d 1 1 1 12d
my-nginx-64fc468bd4 2 2 2 16d
副本集的名字都是[DEPLOYMENT-NAME]-[RANDOM-STRING]
的形式,其中[RANDOM-STRING]
随机串是由 pod-template-hash 产生的,使用--show-labels
可以获取每个pod的自动生成的标签:
kubectl get pods --show-labels
# 结果
NAME READY STATUS RESTARTS AGE LABELS
curl-66959f6557-pn49b 1/1 Running 2 16d pod-template-hash=66959f6557,run=curl
jenkins-7958858b5d-27qlx 1/1 Running 1 12d name=jenkins,pod-template-hash=7958858b5d
my-nginx-64fc468bd4-cgd7r 1/1 Running 0 20m pod-template-hash=64fc468bd4,run=my-nginx
my-nginx-64fc468bd4-ss95t 1/1 Running 0 21m pod-template-hash=64fc468bd4,run=my-nginx
【更新Deployment】
修改Deployment的Pod模板(即.spec.template
)将会触发一个Deployment的推出,比如标签或容器的镜像更新了,但其他的更新,如Deployment的伸缩将不会触发一个rollout。比如现在想将之前Nginx的Pod使用的镜像改变为nginx:1.9.1,那可以这么干:
# 第一个my-nginx为deployment的名字,第2个my-nginx,第3个my-nginx是容器的名字
kubectl --record deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.9.1
# 输出
deployment.apps/my-nginx image updated
deployment.apps/my-nginx image updated
查看对应的信息,注意看Age:
# 查看副本集的信息
kubectl get rs
# 结果
NAME DESIRED CURRENT READY AGE
curl-66959f6557 1 1 1 16d
jenkins-7958858b5d 1 1 1 12d
my-nginx-5fbd7db759 2 2 2 3m55s
my-nginx-64fc468bd4 0 0 0 16d
# 查看pod
kubectl get pods
# 结果
NAME READY STATUS RESTARTS AGE
curl-66959f6557-pn49b 1/1 Running 2 16d
jenkins-7958858b5d-27qlx 1/1 Running 1 12d
my-nginx-5fbd7db759-fxp6m 1/1 Running 0 5m38s
my-nginx-5fbd7db759-rgr22 1/1 Running 0 6m4s
所以下次需要更新Pod的时候只需要更新Deployment中的Pod模板即可。Deployment在升级Pod时可以确保仅有部分数量的Pod可能会被停止,默认情况确保至少比所需的Pod数量少25%(最多25%不可用)。
Rollover(又叫multiple updates in-flight),每次一个新的Deployment对象都会被Deployment controller监测到,如果没有副本集ReplicationSet接管这些Pod就会创建一个新的副本集。现存的副本集控制的Pod的标签应该和.spec.selector
一致,但那些模板不和.spec.selector
匹配的副本集应该按比例缩减,最终的结果应该是:新副本集ReplicationSet将会伸展成.spec.replicas
数量,旧的副本集ReplicationSet应该缩减为0。如果在更新Deployment过程中还存在rollout,Deployment将会创建新的ReplicationSet,并开始向上扩展该副本集,同时将回滚以前正在扩展的副本集–将其添加到旧副本集列表中,并开始向下扩展(其实就是扩大新副本集的规模、缩减旧副本集的规模)。
选择器更新,一般是不推荐去更新选择器的,如果非要这么干,请谨慎!
【回滚Deployment】
有时如果Deployment不稳定需要回滚到之前的版本,比如下面的更新了一个Nginx的Deployment,先看一下它的信息:
# 查看
kubectl describe deployment/my-nginx
# 结果
Name: my-nginx
Namespace: default
CreationTimestamp: Mon, 08 Apr 2019 17:28:01 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 4
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"my-nginx","namespace":"default"},"spec":{"replicas":2,"se...
kubernetes.io/change-cause: kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.7.9 --record=true
Selector: run=my-nginx
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: run=my-nginx
Containers:
my-nginx:
Image: nginx:1.7.9
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: my-nginx-55bbf58cd5 (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 118s deployment-controller Scaled up replica set my-nginx-765c8d656d to 1
Normal ScalingReplicaSet 107s deployment-controller Scaled down replica set my-nginx-765c8d656d to 0
Normal ScalingReplicaSet 107s deployment-controller Scaled up replica set my-nginx-55bbf58cd5 to 1
Normal ScalingReplicaSet 87s deployment-controller Scaled down replica set my-nginx-5fbd7db759 to 1
Normal ScalingReplicaSet 87s deployment-controller Scaled up replica set my-nginx-55bbf58cd5 to 2
Normal ScalingReplicaSet 64s deployment-controller Scaled down replica set my-nginx-5fbd7db759 to 0
[root@k8s-node1 networking]# kubectl rollout history deployment.v1.apps/my-nginx
deployment.apps/my-nginx
REVISION CHANGE-CAUSE
1 kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx nginx=nginx:1.9.1 --record=true
2 kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.9.1 --record=true
3 kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx: --record=true
4 kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.7.9 --record=true
可以看到当前的奖镜像版本是之前更新的nginx:1.7.9,再看一下Deployment的Rollout历史:
# 查看my-nginx的历史版本
kubectl rollout history deployment.v1.apps/my-nginx
# 输出,最近的升级在最下面
deployment.apps/my-nginx
REVISION CHANGE-CAUSE
1 kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx nginx=nginx:1.9.1 --record=true
2 kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.9.1 --record=true
3 kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx: --record=true
4 kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.7.9 --record=true
目前的镜像版本是nginx:1.7.9
,我本地更新过4次,现在进行回滚到最近一次:kubectl rollout undo deployment.v1.apps/my-nginx
,或者直接使用--to-revision
指定回滚到某个版本,比如:kubectl rollout undo deployment.v1.apps/my-nginx --to-revision=1
,然后describe一下可以看到改变。
【伸缩Deployment】
可以已经部署的Deployment进行伸缩:kubectl scale deployment.v1.apps/my-nginx --replicas=1
,如果集群开启了“自动水平Pod伸缩”的功能,那就可以基于已存在的Pod所在的CPU效率选择Pod的最大值和最小值,比如:kubectl autoscale deployment.v1.apps/my-nginx --min=10 --max=15 --cpu-percent=80
按比例伸缩,滚动升级支持APP的多个版本同时运行,当在rollout期间在对Deployment进行滚动升级,那Deployment Controller为了降低风险将会在现有的副本集中平衡额外的副本,这种行为就是按比例伸缩(proportional scaling)。
【Deployment的暂停和继续】
在触发1个或多个更新前可以暂停Deployment,然后再继续,这将允许在暂停和恢复之间应用多个修复程序,而不会触发不必要的rollout,比如之前的Deployment,暂停:kubectl rollout pause deployment.v1.apps/my-nginx
,然后更新Deployment:kubectl set image deployment.v1.apps/my-nginx my-nginx=nginx:1.9.1
,这样不会有新的rollout开始,可以查看:kubectl rollout history deployment.v1.apps/my-nginx
,在暂停的这个时间段可以做很多资源的更新,并且资源的更新是可以被使用的,比如:kubectl set resources deployment.v1.apps/my-nginx -c=my-nginx --limits=cpu=200m,memory=512Mi
(-c
表示容器的名字)。Deployment初始状态要比暂停的优先级高,所以他会继续运行,但只要Deployment是暂停的Deployment新的更新将不会影响Deployment,最后恢复Deployment:kubectl rollout resume deployment.v1.apps/my-nginx
,可以看到新的副本集出现:kubectl get rs -w
和kubectl get rs
。
【Deployment status】
Deployment有各种状态,可以通过kubectl rollout status deployments.v1.apps/my-nginx
查看,主要有如下的几种:
- Progressing Deployment:即正在运行状态,Deployment此时应该出现某些行为:创建新的副本集ReplicaSet、扩大最新的副本集、缩减旧的副本集、新Pod变为ready或avaliable状态;
- Complete Deployment:即完成状态,Deployment应该是:所有和Deployment相关的副本集都已经更新至最新、且这些副本都处于available状态、没有Deployment的旧副本在运行;
- Failed Deployment:即失败状态,Deployment发生这种情况的因素可能是:配额不足、准备就绪探测器(即就绪探针)故障、镜像拉取错误、权限不足、配置错误;
【清理策略】
可以指定通过设置.spec.revisionHistoryLimit
字段指定Deployment要维护多少旧的副本集ReplicaSet,重置后台将会进行垃圾清理,默认为10,这个其实就是在Deployment的更新历史记录的数量,如果将它设置为0,那就不能进行回滚了。