• Kubernetes--k8s---滚动更新--零停机不停服发布服务


    1 滚动更新的定义和目标

    滚动更新的含义

    一次只更新一小部分副本,成功后,再更新更多的副本,最终完成所有副本的更新。

    滚动更新的好处

    最大好处是零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性。

    根据 yaml 创建资源, apply 可以重复执行,create 不行

    kubectl create -f deploy.yml
    kubectl apply -f deploy.yml --record

    注意 当deploy.yml 是上次发布的内容没有更改时,使用kubectl apply无法进行更新发布。比如镜像使用的是latest标签时。

    我们在发布deployment时,如果使用了如下的发布方式 或者 参数配置不正确时,会发现 服务会挂掉一会儿,用户会访问不了。

    kubectl  delete  --ignore-not-found=true -f deploy.yml
    kubectl  create -f deploy.yml

    原因是
    pod被删除或者 容器启动后,到服务真正工作起来,中间会有一段时间无法正常访问,但 k8s 却认为服务是正常就绪状态。

    本篇文章主要解决这个问题,实现 平滑的发布,发布更新服务过程中保证服务一直可用,用户零感知。

    2 设置滚动更新

    2.1 服务准备

    我们有一个api服务deploy.yaml如下:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: familytree-api
      namespace: default
    spec:
      selector:
        matchLabels:
          app: familytree-api
      replicas: 3
      template:
        metadata:
          labels:
            app: familytree-api
        spec:
          containers:
          - name: familytree-api
            image: 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:1.0.0
            imagePullPolicy: Always
            resources:
              requests:
                cpu: 1
                memory: 1Gi
              limits:
                cpu: 4
                memory: 4Gi
            env:
              - name: VERSION
                value: 1.0.0
            ports:
              - containerPort: 8080
    
    
    ---
    
    apiVersion: v1
    kind: Service
    metadata:
      name: familytree-api-service
      namespace: default
    spec:
      selector:
        app: familytree-api
      ports:
        - protocol: TCP
          port: 8080
          targetPort: 8080
    ---
    
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: familytree-api-ingress
      namespace: default
      annotations:
        kubernetes.io/ingress.class: traefik
        traefik.frontend.rule.type: PathPrefix
    spec:
      rules:
      -
        host: api.test.com
        http:
          paths:
          - path: /api/nowater
            backend:
              serviceName: familytree-api-service
              servicePort: 8080
    ---

    服务中包含url路由接口可返回版本号和当前hostname

    访问路由

    app.router.add_get('/api/nowater/version', service.version_print)

    实现代码如下:

    async def version_print(request):
        version = config["version"]
        hostname = socket.gethostname()
        try:
            print("打印版本 "+version+" hostname " + hostname)
            return web.json_response({'version': version, "hostname": hostname})
        except Exception as e:
            return web.json_response({'msg': e.value}, status=500)

    使用命令发布服务

    kubectl create -f deploy.yml

    查看部署列表

    kubectl get deployments | grep familytree-api

    查看正在运行的pod

    kubectl get pods | grep familytree-api

    查看正在运行的pod使用的镜像

    kubectl get deployment -o wide | grep familytree-api

    输出如下:

    [zzq@host3 ~]$ kubectl get deployment -o wide | grep familytree-api
    familytree-api 3 3 3 0 4m familytree-api 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:1.0.0 app=familytree-api

    通过pod描述,查看服务的当前映像版本

    kubectl describe pods familytree-api-7c6fd4bb75-5qtr5

    访问服务url

    [zzq@host3 ~]$ curl http://api.test.com/api/nowater/version
    {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}

    2.2 进行滚动升级

    方式一 将yaml中的镜像版本修改为升级版本–推荐

    image: 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:2.0.0

    环境变量也修改为2.0.0

            env:
              - name: VERSION
                value: 2.0.0

    然后使用apply命令重新发布服务

    kubectl apply -f deploy.yml --record

    记得一定需要带有 --record,否则没有版本的信息记录,不利于回滚定位。

    方式二 使用命令

    kubectl set image deployments/familytree-api familytree-api=123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:2.0.0

    2.3 查看是否升级成功

    查看状态:

    kubectl rollout status deployment/familytree-api
    Waiting for rollout to finish: 1 out of 3 new replicas have been updated..
    deployment "familytree-api" successfully rolled out

    暂停升级

    kubectl rollout pause deployment <deployment>

    继续升级

    kubectl rollout resume deployment <deployment>

    升级结束后,继续查看rs的状态:

    kubectl get rs

    根据AGE我们可以看到离我们最近的当前状态是:3,和我们的yaml文件是一致的,证明升级成功了。用describe命令可以查看升级的全部信息:

    kubectl describe deployment familytree-api

    输出为

    [zzq@host3 ~]$ kubectl describe deployment familytree-api
    Name:                   familytree-api
    Namespace:              default
    CreationTimestamp:      Mon, 23 Sep 2019 18:12:43 +0800
    Labels:                 <none>
    Annotations:            deployment.kubernetes.io/revision=2
                            kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{"kubernetes.io/change-cause":"kubectl apply --filename=./deploy/deploy-prod.yml ...
                            kubernetes.io/change-cause=kubectl apply --filename=./deploy/deploy-prod.yml --record=true
    Selector:               app=familytree-api
    Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=familytree-api
      Containers:
       familytree-api:
        Image:     123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:2.0.0
        Port:       8080/TCP
        Host Port:  0/TCP
        Limits:
          cpu:     4
          memory:  4Gi
        Requests:
          cpu:     1
          memory:  1Gi
        Environment:
          VERSION:  2.0.0
        Mounts:     <none>
      Volumes:      <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    NewReplicaSetAvailable
    OldReplicaSets:  <none>
    NewReplicaSet:   familytree-api-c6fbb4499 (3/3 replicas created)
    Events:
      Type    Reason             Age   From                   Message
      ----    ------             ----  ----                   -------
      Normal  ScalingReplicaSet  20m   deployment-controller  Scaled up replica set familytree-api-66f79b747c to 3
      Normal  ScalingReplicaSet  3m    deployment-controller  Scaled up replica set familytree-api-c6fbb4499 to 1
      Normal  ScalingReplicaSet  3m    deployment-controller  Scaled down replica set familytree-api-66f79b747c to 2
      Normal  ScalingReplicaSet  3m    deployment-controller  Scaled up replica set familytree-api-c6fbb4499 to 2
      Normal  ScalingReplicaSet  3m    deployment-controller  Scaled down replica set familytree-api-66f79b747c to 1
      Normal  ScalingReplicaSet  3m    deployment-controller  Scaled up replica set familytree-api-c6fbb4499 to 3
      Normal  ScalingReplicaSet  3m    deployment-controller  Scaled down replica set familytree-api-66f79b747c to 0

    访问服务url

    [zzq@host3 ~]$ curl http://api.test.com/api/nowater/version
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}

    3 设置服务存活探针和服务健康检查探针以及相应参数

    探针官网介绍

    使用上面的发布步骤并不能保证 服务完全平滑。

    因为k8s不能判断 一个的服务是否已经可用,只要pod正常启动就会判断成 可用。

    但是pod启动后并不代表服务可用,比如java的程序 可能还需要启动spring boot框架,去连接数据库等待。

    这样就会导致 短暂的 服务不可用。

    3.1 服务不可用的示例


    比如我们一直访问准备好的version版本查询接口如下:

    while :; do curl http://api.test.com/api/nowater/version; sleep 1; done

    然后进行版本更新发布

    kubectl apply -f deploy.yml --record

    输出如下:

    [zzq@host3 ~]$ while :; do curl http://api.test.com/api/nowater/version; sleep 1; done 
    ----------
    {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
    ----------
    {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
    ----------
    {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
    ----------
    {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
    ----------
    curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused
    curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused
    curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused
    curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused
    curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused
    ----------
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
    ----------
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
    ----------
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
    ----------
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
    ----------
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
    ----------

    我们可以发现镜像版本已经更新到2.0.0
    我们可以在2.0.0镜像中加入延迟启动服务,也就是说,会先sleep 20s,然后才去启动app服务。
    这就模拟了在服务启动过程中,虽然pod已经是存在的状态,但是并没有真正提供服务。
    可以看到,由于延迟启动,api并没有真正做好准备提供服务,此时流量已经发到后端,导致服务不可用的状态

    3.2 解决方案–探针检测

      在实际生产环境中会遇到这样那样的问题,比如:容器里面应用挂了或者说新启动的容器里面应用还没有就绪等等,所以说就需要进行探测来检验容器是否满足需求。

      那么一般的检测分为几种,比如:进程检测、业务检测。

      进程检测呢很好理解,也就是说通过检测容器进程来验证容器内应用是否存活。
      Kubelet会定期通过Docker Daemon获取所有Docker进程的运行情况,如果发现某个Docker容器未正常运行,则重新启动该容器进程。目前,进程级的健康检查都是默认启用的。

      业务检测呢也好理解,有些人会问,有了进程检测不就挺好的么,为什么要进行业务检测? 
      因为在很多实际场景下,仅仅使用进程级健康检查还远远不够。有时,从Docker的角度来看,容器进程依旧在运行;但是如果从应用程序的角度来看,假设应用代码处于死锁状态的话,那每次调度到这个容器的时候永远都无法正常响应用户的业务。比如对于使用java web服务的应用来说,并不是简单地说tomcat启动成功就可以对外提供服务的,还需要等待spring容器初始化,数据库连接连接上等等。

      为了解决以上问题,Kubernetes引人了一个在容器内执行的活性探针(liveness probe)的概念,以支持用户自己实现应用业务级的健康检查。这些检查项由Kubelet代为执行,以确保用户的应用程序正确运转,至于什么样的状态才算“正确”,则由用户自己定义。

      Kubernetes支持3种类型的应用健康检查动作,分别为HTTP Get、Container Exec和TCP Socket。exec的方式比较通用的,因为不是每个服务都有http服务,但每个服务都可以在自己内部定义健康检查的job,定期执行,然后将检查结果保存到一个特定的文件中,外部探针就不断的查看这个健康文件就OK了。

      介绍完存活性探针(liveness probe)之后我们来看看就绪探针(readiness probe),就绪探针是来确定容器是否已经就绪可以接受访问,只有当Pod中的容器都处于就绪状态时kubelet才会认定该Pod处于就绪状态,至于什么样的状态才算 ”就绪”,还是由用户自己定义。该状态的作用就是控制哪些Pod可以作为service的后端,如果Pod处于非就绪状态,那么它们将会被从service的load balancer中移除,防止 流量分发到 异常的pod中。

    4 存活性探针(liveness probe)和就绪探针(readiness probe)的区别

      readinessProbe检查成功与否,决定这个pod是否会被加入到Service的load balancer列表中,即是否给它分配访问的流量,并不影响Pod本身的生命周期

      如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活探针; kubelet 将根据Pod的restartPolicy自动执行正确的操作。

      如果您希望容器在探测失败时被杀死并重新启动,那么请指定一个存活探针,并指定restartPolicy为Always或OnFailure。

      如果要仅在探测成功时才开始向 Pod 发送流量,请指定就绪探针。在这种情况下,就绪探针可能与存活探针相同,但是spec中的就绪探针的存在意味着Pod将在没有接收到任何流量的情况下启动,并且只有在探针探测成功后才开始接收流量。

      两种探测的配置方法完全一样,支持的配置参数也一样,既可单独探测又可结合者一起执行。

      LivenessProbe:用于判断容器是否存活(running状态),如果LivenessProbe探针探测到容器不健康,则kubelet杀掉该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含LivenessProbe探针,则kubelet认为该容器的LivenessProbe探针返回的值永远是“Success”。

      ReadinessProbe:用于判断容器是否启动完成(ready状态),可以接收请求。如果ReadinessProbe探针检测到失败,则Pod的状态被修改。Endpoint Controller将从Service的Endpoint中删除包含该容器所在Pod的Endpoint。

    4.1 存活性探测

    livenessProbe:存活性探测,最主要是用来探测pod是否需要重启–决定把pod删除重新创建

    在spec的containers中增加
    与image同级
    exec探针:

            livenessProbe:
              exec:
                command:
                - cat
                - /tmp/healthy
              initialDelaySeconds: 5
              periodSeconds: 10
              timeoutSeconds: 2       
              failureThreshold: 3       

    http探针:

        livenessProbe:
          httpGet:
            path: /health
            port: 8080
            scheme: HTTP
        initialDelaySeconds: 5
        periodSeconds: 10
        timeoutSeconds: 2
        failureThreshold: 3

    tcp探针:

      livenessProbe:
          tcpSocket:
            port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
      timeoutSeconds: 2 
      failureThreshold: 3

    参数说明

    说法1:

    initialDelaySeconds:容器启动后第一次执行探测是需要等待多少秒。

    periodSeconds:执行探测的频率。默认是10秒,最小1秒。

    timeoutSeconds:探测超时时间。默认1秒,最小1秒。

    successThreshold:探测失败后,最少连续探测成功多少次才被认定为成功。默认是1。对于liveness必须是1。最小值是1。

    failureThreshold:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3。最小值是1。

    说法2:

    initialDelaySeconds: 表示容器启动之后延迟多久进行liveness探测

    timeoutSeconds:每次执行探测的超时时间

    periodSeconds:探测的周期时间

    successThreshold:最少连续几次探测成功的次数,满足该次数则认为success。

    failureThreshold:最少连续几次探测失败的次数,满足该次数则认为fail作

    举例:

    initialDelaySeconds: 5 #告诉kubelet在第一次执行probe之前要的等待5秒钟

    periodSeconds: 10 #kubelet要每隔10秒执行一次liveness probe 检查

    timeoutSeconds: 2 #超长时长,默认为1s,最小值也为1s

    failureThreshold: 3 #处于成功状态时,探测操作至少连续多少次的失败才被视为检测不通过,默认为3,最小为1

    探针检测命令是在容器中执行 cat /tmp/healthy 命令。
    如果命令执行成功,将返回0,kubelet就会认为该容器是活着的并且很健康。如果返回非0值,kubelet就会杀掉这个容器并重启它。

    4.2 就绪性探测


    readinessProbe:就绪性探测,用来探测pod是否已经能够提供服务–决定是否参与分配流量

    在spec的containers中增加
    与image同级

            readinessProbe:
              tcpSocket:
                port: 80
              initialDelaySeconds: 5
              periodSeconds: 10

    或者

            readinessProbe:
              httpGet:
                path: /api/nowater/version
                port: 8080
                httpHeaders:
                - name : X-Custom-Header
                  value: Awesome
              initialDelaySeconds: 5
              periodSeconds: 10

    periodSeconds 规定kubelet要每隔10秒执行一次readinessProbe 检查。

    initialDelaySeconds 告诉kubelet在第一次执行probe之前要的等待5秒钟。
    探针检测命令是检查tcp连接 端口80 是否畅通。
    也可以检查某个http 请求是否返回成功码。
    如果返回一个成功的返回码,kubelet就会认定该容器服务是可用的。
    如果返回失败的返回码,kubelet将该pod改为not ready,将会被从service的load balancer中移除。

    注意:任何大于200小于400的返回码都会认定是成功的返回码。其他返回码都会被认为是失败的返回码。

    由于设置了readinessProbe,虽然pod已经启动起来了,但是并不会立即投入使用,会出现了 READY: 0/1 的情况
    并且有pod出现了一直持续Terminating状态,因为滚动更新的限制,至少要保证有pod可用

    再查看curl的状态,image的版本平滑更新到2.0.0,没有出现报错的状况

    [zzq@host3 ~]$ while :; do curl http://api.test.com/api/nowater/version; sleep 1; done 
    ----------
    {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
    ----------
    {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
    ----------
    {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
    ----------
    {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
    ----------
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
    ----------
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
    ----------
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
    ----------
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
    ----------
    {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
    ----------

    4.3 调整参数设置

    在spec下面添加滚动升级策略:
    与template同级

    minReadySeconds: 5
    strategy:
      # indicate which strategy we want for rolling update
      type: RollingUpdate
      rollingUpdate:
        maxSurge: 1
        maxUnavailable: 1

    minReadySeconds:

    这个值默认是0,Kubernetes会假设该容器启动起来后就可以提供服务了,会导致用户访问异常
    这里需要估一个比较合理的值,从容器启动到应用正常提供服务
    如果没有设置该值,Kubernetes会假设该容器启动起来后就提供服务了
    如果没有设置该值,在某些极端情况下可能会造成服务不正常运行

    maxSurge:
    升级过程中最多可以比原先设置多出的POD数量
    例如:maxSurage=1,replicas=5,则表示Kubernetes会先启动1一个新的Pod后才删掉一个旧的POD,整个升级过程中最多会有5+1个POD。

    maxUnavaible:
    升级过程中最多有多少个POD处于无法提供服务的状态
    当maxSurge不为0时,该值也不能为0
    例如:maxUnavaible=1,则表示Kubernetes整个升级过程中最多会有1个POD处于无法服务的状态。

    4.4 格式如下

    4.5 回滚

    查看Deployment的升级历史:

    kubectl rollout history deployment nginx-deploy

    查看指定版本的升级历史

    kubectl rollout history deployment nginx-deploy --revision=3

    假如现在要直接回退到当前版本的前一个版本:

    kubectl rollout undo deployment nginx-deploy
    deployment "nginx-deploy" rolled back

    当然也可以用revision回退到指定的版本:

    kubectl rollout undo deployment nginx-deploy --to-revision=2
    deployment "nginx-deploy" rolled back

    现在可以用命令查看Deployment现在的状态了。

    5 k8s滚动更新的原理


    部署(Deployment)自动创建副本集(ReplicaSet),副本集根据参数策略可以精确地控制每次替换的Pod数量,从而可以很好的实现滚动更新。具体来说,k8s每次使用一个新的副本控制器(replication controller)来替换已存在的副本控制器,从而始终使用一个新的Pod模板来替换旧的pod模板。

    大致步骤如下:

    1、创建一个新的replication controller。
    2、增加或减少pod副本数量,直到满足当前批次期望的数量。
    3、删除旧的replication controller。

    5.1 部署概况

    使用命令查看部署概况

    kubectl get deployment


    上图包含的几个滚动发布过程标量,说明如下:

    DESIRED 最终期望处于READY状态的副本数
    CURRENT 当前的副本总数
    UP-TO-DATE 当前完成更新的副本数
    AVAILABLE 当前可用的副本数

    5.2 部署详情

    使用命令查看部署详情

    kubectl describe deployment familytree-api

    从上图可以看到,k8s精确地控制着整个发布过程,滚动进行,直到所有副本全部更新。其实,k8s提供了两个参数maxSurge和maxUnavailable来精确地控制每次滚动的pod数量,如下:

    maxSurge 滚动更新过程中运行操作期望副本数的最大pod数,可以为绝对数值(eg:5),但不能为0;也可以为百分数(eg:10%)。默认为25%。
    maxUnavailable 滚动更新过程中不可用的最大pod数,可以为绝对数值(eg:5),但不能为0;也可以为百分数(eg:10%)。默认为25%。
    如果未指定这两个可选参数,则k8s使用默认配置,如下:

    kubectl get deployment familytree-api -o yaml


    剖析部署helloworldapi的标准输出:

    当前的副本总数 = 3 + 3 * 25% = 4,所以CURRENT为4。

    当前可用的副本数 = 3 - 3 * 25% = 2,所以AVAILABLE为2。

    整个滚动过程是通过控制两个副本集来完成的,新的副本集:familytree-api-c6fbb4499;旧的副本集: familytree-api-66f79b747c 。

    理想状态下的滚动过程:

    创建了一个新的副本集,并为其分配1个新版本的pod,使副本总数达到4,一切正常。
    通知旧副本集,销毁1个旧版本的pod,使可用副本总数保持到2,一起正常。
    当1个副本销毁成功后,通知新副本集,再新增1个新版本的pod,使副本总数达到4,一切正常。

    只要销毁成功,新副本集,就会创造新的pod,一直循环,直到旧的副本集pod数量为0。
    有时整个滚动过程也是不理想的,不符合上述的规律,会有一些混乱。

    k8s最终都会使服务全部更新到期望状态,始终保持最大的副本总数和可用副本总数的不变性

    6 deployment的常用命令和参数说明


    查看部署状态

    kubectl rollout status deployment/review-demo --namespace=scm
    
    kubectl describe deployment/review-demo --namespace=scm


    或者这种写法

    kubectl rollout status deployments review-demo --namespace=scm
    
    kubectl describe deployments review-demo --namespace=scm

    升级

    kubectl set image deployment/review-demo review-demo=library/review-demo:0.0.1 --namespace=scm

    或者

    kubectl edit deployment/review-demo --namespace=scm

    编辑.spec.template.spec.containers[0].image的值

    终止升级

    kubectl rollout pause deployment/review-demo --namespace=scm

    继续升级

    kubectl rollout resume deployment/review-demo --namespace=scm

    回滚

    kubectl rollout undo deployment/review-demo --namespace=scm

    查看deployments版本

    kubectl rollout history deployments --namespace=scm

    回滚到指定版本

    kubectl rollout undo deployment/review-demo --to-revision=2 --namespace=scm

    升级历史

    kubectl describe deployment/review-demo --namespace=scm
    
    Name: review-demo 
    Namespace: scm 
    CreationTimestamp: Tue, 31 Jan 2017 16:42:01 +0800
    Labels: app=review-demo 
    Selector: app=review-demo 
    Replicas: 3 updated | 3 total | 3 available | 0 unavailable 
    StrategyType: RollingUpdate 
    MinReadySeconds: 0 
    RollingUpdateStrategy: 1 max unavailable, 1 max surge 
    OldReplicaSets: <none> 
    NewReplicaSet: review-demo-2741031620 (3/3 replicas created) 
    Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 
    1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set review-demo-2741031620 to 1 
    1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set review-demo-1914295649 to 2 
    1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set review-demo-2741031620 to 2 
    1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set review-demo-1914295649 to 1 
    1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set review-demo-2741031620 to 3
    1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set review-demo-1914295649 to 0

    deployment文件

    apiVersion: extensions/v1beta1 
    kind: Deployment 
    metadata: 
    name: review-demo 
    namespace: scm 
    labels: 
    app: review-demo 
    spec: 
    replicas: 3 # 
    minReadySeconds: 60 #滚动升级时60s后认为该pod就绪 
    strategy: 
    rollingUpdate: ##由于replicas为3,则整个升级,pod个数在2-4个之间 
    maxSurge: 1 #滚动升级时会先启动1个pod 
    maxUnavailable: 1 #滚动升级时允许的最大Unavailable的pod个数 
    template: 
    metadata: 
    labels: 
    app: review-demo 
    spec: terminationGracePeriodSeconds: 60 ##k8s将会给应用发送SIGTERM信号,可以用来正确、优雅地关闭应用,默认为30秒 
    containers: 
    - name: review-demo 
    image: library/review-demo:0.0.1-SNAPSHOT 
    imagePullPolicy: IfNotPresent 
    livenessProbe: #kubernetes认为该pod是存活的,不存活则需要重启 
    httpGet: path: /health 
    port: 8080 
    scheme: HTTP 
    initialDelaySeconds: 60 ## equals to the maximum startup time of the application + couple of seconds 
    timeoutSeconds: 5 
    successThreshold: 1 
    failureThreshold: 5 
    readinessProbe: #kubernetes认为该pod是启动成功的 
    httpGet: path: /health 
    port: 8080 
    scheme: HTTP 
    initialDelaySeconds: 30 ## equals to minimum startup time of the application timeoutSeconds: 5 
    successThreshold: 1 
    failureThreshold: 5 
    resources: # keep request = limit to keep this container in guaranteed class requests: 
    cpu: 50m 
    memory: 200Mi 
    limits: 
    cpu: 500m 
    memory: 500Mi 
    env: 
    - name: PROFILE 
    value: "test" 
    ports: 
    - name: http 
    containerPort: 8080

    几个重要参数说明
    maxSurge与maxUnavailable
    maxSurge: 1 表示滚动升级时会先启动1个pod
    maxUnavailable: 1 表示滚动升级时允许的最大Unavailable的pod个数
    由于replicas为3,则整个升级,pod个数在2-4个之间

    terminationGracePeriodSeconds
    k8s将会给应用发送SIGTERM信号,可以用来正确、优雅地关闭应用,默认为30秒。

    如果需要更优雅地关闭,则可以使用k8s提供的pre-stop lifecycle hook 的配置声明,将会在发送SIGTERM之前执行。

    livenessProbe与readinessProbe
    livenessProbe是kubernetes认为该pod是存活的,不存在则需要kill掉,然后再新启动一个,以达到replicas指定的个数。

    readinessProbe是kubernetes认为该pod是启动成功的,这里根据每个应用的特性,自己去判断,可以执行command,也可以进行httpGet。比如对于使用java web服务的应用来说,并不是简单地说tomcat启动成功就可以对外提供服务的,还需要等待spring容器初始化,数据库连接连接上等等。对于spring boot应用,默认的actuator带有/health接口,可以用来进行启动成功的判断。

    其中readinessProbe.initialDelaySeconds可以设置为系统完全启动起来所需的最少时间,livenessProbe.initialDelaySeconds可以设置为系统完全启动起来所需的最大时间+若干秒。

    这几个参数配置好了之后,基本就可以实现近乎无缝地平滑升级了。对于使用服务发现的应用来说,readinessProbe可以去执行命令,去查看是否在服务发现里头应该注册成功了,才算成功。


    参考:
    原文链接:https://blog.csdn.net/zzq900503/article/details/101221899

  • 相关阅读:
    初步掌握HBase
    基于HBase0.98.13搭建HBase HA分布式集群
    获取当前目录中的文件个数
    MapReduce链接作业
    MapReduce二次排序
    使用map端连接结合分布式缓存机制实现Join算法
    字符串匹配算法-BM
    统计电视机顶盒中无效用户数据,并以压缩格式输出有效用户数据
    字符串匹配算法-KMP
    MapReduce中的Join算法
  • 原文地址:https://www.cnblogs.com/sandshell/p/11719996.html
Copyright © 2020-2023  润新知