Kubernetes 入门之 Deployment

245 阅读9分钟

上一篇文章中,我罗列了所有的 Pod 控制器,但未做进一步讲解。

这篇文章主要讲解 Deployment 控制器。由于 Deployment 本质上是通过 ReplicaSet 管理的 Pod ,所以这篇文章也会包含 ReplicaSet 的内容。

一、ReplicaSet

ReplicaSet 简称 RS ,它的主要作用就是用来确保 Pod 的副本数始终保持一致。即如果有 Pod 异常退出,会自动创建新的 Pod 来替代,而如果异常多出来的容器也会自动回收。

有些文章可能会提到 ReplicationController ,即 RC ,它跟 RS 没有本质不同,Kubernetes 官方建议使用 RS 代替 RC 部署容器,RS 支持集合式的 selector

下面演示一个创建 RS 的模板信息:

rs.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: myapp
        image: heqingbao/k8s_myapp:v1
        ports:
        - containerPort: 80

先看一下清单文件的结构,可以理解为 Pod 模板外面套了一层 RS ,前一篇文章讲的 Pod 那那些探针等内容依然适用。

RS 还有很多复杂的标签,可以通过 kubectl explain rs 查看完整的模板信息。

此 RS 定义 Pod 的副本数为 3 个,下面来创建试试:

[root@master01 ~]# kubectl apply -f rs.yaml
replicaset.apps/frontend created

[root@master01 ~]# kubectl get pod
NAME             READY   STATUS    RESTARTS   AGE
frontend-cmnlh   1/1     Running   0          3s
frontend-dfzs5   1/1     Running   0          3s
frontend-vk2lt   1/1     Running   0          3s

可见,已经创建了 3 个 Pod 。

细心的你应该注意到了 RS 有个标签叫 matchLabels,而里面的 Pod 也刚好配置了 labels ,什么意思呢?

下面我们来修改下 label 试试:

[root@master01 ~]# kubectl label pod frontend-4gd7j tier=frontend1 --overwrite=True
pod/frontend-4gd7j labeled

[root@master01 ~]# kubectl get pod --show-labels
NAME             READY   STATUS    RESTARTS   AGE     LABELS
frontend-4gd7j   1/1     Running   0          2m31s   tier=frontend1
frontend-4w9kq   1/1     Running   0          2m31s   tier=frontend
frontend-9chbs   1/1     Running   0          7s      tier=frontend
frontend-x9vwz   1/1     Running   0          2m31s   tier=frontend

为什么会出现 4 个 Pod 呢?

因为 RS 会始终保持 match labels 的条件限制。即这里的 RS 会始终保持 Label= tier=frontend 的 Pod 的数量为 3 个。

对于 Kubernetes 来说, 它的很多副本数目监控都是以为 labels 为基础的。

二、Deployment

Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义方法,用来替代以前的 ReplicationController 来方便的管理应用。

典型的应用场景包括:

  • 定义 Deployment 来创建 Pod 和 ReplicaSet(Deployment 并不是直接管理 Pod,而是通过 RS 去管理 Pod)
  • 滚动升级和回滚应用
  • 扩容和缩容
  • 暂停和继续 Deployment

下面来演示下

2.1 部署一个简单的应用

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
     labels:
       app: myapp
    spec:
      containers:
      - name: myapp
        image: heqingbao/k8s_myapp:v1
        ports:
        - containerPort: 80

通过 Deployment 部署一个 3 个副本的 Pod 。

[root@master01 ~]# kubectl apply -f deployment.yaml
deployment.apps/myapp-deployment created

[root@master01 ~]# kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
myapp-deployment   3/3     3            3           10s

# Deployment 会创建对应的 RS
[root@master01 ~]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
myapp-deployment-669d4c567d   3         3         3       15s

[root@master01 ~]# kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
myapp-deployment-669d4c567d-84lq8   1/1     Running   0          18s
myapp-deployment-669d4c567d-bmrkf   1/1     Running   0          18s
myapp-deployment-669d4c567d-d7d4h   1/1     Running   0          18s

从上面可以看出,Deployment 是通过 RS 间接管理 Pod 的。

注意 Pod 的名字结构:

Deployment:myapp-deployment

ReplicaSet:myapp-deployment-669d4c567d

