Deployment
在Pod这个章节介绍了Pod,Pod是Kubernetes创建或部署的最小单位,但是Pod是被设计为相对短暂的一次性实体,Pod可以被驱逐(当节点资源不足时)、随着集群的节点fail而消失。同时kubernetes提供了Controller(控制器)来管理Pod,Controller可以创建和管理多个Pod,提供副本管理、滚动升级和自愈能力,其中最为常用的就是Deployment。
一个Deployment可以包含一个或多个Pod副本,每个Pod副本的角色相同,所以系统会自动为Deployment的多个Pod副本分发请求。
Deployment集成了上线部署、滚动升级、创建副本,恢复上线任务,在某种程度上,Deployment可以帮我们实现无人值守的上线,大大降低我们的上线过程的复杂沟通、操作风险。
创建Deployment
以下示例为创建一个名为nginx的Deployment负载,使用nginx:latest镜像创建两个Pod,每个Pod占用500m core CPU、1G内存。
apiVersion: apps/v1 # 注意这里与Pod的区别,Deployment是apps/v1而不是v1 kind: Deployment # 资源类型为Deployment metadata: name: nginx # Deployment的名称 spec: replicas: 2 # Pod的数量,Deployment会确保一直有2个Pod运行 selector: # Label Selector matchLabels: app: nginx template: # Pod的定义,用于创建Pod,也称为Pod template metadata: labels: app: nginx spec: volumes: - name: cci-sfs-test # sfs卷的名称 persistentVolumeClaim: claimName: cci-sfs-test containers: - image: nginx:latest name: container-0 resources: limits: cpu: 500m memory: 1024Mi requests: cpu: 500m memory: 1024Mi volumeMounts: - name: cci-sfs-test mountPath: /tmp/sfs0/krlp2k8j # sfs卷的容器内挂载路径 imagePullSecrets: # 拉取镜像使用的证书,必须为imagepull-secret - name: imagepull-secret
从这个定义中可以看到Deployment的名称为nginx,spec.replicas定义了Pod的数量,即这个Deployment控制2个Pod;spec.selector是Label Selector(标签选择器),表示这个Deployment会选择Label为app=nginx的Pod;spec.template是Pod的定义,内容与Pod中的定义完全一致。
将上面Deployment的定义保存到deployment.yaml文件中,使用kubectl创建这个Deployment。
使用kubectl get查看Deployment和Pod,可以看到DESIRED值为2,这表示这个Deployment期望有2个Pod,CURRENT也为2,这表示当前有2个Pod,AVAILABLE为2表示有2个Pod是可用的。
$ kubectl create -f deployment.yaml -n $namespace_name $ kubectl get deployment -n $namespace_name NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx 2 2 2 2 8s
Deployment如何控制Pod
继续查询Pod,如下所示。
$ kubectl get pods -n $namespace_name NAME READY STATUS RESTARTS AGE nginx-7f98958cdf-tdmqk 1/1 Running 0 13s nginx-7f98958cdf-txckx 1/1 Running 0 13s
如果删掉一个Pod,您会发现立马会有一个新的Pod被创建出来,如下所示,这就是前面所说的Deployment会确保有2个Pod在运行,如果删掉一个,Deployment会重新创建一个,如果某个Pod崩溃或有什么问题,Deployment会自动拉起这个Pod。
$ kubectl delete pod nginx-7f98958cdf-txckx -n $namespace_name $ kubectl get pods -n $namespace_name NAME READY STATUS RESTARTS AGE nginx-7f98958cdf-tdmqk 1/1 Running 0 21s nginx-7f98958cdf-tesqr 1/1 Running 0 21s
看到有如下两个名为nginx-7f98958cdf-tdmqk和nginx-7f98958cdf-tesqr的Pod, 其中nginx是直接使用Deployment的名称,-7f98958cdf-tdmqk和-7f98958cdf-tesqr是kubernetes随机生成的后缀。
您也许会发现这两个后缀中前面一部分是相同的,都是7f98958cdf,这是因为Deployment不是直接控制Pod的,Deployment是通过一种名为ReplicaSet的控制器控制Pod,通过如下命令可以查询ReplicaSet,其中rs是ReplicaSet的缩写。
$ kubectl get rs -n $namespace_name NAME DESIRED CURRENT READY AGE nginx-7f98958cdf 3 3 3 1m
这个ReplicaSet的名称为nginx-7f98958cdf,后缀-7f98958cdf也是随机生成的。
Deployment控制Pod的方式如图1所示,Deployment控制ReplicaSet,ReplicaSet控制Pod。
如果使用kubectl describe命令查看Deployment的详情,您就可以看到ReplicaSet,如下所示,可以看到有一行 NewReplicaSet: nginx-7f98958cdf (2/2 replicas created),而且 Events 里面事件确是把ReplicaSet的实例扩容到2个。在实际使用中您也许不会直接操作ReplicaSet,但了解Deployment通过控制ReplicaSet来控制Pod会有助于您定位问题。
$ kubectl describe deploy nginx -n $namespace_name Name: nginx Namespace: default CreationTimestamp: Sun, 16 Dec 2018 19:21:58 +0800 Labels: app=nginx ... NewReplicaSet: nginx-7f98958cdf (2/2 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 5m deployment-controller Scaled up replica set nginx-7f98958cdf to 2
升级
在实际应用中,升级是一个常见的场景,Deployment能够很方便地支撑应用升级。
Deployment 可以设置不同的升级策略,有如下两种。
- RollingUpdate:也就是滚动升级(逐步创建新Pod然后删除旧Pod),也是默认策略
- Recreate:也就是先把当前Pod删掉再重新创建Pod
Deployment的升级可以是声明式的,也就是说只需要修改Deployment的YAML定义即可,比如使用kubectl edit命令将上面Deployment中的镜像修改为nginx:alpine。修改完成后再查询ReplicaSet和Pod,发现创建了一个新的ReplicaSet,Pod也重新创建了。
$ kubectl edit deploy nginx -n $namespace_name $ kubectl get rs -n $namespace_name NAME DESIRED CURRENT READY AGE nginx-6f9f58dffd 2 2 2 1m nginx-7f98958cdf 0 0 0 48m $ kubectl get pods -n $namespace_name NAME READY STATUS RESTARTS AGE nginx-6f9f58dffd-tdmqk 1/1 Running 0 21s nginx-6f9f58dffd-tesqr 1/1 Running 0 21s
Deployment可以通过maxSurge 和 maxUnavailable两个参数控制升级过程中同时重新创建Pod的比例,这在很多时候是非常有用,配置如下所示。
spec: strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0 type: RollingUpdate
- maxSurge:与Deployment中spec.replicas相比,可以有多少个Pod存在,默认值是25%,比如spec.replicas为 4,那升级过程中就不能超过5个 Pod存在,即按1个的步伐升级,实际升级过程中会换算成数字,且换算会向上取整。这个值也可以直接设置成数字。
- maxUnavailable:与Deployment中spec.replicas相比,可以有多少个Pod失效,也就是删除的比例,默认值是25%,比如spec.replicas为 4,那升级过程中就至少有3个Pod存在,即删除Pod 的步伐是 1。同样这个值也可以设置成数字。
在前面的例子中,由于spec.replicas是2,如果maxSurge和maxUnavailable都为默认值25%,那实际升级过程中,maxSurge允许最多3个 Pod 存在(向上取整,2*1.25=2.5,取整为3),而 maxUnavailable 则不允许有 Pod Unavailable(向上取整,2*0.75=1.5,取整为2),也就是说在升级过程中,一直会有2个Pod处于运行状态,每次新建一个Pod,等这个Pod创建成功后再删掉一个旧Pod,直至Pod全部为新Pod。
回滚
回滚也称为回退,即当发现升级出现问题时,让应用回到老的版本。Deployment可以非常方便地回滚到老版本。
例如上面升级的新版镜像有问题,可以执行kubectl rollout undo命令进行回滚。
$ kubectl rollout undo deployment nginx -n $namespace_name deployment "nginx" rolled back
Deployment之所以能如此容易的做到回滚,是因为Deployment是通过ReplicaSet控制Pod的,升级后之前ReplicaSet都一直存在,Deployment回滚做的就是使用之前的ReplicaSet再次把Pod创建出来。Deployment中保存ReplicaSet的数量可以使用revisionHistoryLimit参数限制,默认值为10。