• 服务滚动升级
    • ReplicationController与Deployment的关系
      • ReplicationController
      • Deployment
    • 创建测试镜像
    • 测试
    • 使用ReplicationController创建的Pod如何RollingUpdate
    • 参考

    服务滚动升级

    当有镜像发布新版本,新版本服务上线时如何实现服务的滚动和平滑升级?

    如果你使用ReplicationController创建的pod可以使用kubectl rollingupdate命令滚动升级,如果使用的是Deployment创建的Pod可以直接修改yaml文件后执行kubectl apply即可。

    Deployment已经内置了RollingUpdate strategy,因此不用再调用kubectl rollingupdate命令,升级的过程是先创建新版的pod将流量导入到新pod上后销毁原来的旧的pod。

    Rolling Update适用于DeploymentReplication Controller,官方推荐使用Deployment而不再使用Replication Controller。

    使用ReplicationController时的滚动升级请参考官网说明:https://kubernetes.io/docs/tasks/run-application/rolling-update-replication-controller/

    ReplicationController与Deployment的关系

    ReplicationController和Deployment的RollingUpdate命令有些不同,但是实现的机制是一样的,关于这两个kind的关系我引用了ReplicationController与Deployment的区别中的部分内容如下,详细区别请查看原文。

    ReplicationController

    Replication Controller为Kubernetes的一个核心内容,应用托管到Kubernetes之后,需要保证应用能够持续的运行,Replication Controller就是这个保证的key,主要的功能如下:

    • 确保pod数量:它会确保Kubernetes中有指定数量的Pod在运行。如果少于指定数量的pod,Replication Controller会创建新的,反之则会删除掉多余的以保证Pod数量不变。
    • 确保pod健康:当pod不健康,运行出错或者无法提供服务时,Replication Controller也会杀死不健康的pod,重新创建新的。
    • 弹性伸缩 :在业务高峰或者低峰期的时候,可以通过Replication Controller动态的调整pod的数量来提高资源的利用率。同时,配置相应的监控功能(Hroizontal Pod Autoscaler),会定时自动从监控平台获取Replication Controller关联pod的整体资源使用情况,做到自动伸缩。
    • 滚动升级:滚动升级为一种平滑的升级方式,通过逐步替换的策略,保证整体系统的稳定,在初始化升级的时候就可以及时发现和解决问题,避免问题不断扩大。

    Deployment

    Deployment同样为Kubernetes的一个核心内容,主要职责同样是为了保证pod的数量和健康,90%的功能与Replication Controller完全一样,可以看做新一代的Replication Controller。但是,它又具备了Replication Controller之外的新特性:

    • Replication Controller全部功能:Deployment继承了上面描述的Replication Controller全部功能。
    • 事件和状态查看:可以查看Deployment的升级详细进度和状态。
    • 回滚:当升级pod镜像或者相关参数的时候发现问题,可以使用回滚操作回滚到上一个稳定的版本或者指定的版本。
    • 版本记录: 每一次对Deployment的操作,都能保存下来,给予后续可能的回滚使用。
    • 暂停和启动:对于每一次升级,都能够随时暂停和启动。
    • 多种升级方案:Recreate:删除所有已存在的pod,重新创建新的; RollingUpdate:滚动升级,逐步替换的策略,同时滚动升级时,支持更多的附加参数,例如设置最大不可用pod数量,最小升级间隔时间等等。

    创建测试镜像

    我们来创建一个特别简单的web服务,当你访问网页时,将输出一句版本信息。通过区分这句版本信息输出我们就可以断定升级是否完成。

    所有配置和代码见../manifests/test/rolling-update-test目录。

    Web服务的代码main.go

    1. package main
    2. import (
    3. "fmt"
    4. "log"
    5. "net/http"
    6. )
    7. func sayhello(w http.ResponseWriter, r *http.Request) {
    8. fmt.Fprintf(w, "This is version 1.") //这个写入到w的是输出到客户端的
    9. }
    10. func main() {
    11. http.HandleFunc("/", sayhello) //设置访问的路由
    12. log.Println("This is version 1.")
    13. err := http.ListenAndServe(":9090", nil) //设置监听的端口
    14. if err != nil {
    15. log.Fatal("ListenAndServe: ", err)
    16. }
    17. }

    创建Dockerfile

    1. FROM alpine:3.5
    2. MAINTAINER Jimmy Song<rootsongjc@gmail.com>
    3. ADD hellov2 /
    4. ENTRYPOINT ["/hellov2"]

    注意修改添加的文件的名称。

    创建Makefile

    修改镜像仓库的地址为你自己的私有镜像仓库地址。

    修改Makefile中的TAG为新的版本号。

    1. all: build push clean
    2. .PHONY: build push clean
    3. TAG = v1
    4. # Build for linux amd64
    5. build:
    6. GOOS=linux GOARCH=amd64 go build -o hello${TAG} main.go
    7. docker build -t sz-pg-oam-docker-hub-001.tendcloud.com/library/hello:${TAG} .
    8. # Push to tenxcloud
    9. push:
    10. docker push sz-pg-oam-docker-hub-001.tendcloud.com/library/hello:${TAG}
    11. # Clean
    12. clean:
    13. rm -f hello${TAG}

    编译

    1. make all

    分别修改main.go中的输出语句、Dockerfile中的文件名称和Makefile中的TAG,创建两个版本的镜像。

    测试

    我们使用Deployment部署服务来测试。

    配置文件rolling-update-test.yaml

    1. apiVersion: extensions/v1beta1
    2. kind: Deployment
    3. metadata:
    4. name: rolling-update-test
    5. spec:
    6. replicas: 3
    7. template:
    8. metadata:
    9. labels:
    10. app: rolling-update-test
    11. spec:
    12. containers:
    13. - name: rolling-update-test
    14. image: sz-pg-oam-docker-hub-001.tendcloud.com/library/hello:v1
    15. ports:
    16. - containerPort: 9090
    17. ---
    18. apiVersion: v1
    19. kind: Service
    20. metadata:
    21. name: rolling-update-test
    22. labels:
    23. app: rolling-update-test
    24. spec:
    25. ports:
    26. - port: 9090
    27. protocol: TCP
    28. name: http
    29. selector:
    30. app: rolling-update-test

    部署service

    1. kubectl create -f rolling-update-test.yaml

    修改traefik ingress配置

    ingress.yaml文件中增加新service的配置。

    1. - host: rolling-update-test.traefik.io
    2. http:
    3. paths:
    4. - path: /
    5. backend:
    6. serviceName: rolling-update-test
    7. servicePort: 9090

    修改本地的host配置,增加一条配置:

    1. 172.20.0.119 rolling-update-test.traefik.io

    注意:172.20.0.119是我们之前使用keepalived创建的VIP。

    打开浏览器访问http://rolling-update-test.traefik.io将会看到以下输出:

    1. This is version 1.

    滚动升级

    只需要将rolling-update-test.yaml文件中的image改成新版本的镜像名,然后执行:

    1. kubectl apply -f rolling-update-test.yaml

    也可以参考Kubernetes Deployment Concept中的方法,直接设置新的镜像。

    1. kubectl set image deployment/rolling-update-test rolling-update-test=sz-pg-oam-docker-hub-001.tendcloud.com/library/hello:v2

    或者使用kubectl edit deployment/rolling-update-test修改镜像名称后保存。

    使用以下命令查看升级进度:

    1. kubectl rollout status deployment/rolling-update-test

    升级完成后在浏览器中刷新http://rolling-update-test.traefik.io将会看到以下输出:

    1. This is version 2.

    说明滚动升级成功。

    使用ReplicationController创建的Pod如何RollingUpdate

    以上讲解使用Deployment创建的Pod的RollingUpdate方式,那么如果使用传统的ReplicationController创建的Pod如何Update呢?

    举个例子:

    1. $ kubectl -n spark-cluster rolling-update zeppelin-controller --image sz-pg-oam-docker-hub-001.tendcloud.com/library/zeppelin:0.7.1
    2. Created zeppelin-controller-99be89dbbe5cd5b8d6feab8f57a04a8b
    3. Scaling up zeppelin-controller-99be89dbbe5cd5b8d6feab8f57a04a8b from 0 to 1, scaling down zeppelin-controller from 1 to 0 (keep 1 pods available, don't exceed 2 pods)
    4. Scaling zeppelin-controller-99be89dbbe5cd5b8d6feab8f57a04a8b up to 1
    5. Scaling zeppelin-controller down to 0
    6. Update succeeded. Deleting old controller: zeppelin-controller
    7. Renaming zeppelin-controller-99be89dbbe5cd5b8d6feab8f57a04a8b to zeppelin-controller
    8. replicationcontroller "zeppelin-controller" rolling updated

    只需要指定新的镜像即可,当然你可以配置RollingUpdate的策略。

    参考

    Rolling update机制解析

    Running a Stateless Application Using a Deployment

    Simple Rolling Update

    使用kubernetes的deployment进行RollingUpdate