容器编排具有k8s中非常重要的功能:水平扩展/收缩。
作业副本与水平伸缩
例如更新了Deployment的Pod模板,那么Deployment就会遵循滚动更新的方式来升级现有的容器,这个功能的实现依赖于k8s中一个非常重要的概念:ReplicaSet。
一个ReplicaSet其实就是由副本数目的定义加上一个Pod模板组成的,例如
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: nginx-set
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9并且Deployment控制器实际操纵的,正是ReplicaSet对象,而不是Pod对象。所以正如在控制器模型末尾提到的ownerReference,一个Pod的ownerReference正是ReplicaSet对象。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80上面的例子中,声明的ReplicaSet的副本数为3,ReplicaSet通过控制器模式来保证系统中的Pod数目永远等于指定的个数,需要注意的是 Deployment 只允许容器的 restartPolicy=Always 的主要原因:只有在容器能保证自己始终是 Running 状态的前提下,ReplicaSet 调整 Pod 的个数才有意义,挂掉的Pod是没有作用的,要保证Pod出于Running就要能够重启。
Deployment同样通过控制器模式来修改它所控制的ReplicaSet的个数和属性。然后ReplicaSet就会自动进行扩容或者收缩。
水平伸缩的命令为:
kubeclt scale deployment nginx-deployment --replicas=4就算只有一个分片也比较推荐引入deployment进行管理,可以利用伸缩的命令进行启停:
# 启动
kubeclt scale deployment nginx-deployment --replicas=1
# 停止
kubeclt scale deployment nginx-deployment --replicas=0滚动更新
创建这个nginx-deployment:
$ kubectl create -f nginx-deployment.yaml通过如下命令可以看到deployment创建后的信息:
kubectl get deployments还有一条命令可以实时查看deployment对象的状态变化:
$ kubectl rollout status deployment/nginx-deployment
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment.apps/nginx-deployment successfully rolled out查看ReplicaSet的命令为:
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-3167673210 3 3 3 20s一个ReplicaSet的名字由deployment的名称与一串随机字符串组成,ReplicaSet 会把这个随机字符串加在它所控制的所有 Pod 的标签里,从而保证这些 Pod 不会与集群里的其他 Pod 混淆。
现在deployment已经启动,相关信息也查看了,那么接下来就是进行水平扩展或者收缩了。要完成这一点,其实非常简单,就是修改deployment的API对象,滚动更新就会自动触发。
对于deployment的修改也有很多方式,比如,使用kubectl edit指令直接编辑etcd中的API对象:
$ kubectl edit deployment/nginx-deployment
...
spec:
containers:
- name: nginx
image: nginx:1.9.1 # 1.7.9 -> 1.9.1
ports:
- containerPort: 80
...
deployment.extensions/nginx-deployment edited编辑完成退出后就会触发滚动更新流程。
为了了解滚动更新的流程,使用 kubectl rollout status 指令查看 nginx-deployment 的状态变化
$ kubectl rollout status deployment/nginx-deployment
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment.extensions/nginx-deployment successfully rolled out也可以查看deployment的events来查看滚动更新的流程:
- 使用修改后的Pod模板,创建一个新的ReplicaSet。
- 然后将新的ReplicaSet的Pod副本数从0变为1,将旧的ReplicaSet的副本数减少1。
- 这样交替进行,直到旧的Pod全部替换成新的Pod。
将一个集群中正在运行的多个 Pod 版本,交替地逐一升级的过程,就是“滚动更新”。这样可以保证在新的Pod启动不起来的时候会停止滚动更新,并且仍然存在旧的副本能够提供服务。这同样要求使用Pod的健康检查来保证应用的状态,而不是容器的状态。
deployment还可以确保在任何时间窗口内只有指定比例的Pod处于离线状态,并且只有指定比例的新Pod被创建出来,这两个比例值都是可以设置的,默认为DESIRE值的25%。这个策略,是 Deployment 对象的一个字段,名叫RollingUpdateStrategy ,如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
...
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1因为deployment有3个Pod副本,所以这个配置可以保证滚动更新的过程中,永远保证最少有2个可用Pod副本,最多有4个可用的Pod副本。maxSurge 指定的是除了 DESIRED 数量之外,在一次“滚动”中,Deployment 控制器还可以创建多少个新 Pod;而 maxUnavailable 指的是,在一次“滚动”中,Deployment 控制器可以删除多少个旧 Pod。这两个配置还可以用前面我们介绍的百分比形式来表示
如果滚动更新失败,那么会自动停止。可以执行下面的命令回滚到旧版本,其实就是让这个旧 ReplicaSet再次“扩展”成 3 个 Pod,而让新的 ReplicaSet重新“收缩”到 0 个 Pod:
$ kubectl rollout undo deployment/nginx-deployment
deployment.extensions/nginx-deploymentdeployment的每次变更都会记录一次版本,使用kubectl rollout histroy可以查看版本变更的历史,从1开始:
$ kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 kubectl create -f nginx-deployment.yaml --record
2 kubectl edit deployment/nginx-deployment
3 kubectl set image deployment/nginx-deployment nginx=nginx:1.91通过指定版本可以查看或回滚到任何一个历史版本:
# 查看指定版本的API对象细节
$ kubectl rollout history deployment/nginx-deployment --revision=2
# 回滚到指定版本
$ kubectl rollout undo deployment/nginx-deployment --to-revision=2
deployment.extensions/nginx-deployment在前面每次修改都会生成一个新的ReplicaSet对象,有些浪费资源,k8s提供了一个指令,可以使得对deployment的多次修改最后只生成一个ReplicaSet对象。就是kubectl rollout pause指令。用法如下:
$ kubectl rollout pause deployment/nginx-deployment
deployment.extensions/nginx-deployment paused这条指令将deployment变为暂停状态,对其的任何修改都不会触发滚动更新,修改完成之后再恢复一下,那么所有的更改只会触发一次滚动更新:
$ kubectl rollout resume deployment/nginx-deployment
deployment.extensions/nginx-deployment resumed就算多个修改只产生一个ReplicaSet对象,随着应用的更新这个对象也是会越来越多的。Deployment 对象有一个字段,叫作 spec.revisionHistoryLimit,就是 Kubernetes 为 Deployment 保留的“历史版本”个数。如果不需要保存历史版本,就将这个字段设置为0。
Deployment 实际上是一个两层控制器。首先,它通过 ReplicaSet 的个数来描述应用的版本;然后,它再通过 ReplicaSet 的属性(比如 replicas 的值),来保证 Pod 的副本数量。