Deployment为Pod和Replica Set(升级版的 Replication Controller)提供声明式更新。
注意:您不该手动管理由 Deployment 创建的 Replica Set,否则您就篡越了 Deployment controller 的职责!
Deployment的典型的用例如下:
1、创建一个Deployment对象来生成对应的ReplicaSet,并完成Pod副本的创建过程。
2、检查Deployment的状态来查看部署动作是否完成,Pod副本的数量是否达到预期的值。
3、更新Deployment以创建新的Pod,通过修改Pod-Template-Spec字段来声明Pod的新状态。这会创建一个新的ReplicaSet,Deployment会按照控制的速率将pod从旧的ReplicaSet移动到新的ReplicaSet中。
4、如果当前状态不稳定,则回滚到一个早先的Deployment版本。
5、暂停Deployment,以便于一次性修改多个PodTemplateSpec的配置项,然后再恢复Deployment,进行新的发布。
6、扩容Deployment以满足更高的负载。
7、查看Deployment 的状态,以此作为发布是否成功的指标。
8、清除旧的不必要的 ReplicaSets。
(1)创建 Deployment
下面是一个 Deployment 示例,它创建了一个 ReplicaSet 来启动3个 nginx pod。
下载示例文件nginx-deployment.yaml并执行命令:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
执行创建命令:
[root@gqtest ~]# kubectl create -f nginx-deployment.yaml --record
deployment "nginx-deployment" created
注:--record选项可以记录当前命令执行记录,便于以后查看一个deployment revision中执行了哪些命令。
(2)更新Deployment
Deployment的更新(rollout)当且仅当Deployment的pod template中的label发生更新或者镜像发生更改时,才会被触发。像Deployment扩容,不会触发rollout事件。
假如我们现在想要让 nginx pod 使用nginx:1.9.1的镜像来代替原来的nginx:1.7.9的镜像。
[root@gqtest ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment "nginx-deployment" image updated
或者可以使用edit命令来编辑 Deployment,修改 .spec.template.spec.containers[0].image ,将nginx:1.7.9 改写成 nginx:1.9.1。
[root@gqtest ~]# kubectl edit deployment/nginx-deployment
(3)回退Deployment
可以通过设置.spec.revisonHistoryLimit项来指定 deployment 最多保留多少 revision 历史记录。默认的会保留所有的 revision;如果将该项设置为0,Deployment就不允许回退了。
只要 Deployment 的 rollout 被触发就会创建一个 revision。也就是说当且仅当 Deployment 的 Pod template(如.spec.template)被更改,例如更新template 中的 label 和容器镜像时,就会创建出一个新的 revision。
我们先故意执行一个有错误的Deployment任务:
[root@gqtest ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.99
deployment "nginx-deployment" image updated
我们故障写了一个不存在的镜像文件版本,Deployment rollout任务会补卡住,如下所示:
可以看到pod的状态处于"ImagePullBackOff"的错误状态:
[root@gqtest ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mysql-mn49n 1/1 Running 1 3d
myweb-k6fp0 1/1 Running 1 3d
myweb-m9nv9 1/1 Running 1 3d
nginx-deployment-538426637-g55n4 0/1 ImagePullBackOff 0 3m
注:Deployment controller会自动停止坏的 rollout,并停止扩容新的 ReplicaSet。
我们需要回退到稳定版本的Deployment revision。
先查看一下Deployment的revision记录:
[root@gqtest ~]# kubectl rollout history deployment/nginx-deployment
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 kubectl create -f nginx-deployment.yaml --record
2 kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
3 kubectl set image deployment/nginx-deployment nginx=nginx:1.99
注:因为我们创建 Deployment 的时候使用了--recored参数可以记录命令,我们可以很方便的查看每次 revision 的变化。
查看单个revision 的详细信息:
[root@gqtest ~]# kubectl rollout history deployment/nginx-deployment --revision=2
回退到历史版本
回退到上一个版本:
[root@gqtest ~]# kubectl rollout undo deployment/nginx-deployment
deployment "nginx-deployment" rolled back
回退到一个指定的版本:
# kubectl rollout undo deployment/nginx-deployment --to-revision=2
deployment "nginx-deployment" rolled back
可以通过设置.spec.revisonHistoryLimit项来指定 deployment 最多保留多少 revision 历史记录。默认的会保留所有的 revision;如果将该项设置为0,Deployment就不允许回退了。
(4)Deployment 扩容
使用以下命令将nginx-deployment扩容为3副本:
[root@gqtest ~]# kubectl scale deployment nginx-deployment --replicas 3
deployment "nginx-deployment" scaled
查看该Deployment的事件记录:
[root@gqtest ~]# kubectl describe deployment nginx-deployment
注:假如集群中启用了horizontal pod autoscaling,您可以给 Deployment 设置一个 autoscaler,基于当前 Pod的 CPU 利用率选择最少和最多的 Pod 数。
关于Deployment的比例扩容:
RollingUpdate Deployment 支持同时运行一个应用的多个版本。或者 autoscaler 扩 容 RollingUpdate Deployment 的时候,正在中途的 rollout(进行中或者已经暂停的),为了降低风险,Deployment controller 将会平衡已存在的活动中的 ReplicaSet(有 Pod 的 ReplicaSet)和新加入的 replica。这被称为比例扩容。
(5)暂停和恢复Deployment
可以在发出一次或多次更新前暂停一个 Deployment,然后再恢复它。这样您就能多次暂停和恢复 Deployment,在此期间进行一些修复工作,而不会发出不必要的 rollout。
[root@gqtest ~]# kubectl rollout pause deployment/nginx-deployment
deployment "nginx-deployment" paused
[root@gqtest ~]# kubectl set image deploy/nginx-deployment nginx=nginx:1.9.2
deployment "nginx-deployment" image updated
即使执行了上面的镜像更改命令,也没有触发任何Deployment rollout的事件。而且可以继续做更多的修改,例如:
[root@gqtest ~]# kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=256Mi
deployment "nginx-deployment" resource requirements updated
注:-c选项的作用是指定容器唯一标识名
当各种变更都准备妥当后,我们恢复该deployment:
[root@gqtest ~]# kubectl rollout resume deploy nginx-deployment
deployment "nginx-deployment" resumed
查看一下deployment处理结果,使用-w选项(watch)跟踪输出如下所示:
[root@gqtest ~]# kubectl get rs -w
(6)Deployment 状态
Deployment 在生命周期中有多种状态。在创建一个新的 ReplicaSet 的时候它可以是 progressing 状态, complete 状态,或者 fail to progress 状态。
进行中的 Deployment
Kubernetes 将执行过下列任务之一的 Deployment 标记为 progressing 状态:
Deployment 正在创建新的ReplicaSet过程中。
Deployment 正在扩容一个已有的 ReplicaSet。
Deployment 正在缩容一个已有的 ReplicaSet。
有新的可用的 pod 出现。
可以使用kubectl rollout status命令监控 Deployment 的进度。
完成的 Deployment
Kubernetes 将包括以下特性的 Deployment 标记为 complete 状态:
Deployment 最小可用。最小可用意味着 Deployment 的可用 replica 个数等于或者超过 Deployment 策略中的期望个数。
所有与该 Deployment 相关的replica都被更新到了指定版本,也就说更新完成。
该 Deployment 中没有旧的 Pod 存在。
可以用kubectl rollout status命令查看 Deployment 是否完成。如果 rollout 成功完成,kubectl rollout status将返回一个0值的 Exit Code。
[root@gqtest ~]# kubectl rollout status deploy/nginx-deployment
deployment "nginx-deployment" successfully rolled out
[root@gqtest ~]# echo $?
0
版本记录的清理策略
可以设置 Deployment 中的 .spec.revisionHistoryLimit 项来指定保留多少旧的 ReplicaSet。 余下的将在后台被当作垃圾收集。默认的,所有的 revision 历史就都会被保留。在未来的版本中,将会更改为2。
注意: 将该值设置为0,将导致所有的 Deployment 历史记录都会被清除,该 Deployment 就无法再回退了。
(7)编写 Deployment Spec
在所有的 Kubernetes 配置中,Deployment 也需要apiVersion,kind和metadata这些配置项。
Deployment也需要 .spec section.
Pod Template
.spec.template 是 .spec中唯一要求的字段。
.spec.template 是 pod template. 它跟 Pod有一模一样的schema,除了它是嵌套的并且不需要apiVersion 和 kind字段。
为了划分Pod的范围,Deployment中的pod template必须指定适当的label(不要跟其他controller重复了)和适当的重启策略。
.spec.template.spec.restartPolicy 可以设置为 Always , 如果不指定的话这就是默认配置。
Replicas
.spec.replicas 是可以选字段,指定期望的pod数量,默认是1。
Selector
.spec.selector是可选字段,用来指定 label selector ,圈定Deployment管理的pod范围。
如果被指定, .spec.selector 必须匹配 .spec.template.metadata.labels,否则它将被API拒绝。如果 .spec.selector 没有被指定, .spec.selector.matchLabels 默认是 .spec.template.metadata.labels。
在Pod的template跟.spec.template不同或者数量超过了.spec.replicas规定的数量的情况下,Deployment会杀掉label跟selector不同的Pod。
注意: 不应该再创建其他label跟这个selector匹配的pod,或者通过其他Deployment,或者通过其他Controller,例如ReplicaSet和ReplicationController。否则该Deployment会被把它们当成都是自己创建的。Kubernetes不会阻止这么做。如果有多个controller使用了重复的selector,controller们就会互相打架并导致不正确的行为。
策略
.spec.strategy 指定新的Pod替换旧的Pod的策略。 .spec.strategy.type 可以是"Recreate"或者是 "RollingUpdate"(按比例更新)。"RollingUpdate"是默认值。
Recreate Deployment,.spec.strategy.type==Recreate时,在创建出新的Pod之前会先杀掉所有已存在的Pod。
Rolling Update Deployment,.spec.strategy.type==RollingUpdate时,Deployment使用rolling update 的方式更新Pod 。可以指定maxUnavailable 和 maxSurge 来控制 rolling update 进程。
Max Unavailable,.spec.strategy.rollingUpdate.maxUnavailable 是可选配置项,用来指定在升级过程中不可用Pod的最大数量。该值可以是一个绝对值(例如5),也可以是期望Pod数量的百分比(例如10%)。通过计算百分比的绝对值向下取整。例如,该值设置成30%,启动rolling update后旧的ReplicatSet将会立即缩容到期望的Pod数量的70%。新的Pod ready后,随着新的ReplicaSet的扩容,旧的ReplicaSet会进一步缩容,确保在升级的所有时刻可以用的Pod数量至少是期望Pod数量的70%。
Max Surge,.spec.strategy.rollingUpdate.maxSurge 是可选配置项,用来指定可以超过期望的Pod数量的最大个数。该值可以是一个绝对值(例如5)或者是期望的Pod数量的百分比(例如10%)。当MaxUnavailable为0时该值不可以为0。通过百分比计算的绝对值向上取整。默认值是1。例如,该值设置成30%,启动rolling update后新的ReplicatSet将会立即扩容,新老Pod的总数不能超过期望的Pod数量的130%。旧的Pod被杀掉后,新的ReplicaSet将继续扩容,旧的ReplicaSet会进一步缩容,确保在升级的所有时刻所有的Pod数量和不会超过期望Pod数量的130%。
Progress Deadline Seconds
.spec.progressDeadlineSeconds 是可选配置项,用来指定在系统报告Deployment的failed progressing——表现为resource的状态中type=Progressing、Status=False、 Reason=ProgressDeadlineExceeded前可以等待的Deployment进行的秒数。Deployment controller会继续重试该Deployment。未来,在实现了自动回滚后, deployment controller在观察到这种状态时就会自动回滚。
如果设置该参数,该值必须大于 .spec.minReadySeconds。
Min Ready Seconds
.spec.minReadySeconds是一个可选配置项,用来指定没有任何容器crash的Pod并被认为是可用状态的最小秒数。默认是0(Pod在ready后就会被认为是可用状态)。
Rollback To
.spec.rollbackTo 是一个可以选配置项,用来配置Deployment回退的配置。设置该参数将触发回退操作,每次回退完成后,该值就会被清除。
Revision
.spec.rollbackTo.revision是一个可选配置项,用来指定回退到的revision。默认是0,意味着回退到历史中最老的revision。
Revision History Limit
Deployment revision history存储在它控制的ReplicaSets中。
.spec.revisionHistoryLimit 是一个可选配置项,用来指定可以保留的旧的ReplicaSet数量。该理想值取决于心Deployment的频率和稳定性。如果该值没有设置的话,默认所有旧的Replicaset或会被保留,将资源存储在etcd中,是用kubectl get rs查看输出。每个Deployment的该配置都保存在ReplicaSet中,然而,一旦删除了旧的RepelicaSet,该Deployment就无法再回退到那个revison了。
如果将该值设置为0,所有具有0个replica的ReplicaSet都会被删除。在这种情况下,新的Deployment rollout无法撤销,因为revision history都被清理掉了。
Paused
.spec.paused是可以可选配置项,boolean值。用来指定暂停和恢复Deployment。Paused和没有paused的Deployment之间的唯一区别就是,所有对paused deployment中的PodTemplateSpec的修改都不会触发新的rollout。
Deployment被创建之后默认是非paused。
(8)、Horizontal Pod Autoscaler
横向自动扩容功能,简称HPA,也是k8s系统中的一种资源对象。在v1.1版本中首次发布,在v1.2版本中升级为稳定版。在v1.6版本之前,仅支持使用CPU负载作为是否扩容的判定条件;自v1.6版本开始提供了根据应用自定义指标进行自动扩容和缩容的功能,不过目前仍为实验性质。
可以通过yaml文件定义一个HPA对象,或者直接使用命令创建一个HPA对象。
yaml文件定义的样例:
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
maxReplicas: 10
minReplicas: 1
scaleTargetRef:
kink: Deployment
name: php-apache
targetCPUUtilizationPercentage: 90
注:当名为php-apache的deployment的Pods副本的CPU使用率超过90%时,会触发自动扩容行为。但扩容或缩容都必须满足的约束条件是Pod的副本数量要在1~10之间。
以上为命令行方式创建一个HPA:
[root@gqtest ~]# kubectl autoscale deployment nginx-deployment --min=1 --max=5 --cpu-percent=80
deployment "nginx-deployment" autoscaled
(9)、StatefulSet
StatefulSet(有状态系统服务设计)在k8s v1.5中引入,在Kubernetes 1.7中还是beta特性。
现实中很多服务是有状态的,如MySQL集群、kafka集群、ZooKeeper集群等,这些应用集群有以下特点:
每个节点都有固定的身份ID,通过这个ID,集群中的成员可以相互发现和通信;
集群的规模是相对固定的,且不能随意变动;
集群里每个节点都是有状态的,通常会持久化数据到永久存储中;
如果磁盘损坏导致集群里某个节点无法正常运行,则集群功能会部分受损;
StatefulSet是Deployment/RC的一个特殊变种,有如下特性:
StatefulSet里每个Pod都有稳定、唯一的网络标识,可以用来发现集群内其他成员。假设StatefulSet名字叫kafka,那么第1个Pod会命名为kafka-0,第2个Pod叫kafka-1,以此类推。
StatefulSet控制的Pod副本的启停顺序是受控的,操作第n个Pod时,前n-1个Pod已经是运行且准备好的状态。
StatefulSet里的Pod采用稳定的持久化存储卷,通过PV/PVC实现,删除Pod时默认不会删除与StatefulSet相关的存储卷。
StatefulSet需要与Headless Service配合使用,需要在每个StatefulSet的定义中声明它属于哪个Headless Service。
Headless Service没有Cluster IP,当解析Headless Service的DNS域名时,得到的是该Service对应的全部Pod的Endpoint列表。StatefulSet在Headless Service的基础上,又为受Headless Service控制的每个Pod实例创建了一个DNS域名,格式为:$(podname).$(headless service name)。
样例:一个3节点的kafka的StatefulSet集群
该应用集群的headless service名称定义为kafka
该应用集群的StatefulSet名字为kafka,则StatefulSet里的3个Pod的名称分别为:kafka-0,kafka-1,kafka-2
该应用集群的StatefulSet中3个Pod的DNS名称应该是:kafka-0.kafka,kafka-1.kafka,kafka-2.kafka
可以在该应用集群的配置文件中直接使用上述DNS名称来代表相应的Pod。