Deployment


无状态服务deployment

Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括:

  • 定义 Deployment 来创建 Pod 和 ReplicaSet

  • 滚动升级和回滚应用

  • 扩容和缩容

49.png

Deployment 应用示例:

vim deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      app: web-nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: web-nginx
    spec:
      containers:
        - name: web-nginx
          image: docker.io/nginx
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 80


kubectl create -f deploy.yaml --record
    ## --record参数可以记录命令,我们可以很方便的查看每次 revision 的变化

创建完成后,我们可以查看下我们的 Pod 状态:

50.png

我们可以通过命令 kubectl scale deployment my-nginx --replicas=5 将副本数量扩容到 5 个:

53.png

也可以通过该命令 kubectl scale deployment my-nginx --replicas=2 缩容到 2 个:

54.png

这个时候我们注意一下,在缩容的时候,优先删除的是创建时间短的 Pod 。下面我们在来看一下 deployment 的升级与回滚:

查看当前的 Pod 当中的 nginx 的版本: kubectl exec Pod-name -it – nginx -v

升级 images 版本: kubectl set image deployment/my-nginx web-nginx=nginx:1.9.1

55.png

使用命令 kubectl get rs 命令查看 Pod 的更新过程:

56.png

当升级完成后,查看一下当前 Pod 的 nginx 的版本:

57.png

通过命令查看 deployment 的历史记录: kubectl rollout history deployment my-nginx

58.png

回滚到之前的版本: kubectl rollout undo deployment --to-revision=1

59.png

回滚完成后,查看一下当前 Pod 的 nginx 的版本:

60.png

清理 Policy :

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

实战

Deployment实例

# 创建一个deployment,引用nginx的服务镜像,这里的副本数量默认是1,nginx容器镜像用的是latest
# 在K8s新版本开始,对服务api进行了比较大的梳理,明确了各个api的具体职责,而不像以前旧版本那样混为一谈
# kubectl create deployment nginx --image=docker.io/library/nginx:1.21.6
deployment.apps/nginx created

# 查看创建结果
# kubectl get deployments.apps
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           17s

# kubectl  get rs   # <-- 看下自动关联创建的副本集replicaset
NAME               DESIRED   CURRENT   READY   AGE
nginx-796b85dbb8   1         1         1       34s


# kubectl get pod   # <-- 查看生成的pod,注意镜像下载需要一定时间,耐心等待,注意观察pod名称的f89759699,是不是和上面rs的一样,对了,因为这里的pod就是由上面的rs创建出来,为什么要设置这么一个环节呢,后面会以实例来演示
NAME                    READY   STATUS              RESTARTS   AGE
nginx-796b85dbb8-7gxn8   0/1     ContainerCreating   0          13s

# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-796b85dbb8-7gxn8   1/1     Running   0          58s



# 扩容pod的数量
# kubectl scale deployment nginx --replicas=2
deployment.apps/nginx scaled

# 查看扩容后的pod结果
# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-796b85dbb8-7gxn8   1/1     Running   0          105s
nginx-796b85dbb8-hrlrx   1/1     Running   0          3s


# 具体看下pod是不是分散运行在不同的node上呢
# kubectl get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE    IP              NODE         NOMINATED NODE   READINESS GATES
nginx-796b85dbb8-7gxn8   1/1     Running   0          2m7s   172.20.139.70   10.0.1.203   <none>           <none>
nginx-796b85dbb8-hrlrx   1/1     Running   0          25s    172.20.217.78   10.0.1.204   <none>           <none>



# 接下来替换下这个deployment里面nginx的镜像版本,来讲解下为什么需要rs副本集呢,这个很重要哦
# 我们先看看目前nginx是哪个版本,随便输入一个错误的uri,页面就会打印出nginx的版本号了

# 我们先来创建一个service
# kubectl create service clusterip nginx --tcp=80:80 --dry-run=client -o yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: nginx
  name: nginx
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: ClusterIP
status:
  loadBalancer: {}


nginx_svc=$(kubectl get svc --no-headers |awk '/^nginx/{print $3}')

curl ${nginx_svc}/1
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.21.6</center>
</body>
</html>

# 根据输出可以看到版本号是nginx/1.21.6,我们这里模拟服务发版操作,先来看下有哪些版本的nginx
ctr -n k8s.io images ls|grep nginx

# 注意命令最后面的 `--record` 参数,这个在生产中作为资源创建更新用来回滚的重要标记,强烈建议在生产中操作时都加上这个参数
# kubectl set image deployment/nginx  nginx=docker.io/library/nginx:1.25.1 --record 
deployment.apps/nginx image updated

# 观察下pod的信息,可以看到旧nginx的2个pod逐渐被新的pod一个一个的替换掉
# kubectl  get pod -w
NAME                     READY   STATUS              RESTARTS   AGE
nginx-5f5f7c68bc-csgw2   1/1     Running             0          2m18s
nginx-5f5f7c68bc-gbkl9   0/1     ContainerCreating   0          84s
nginx-796b85dbb8-hrlrx   1/1     Running             0          12m