Pod:myapp-deployment-669d4c567d-84lq8

都是在上一层名称上加了个 hash

2.2 扩容

扩大到 10 个副本数

[root@master01 ~]# kubectl scale deployment myapp-deployment --replicas=10
deployment.apps/myapp-deployment scaled

[root@master01 ~]# kubectl get pod
NAME                                READY   STATUS    RESTARTS   AGE
myapp-deployment-669d4c567d-84lq8   1/1     Running   0          40s
myapp-deployment-669d4c567d-9gprm   1/1     Running   0          5s
myapp-deployment-669d4c567d-bb2pb   1/1     Running   0          5s
myapp-deployment-669d4c567d-bmrkf   1/1     Running   0          40s
myapp-deployment-669d4c567d-cqt79   1/1     Running   0          5s
myapp-deployment-669d4c567d-d7d4h   1/1     Running   0          40s
myapp-deployment-669d4c567d-jbtnw   1/1     Running   0          5s
myapp-deployment-669d4c567d-kftpx   1/1     Running   0          5s
myapp-deployment-669d4c567d-tp4lh   1/1     Running   0          5s
myapp-deployment-669d4c567d-w8b8g   1/1     Running   0          5s

你会发现,一旦部署进 k8s 以后,应用的扩缩容(尤其是无状态应用的扩缩容)是非常简单的。

同时我们再查看 RS:

[root@master01 ~]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
myapp-deployment-669d4c567d   10        10        10      48s

可以看到,RS 的名字并没有变,也即还是扩容前的 RS ,也就是说 RS 的模板没有被改变。所以这种 scale 的方式无法做到回滚(或回退)。

如果集群支持 HPA(Horizontal Pod Autoscaling)的话,还可以为 Deployment 设置自动扩展:

kubectl autoscale deployment myapp-deployment --min=10 --max=15 --cpu-percent=80

2.3 更新镜像

更新镜像也比较简单

# 把镜像升级到 v2 版本
[root@master01 ~]# kubectl set image deployment/myapp-deployment myapp=heqingbao/k8s_myapp:v2
deployment.apps/myapp-deployment image updated

# 发现创建了一个新的 RS ,并且所有的 Pod 都更新到了 v2 版本
[root@master01 ~]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
myapp-deployment-669d4c567d   0         0         0       4m19s
myapp-deployment-7597b547d7   10        10        10      8s

[root@master01 ~]# kubectl get pod -o wide
NAME                                READY   STATUS    RESTARTS   AGE    IP               NODE     NOMINATED NODE   READINESS GATES
myapp-deployment-7597b547d7-2mld5   1/1     Running   0          118s   172.16.140.91    node02   <none>           <none>
myapp-deployment-7597b547d7-2x87k   1/1     Running   0          118s   172.16.196.158   node01   <none>           <none>
myapp-deployment-7597b547d7-7zn2g   1/1     Running   0          118s   172.16.196.157   node01   <none>           <none>
myapp-deployment-7597b547d7-d4gdj   1/1     Running   0          115s   172.16.140.93    node02   <none>           <none>
myapp-deployment-7597b547d7-ddmb8   1/1     Running   0          118s   172.16.196.156   node01   <none>           <none>
myapp-deployment-7597b547d7-g7q7n   1/1     Running   0          115s   172.16.196.159   node01   <none>           <none>
myapp-deployment-7597b547d7-jk827   1/1     Running   0          114s   172.16.140.94    node02   <none>           <none>
myapp-deployment-7597b547d7-nxq2h   1/1     Running   0          115s   172.16.196.160   node01   <none>           <none>
myapp-deployment-7597b547d7-wlv5s   1/1     Running   0          118s   172.16.140.90    node02   <none>           <none>
myapp-deployment-7597b547d7-xm7n6   1/1     Running   0          116s   172.16.140.92    node02   <none>           <none>

# 验证
[root@master01 ~]# curl 172.16.140.91/index.html
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>

可以看到所有的 Pod 都已经全部更新到 v2 版本了。

这就是我们在 Deployment 里面更新镜像的方式,如果提交了新的代码,编译了新的镜像,,我们只需要这句简单的命令就可以把应用程序更新到最新版本,非常简单。

2.4 回滚

如果新的镜像有问题,还可以回滚:

[root@master01 ~]# kubectl rollout undo deployment/myapp-deployment
deployment.apps/myapp-deployment rolled back

[root@master01 ~]# kubectl get pod
NAME                                READY   STATUS        RESTARTS   AGE
myapp-deployment-669d4c567d-5h68s   1/1     Running       0          10s
myapp-deployment-669d4c567d-8h5m5   1/1     Running       0          6s
myapp-deployment-669d4c567d-d57bm   1/1     Running       0          10s
myapp-deployment-669d4c567d-d8bc9   1/1     Running       0          7s
myapp-deployment-669d4c567d-fkvtk   1/1     Running       0          6s
myapp-deployment-669d4c567d-ggq9x   1/1     Running       0          10s
myapp-deployment-669d4c567d-hsrts   1/1     Running       0          10s
myapp-deployment-669d4c567d-rjcvm   1/1     Running       0          6s
myapp-deployment-669d4c567d-tf94t   1/1     Running       0          8s
myapp-deployment-669d4c567d-tkj55   1/1     Running       0          10s
myapp-deployment-7597b547d7-2mld5   0/1     Terminating   0          5m18s
myapp-deployment-7597b547d7-7zn2g   0/1     Terminating   0          5m18s
myapp-deployment-7597b547d7-ddmb8   0/1     Terminating   0          5m18s
myapp-deployment-7597b547d7-g7q7n   0/1     Terminating   0          5m15s
myapp-deployment-7597b547d7-wlv5s   0/1     Terminating   0          5m18s

# 所有Pod已回滚到之前的RS管理了
[root@master01 ~]# kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
myapp-deployment-669d4c567d   10        10        10      9m41s
myapp-deployment-7597b547d7   0         0         0       5m30s

[root@master01 ~]# kubectl get pod -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
myapp-deployment-669d4c567d-5h68s   1/1     Running   0          56s   172.16.140.95    node02   <none>           <none>
myapp-deployment-669d4c567d-8h5m5   1/1     Running   0          52s   172.16.196.165   node01   <none>           <none>
myapp-deployment-669d4c567d-d57bm   1/1     Running   0          56s   172.16.196.162   node01   <none>           <none>
myapp-deployment-669d4c567d-d8bc9   1/1     Running   0          53s   172.16.196.164   node01   <none>           <none>
myapp-deployment-669d4c567d-fkvtk   1/1     Running   0          52s   172.16.140.99    node02   <none>           <none>
myapp-deployment-669d4c567d-ggq9x   1/1     Running   0          56s   172.16.196.161   node01   <none>           <none>
myapp-deployment-669d4c567d-hsrts   1/1     Running   0          56s   172.16.140.96    node02   <none>           <none>
myapp-deployment-669d4c567d-rjcvm   1/1     Running   0          52s   172.16.140.98    node02   <none>           <none>
myapp-deployment-669d4c567d-tf94t   1/1     Running   0          54s   172.16.196.163   node01   <none>           <none>
myapp-deployment-669d4c567d-tkj55   1/1     Running   0          56s   172.16.140.97    node02   <none>           <none>

# 验证
[root@master01 ~]# curl 172.16.140.95/index.html
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

可见所有 Pod 都已经回退到 v1 版本了。

还可以回滚到指定版本:

# 查看历史版本
[root@master01 ~]# kubectl rollout history deployment/myapp-deployment
deployment.apps/myapp-deployment
REVISION  CHANGE-CAUSE
2         <none>
3         <none>

# 回滚到指定版本
[root@master01 ~]# kubectl rollout undo deployment/myapp-deployment --to-revision=2
deployment.apps/myapp-deployment rolled back

可以使用 kubectl rollout status 查看 Deployment 是否完成,如果 rollout 成功完成,kubectl rollout status 将返回一个 0 值的 Exit Code

[root@master01 ~]# kubectl rollout status deployment/myapp-deployment
deployment "myapp-deployment" successfully rolled out

[root@master01 ~]# echo $?
[root@master01 ~]# 0


2.5 清理策略

可以通过设置 .spec.revisonHistoryLimit项来指定 deployment 最多保留多少 revision 历史记录,默认会保留所有,如果设置为 0 ,Deployment 就不允许回退了。


欢迎关注公众号:非著名开发者,订阅更多精彩内容。