k8s如何滚动升级应用

本文基于《Kubernetes in Action》第9章整理。

在进入正文前,不得不感慨一下标签选择器的设计对解耦k8s各模块发挥的作用。k8s的service, replicaSet, 滚动升级,调度的亲缘性和污点容忍度都离不开标签选择器。标签选择器让k8s对资源的操作更加灵活。

手动进行滚动升级

我们先用如下的配置创建一个ReplicationController

apiVersion: v1
kind: ReplicationController
metadata:
  name: kubia-v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kubia
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
        - image: test:v1
          name: my-container

并创建一个service,其标签选择器是 “app: kubia”

现在我们想要更新镜像,可以执行如下步骤进行滚动升级。

  • 新建一个新的ReplicationController,如下所示
apiVersion: v1
kind: ReplicationController
metadata:
  name: kubia-v2
spec:
  replicas: 0
  selector:
    matchLabels:
      app: kubia
      deployment: 757d16 # 增加标签,用于标记此次的升级记录
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
        deployment: 757d16 # 增加标签,用于标记此次的升级记录
    spec:
      containers:
        - image: test:v2 # 修改镜像
          name: my-container
  • 为原pod和ReplicationController增加标签:deployment: 343der。此时,kubia-v1还是管理着原先的pod,kubia-v2新建的pod不会被kubia-v1管理。但是不论kubia-v1还是kubia-v2创建的pod,都会和之前建的service关联。
  • 逐步扩容kubia-v2,并逐步缩容kubia-v1,直至所有pod都是由kubia-v2管理,则此次滚动升级结束

上述的步骤,也是之前kubectl的roling-update命令执行的大概过程。

这个过程存在以下弊端

  1. 过程繁琐。需要多次和API服务器交互
  2. 是在客户端执行,因此无法保证一致性,如果在滚动升级过程中和API服务器的交互出现问题,则pod, rc等资源会处于中间状态
  3. 不符合k8s的设计理念。应该通过设置期望的状态而不是告诉需要做哪些事情

通过Deployment滚动升级

首先创建以下配置,命名为deployment.yaml

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: kubia
spec:
  replicas: 3
  progressDeadlineSeconds: 600 # 滚动升级失败的超时时间
  minReadySeconds: 10 # 需要容器就绪多久后才能认为可用,在可用前,滚动升级不会继续。这个可以用于控制滚动升级的速率
  strategy:
    rollingUpdate:
      maxSurge: 1 # 在期望副本数基础上,最多允许超出的pod实例数量,允许设置绝对值和百分比
      maxUnavailable: 25% # 相对于期望副本数,允许有多少pod实例处于不可用状态,允许设置绝对值和百分比
    type: RollingUpdate # 表示滚动升级。也可以配置成 Recreate,其会一次性删除所有旧版本的pod,然后创建新的pod
  selector:
    matchLabels:
      app: kubia
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
        - image: test:v1
          name: my-container

执行下面命令会创建Deployment

kubectl create -f deployment.yaml --record

--record会记录历史版本号,在回滚时会很有用

随后,这个deployment会创建一个ReplicaSet,然后新建的ReplicaSet再去创建pod,不过这个都不需要我们关注。所以,Deployment是比ReplicaSet更高级的资源,是用于协调多个ReplicaSet的。

修改pod模板才会触发滚动升级,因此修改deployment本身的配置,以及pod关联的ConfigMap等都不会触发滚动升级。当滚动升级开始的时候,会新建一个ReplicaSet,根据新的pod模板创建新的pod,并不断扩容新的ReplicaSet,缩容旧的ReplicaSet。过程类似上面介绍的手动滚动升级,区别是Deployment不会删除旧的ReplicaSet,因此可以方便的进行回滚。

滚动升级相关的命令是kubectl rollout,可以查看其都有哪些子命令

k8s如何滚动升级应用_第1张图片

kubectl rollout history deployment my-deployment # 可以查看my-deployment的滚动升级历史
kubectl rollout pause deployment my-deployment # 可以暂停滚动升级
kubectl rollout resume deployment my-deployment # 可以恢复滚动升级
kubectl rollout status deployment my-deployment # 可以查看滚动升级中的状态
kubectl rollout undo deployment my-deployment --to-revision=1 # 回滚到指定版本

聊一下服务的上线

服务的上线是一个危险的动作,很多事故都是因为上线引起的。之所以危险,原因有很多,比如测试不到位,服务没有优雅退出,没有做好兼容等。所以对于服务的上线,需要足够的敬畏。

为了减少服务上线带来的事故,采取的措施一般有

  1. 封线。比如节假日前后,流量高峰期时一般不允许上线
  2. 周知。周知相关服务的负责人,让他们协助在服务上线期间一起观察服务有无异常
  3. 分阶段升级。比如第一次只升级其中一个实例,第二次升级3个实例,逐步放量,缓慢上线
  4. 做好观察。在服务上线期间,需要盯监控,关注告警,观察失败日志,在出现异常的时候第一时间会滚

你可能感兴趣的:(k8s,kubernetes,云原生,容器)