# 我们再看下nginx的rs,可以看到现在有两个了
# kubectl get rs
NAME               DESIRED   CURRENT   READY   AGE
nginx-5f5f7c68bc   2         2         2       5m7s
nginx-796b85dbb8   0         0         0       16m


# 看下现在nginx的描述信息,我们来详细分析下这个过程
# kubectl describe deployments.apps nginx
Name:                   nginx
Namespace:              default
CreationTimestamp:      Thu, 26 Oct 2023 21:50:16 +0800
Labels:                 app=nginx
......
RollingUpdateStrategy:  25% max unavailable, 25% max surge  # 注意这里,这个就是用来控制rs新旧版本迭代更新的一个频率,滚动更新的副本总数最大值(以2的基数为例):2+2*25%=2.5 -- > 3,可用副本数最大值(默认值两个都是25%):2-2*25%=1.5 --> 2
......


Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  16m    deployment-controller  Scaled up replica set nginx-796b85dbb8 to 1
  Normal  ScalingReplicaSet  14m    deployment-controller  Scaled up replica set nginx-796b85dbb8 to 2 from 1
  Normal  ScalingReplicaSet  5m22s  deployment-controller  Scaled up replica set nginx-5f5f7c68bc to 1  # 启动1个新版本的pod
  Normal  ScalingReplicaSet  3m14s  deployment-controller  Scaled down replica set nginx-796b85dbb8 to 1 from 2 # 上面完成就释放掉一个旧版本的
  Normal  ScalingReplicaSet  3m14s  deployment-controller  Scaled up replica set nginx-5f5f7c68bc to 2 from 1 # 然后再启动1个新版本的pod
  Normal  ScalingReplicaSet  65s    deployment-controller  Scaled down replica set nginx-796b85dbb8 to 0 from 1 # 释放掉最后1个旧的pod



# 回滚
# 还记得我们上面提到的 --record  参数嘛,这里它就会发挥很重要的作用了
# 这里还以nginx服务为例,先看下当前nginx的版本号

nginx_svc=$(kubectl get svc --no-headers |awk '/^nginx/{print $3}')
curl ${nginx_svc}/1

<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.25.1</center>
</body>
</html>

# 升级nginx的版本
#  kubectl set image deployments/nginx nginx=nginx:1.21.6 --record 

# 已经升级完成
# curl ${nginx_svc}/1         
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.21.6</center>
</body>
</html>

# 这里假设是我们在发版服务的新版本,结果线上反馈版本有问题,需要马上回滚,看看在K8s上怎么操作吧
# 首先通过命令查看当前历史版本情况,只有接了`--record`参数的命令操作才会有详细的记录,这就是为什么在生产中操作一定得加上的原因了
# kubectl rollout history deployment nginx 
deployment.apps/nginx 
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployment/nginx nginx=docker.io/library/nginx:1.25.1 --record=true
3         kubectl set image deployments/nginx nginx=nginx:1.21.6 --record=true


# 根据历史发布版本前面的阿拉伯数字序号来选择回滚版本,这里我们回到上个版本号,也就是选择2 ,执行命令如下:
# kubectl rollout undo deployment nginx --to-revision=2
deployment.apps/nginx rolled back

# 等一会pod更新完成后,看下结果已经回滚完成了,怎么样,在K8s操作就是这么简单:
# curl ${nginx_svc}/1                                
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.25.1</center>
</body>
</html>


# 在K8s上命令行删除一个资源直接用delete参数
# kubectl delete deployment nginx
deployment.apps "nginx" deleted

# 可以看到关联的rs副本集也被自动清空了
# kubectl  get rs
No resources found in default namespace.

# 相关的pod也没了
# kubectl get pod 
No resources found in default namespace.


# 生成nginx.yaml文件
# kubectl create deployment nginx --image=nginx --dry-run -o yaml > nginx.yaml
我们注意到执行上面命令时会有一条告警提示... --dry-run is deprecated and can be replaced with --dry-run=client.  ,虽然并不影响我们生成正常的yaml配置,但如果看着不爽可以按命令提示将--dry-run换成--dry-run=client
# 接着我们vim nginx.yaml,将replicas: 1的数量改成replicas: 2

# 开始创建,我们后面这类基于yaml文件来创建资源的命令统一都用apply了
# kubectl  apply -f nginx.yaml 
deployment.apps/nginx created

# 查看创建的资源,这个有个小技巧,同时查看多个资源可以用,分隔,这样一条命令就可以查看多个资源了
# kubectl get deployment,rs,pod
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   2/2     2            2           116s

NAME                              DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-f89759699   2         2         2       116s

NAME                        READY   STATUS    RESTARTS   AGE
pod/nginx-f89759699-bzwd2   1/1     Running   0          116s
pod/nginx-f89759699-qlc8q   1/1     Running   0          116s

作业

试着用命令行和yaml配置这两种方式,来创建redis的deployment服务,同时可以将pod后面的作业再复习下