概述

本文核心问题是:如何升级应用。

对于Pod的更新有两种策略:

  • 一是删除全部旧Pod之后再创建新Pod。好处是,同一时间只会有一个版本的应用存在;缺点是,应用有一段时间不可用。
  • 二是先创建新Pod,再删除旧Pod。可以一次性创建全部,再删除全部,也可以逐渐创建删除。好处是应用一直可用,缺点是要同时支持两个版本。

蓝绿部署

对于应用的版本v1和版本v2:

  • 在运行v1前,流量一直都在v2上
  • 部署v1,然后测试通过后,将流量切换到v2,v2就成为了新的生产环境
  • 一旦v2出现问题,可以在切回v1

金丝雀部署(也称灰度部署)

金丝雀部署一种增量发布,先是在小范围内发布,然后观察测试,如无问题逐渐发布全部。

kubectl rolling-update

因为kubectl rolling-update的方式已经过时,所以只是做一下简介。

假设现在有一个名为test-v1,Pod选择器为app=order的ReplicationController要升级为test-v2,则执行下面命令可升级:

k rolling-update test-v1 test-v2 --image=test:v2

运行此命令后:

  1. 立刻创建一个名为test-v2的ReplicationController,他的Pod模板镜像正是test:v2,并添加一个标签deployment=xxxx
  2. test-v1以及app=order选中的Pod都会被加上一个标签:deployment=yyyy。如此做法是防止Pod的管理混乱。
  3. 先将test-v2的Pod扩展为1,使用更新后的模板创建新Pod;再将test-v1缩小1,如此循环。
  4. 因为在滚动过程中Service的标签选择器一直是app=order,所以新老版本都会接收到流量。

过时的原因是:伸缩的请求时由kubectl发起的,如果因为任何原因丢失了网络连接,升级将处于中间状态。另一个原因是:期望只修改Pod定义中的镜像tag,就能时Kubernetes运行升级工作

使用Deployment声明式的升级

Deployment是一种更高阶的资源,用于部署程序并以声明的方式升级应用,而不是通过ReplicationController或ReplicaSet进行部署。

在使用Deployment时,Pod是由Deployment的ReplicaSet创建的。

准备镜像

将之前的文章(Kubernetes学习笔记(四):服务)里的拿过来做一下微小的改动,生成两个镜像。改动内容就是在输出内容加上版本号。

fmt.Fprintf(w,"this is v1, hostname: %v\n",hostname)
docker push registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v1 fmt.Fprintf(w,"this is v2, hostname: %v\n",hostname)
docker push registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v2

创建Deployment

Deployment与ReplicaSet的配置相似,都含有标签选择器、副本数量和Pod模板。此外Deployment还会包含一个部署策略。

定义Service

定义了一个NodePort类型的Service

# goweb-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: goweb
spec:
type: NodePort
selector:
app: goweb
ports:
- port: 80
targetPort: 8000
nodePort: 31234

定义Deployment

# goweb-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: goweb
spec:
replicas: 3
selector:
matchLabels:
app: goweb
template:
metadata:
labels:
app: goweb
spec:
containers:
- name: goweb
image: registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v1

运行查看

可以看到名为goweb-fdfcfdcc6的RS,有个label是pod-template-hash=fdfcfdcc6,顾名思义,fdfcfdcc6就是pod模板的hash值。

创建Deployment时指定 --record 记录历史版本号,非常有用

-> [root@kube0.vm] [~] k create -f goweb-svc.yaml
service/goweb created -> [root@kube0.vm] [~] k create -f goweb-deployment.yaml --record deployment.apps/goweb created
-> [root@kube0.vm] [~] k get all -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/goweb-fdfcfdcc6-4wklw 1/1 Running 0 9s 10.244.2.37 kube2.vm <none> <none>
pod/goweb-fdfcfdcc6-bw8c4 1/1 Running 0 9s 10.244.2.36 kube2.vm <none> <none>
pod/goweb-fdfcfdcc6-xjcwf 1/1 Running 0 9s 10.244.1.33 kube1.vm <none> <none> NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/goweb NodePort 10.100.193.94 <none> 80:31234/TCP 28s app=goweb
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 54s <none> NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/goweb 3/3 3 3 9s goweb registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v1 app=goweb NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
replicaset.apps/goweb-fdfcfdcc6 3 3 3 9s goweb registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v1 app=goweb,pod-template-hash=fdfcfdcc6

升级Deployment

只要修改Deployment的Pod模板定义,Kubernetes会自动的将实际状态收敛为修改后的状态。对于升级,只需要修改Pod中镜像的tag。

升级策略由deployment.spec.strategy.type定义,值是Recreate或RollingUpdate,默认RollingUpdate。

kubectl patch及minReadySeconds

使用kubectl patch定义deployment.spec.minReadySeconds来减慢滚动升级时间,以便观察升级过程

-> [root@kube0.vm] [~] k patch deployment goweb -p '{"spec":{"minReadySeconds":5}}'
deployment.apps/goweb patched

循环请求服务

在执行升级前新开窗口,运行下面的命令查看输出

-> [root@kube0.vm] [~] while true; do curl http://192.168.199.231:31234/ ; sleep 1; done
this is v1, hostname: goweb-fdfcfdcc6-pw7b4
this is v1, hostname: goweb-fdfcfdcc6-pw7b4
this is v1, hostname: goweb-fdfcfdcc6-x8n7h
this is v1, hostname: goweb-fdfcfdcc6-pw7b4
this is v1, hostname: goweb-fdfcfdcc6-x8n7h
this is v1, hostname: goweb-fdfcfdcc6-j4mz8
this is v1, hostname: goweb-fdfcfdcc6-j4mz8
# 以上是升级之前的输出、以下是开始升级后的
this is v1, hostname: goweb-fdfcfdcc6-x8n7h
this is v1, hostname: goweb-fdfcfdcc6-pw7b4
this is v1, hostname: goweb-fdfcfdcc6-pw7b4
this is v1, hostname: goweb-fdfcfdcc6-j4mz8
this is v2, hostname: goweb-65cc575865-25988
this is v2, hostname: goweb-65cc575865-25988
this is v1, hostname: goweb-fdfcfdcc6-x8n7h
this is v1, hostname: goweb-fdfcfdcc6-j4mz8
this is v2, hostname: goweb-65cc575865-bfd98
this is v2, hostname: goweb-65cc575865-bfd98
this is v2, hostname: goweb-65cc575865-25988
this is v2, hostname: goweb-65cc575865-25988
this is v2, hostname: goweb-65cc575865-25988
# 这之后就是升级完成了

kubectl set

使用 kubectl set image 更新任何包含容器资源的镜像。

-> [root@kube0.vm] [~] k set image deployment goweb goweb=registry.cn-hangzhou.aliyuncs.com/orzi/goweb:v2
deployment.apps/goweb image updated

kubectl rollout

查看升级状态信息。执行完kubectl set image,立刻执行下面的命令。手速得快,不然赶不上热乎的。

-> [root@kube0.vm] [~] k rollout status deployment goweb
Waiting for deployment "goweb" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "goweb" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "goweb" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "goweb" rollout to finish: 1 old replicas are pending termination...
deployment "goweb" successfully rolled out

修改Deployment或其他资源的方式

方法 作用
kubectl edit 使用编辑器打开资源配置
kubectl patch 在命令行以merge的方式修改配置
kubectl apply 通过yaml或者json文件,修改新改动的值。如果指定的对象不存在则创建。
kubectl replace 使用yaml或者json文件替换一个必须已存在的对象配置。
kubectl set image 修改镜像

回滚

使用kubectl rollout undo 回滚到上一个版本

-> [root@kube0.vm] [~] k rollout undo deployment goweb
deployment.apps/goweb rolled back

使用 kubectl rollout history 查看版本记录

-> [root@kube0.vm] [~] k rollout history deployment goweb
deployment.apps/goweb
REVISION CHANGE-CAUSE
6 kubectl create --filename=goweb-deployment.yaml --record=true
7 kubectl create --filename=goweb-deployment.yaml --record=true

回滚到特定版本

-> [root@kube0.vm] [~] k rollout undo deployment goweb --to-revision=5
error: unable to find specified revision 5 in history -> [root@kube0.vm] [~] k rollout undo deployment goweb --to-revision=7
deployment.apps/goweb skipped rollback (current template already matches revision 7) -> [root@kube0.vm] [~] k rollout undo deployment goweb --to-revision=6
deployment.apps/goweb rolled back

通过deployment.spec.revisionHistoryLimit指定历史版本个数,默认为2。也就是当前和上一个版本。

控制滚动升级速率

deployment.spec.strategy.rollingUpdate下有两个字段,用来控制升级速率

  • maxSurge:超出期望副本数的Pod实例的比例或个数。默认25%,转换成绝对值后四舍五入,也可以直接指定为绝对值。
  • maxUnavailable:滚动升级时,最多允许有多少实例不可用,默认25%,转换成绝对值后四舍五入,也可以直接指定为绝对值。

暂停、恢复升级

  • 使用kubectl rollout pause暂停升级
  • 使用kubectl rollout resume取消暂停

阻止出错版本的滚动升级

  • minReadySeconds:指定新创建的Pod至少要运行多久才视为可用。
  • 配置就绪探针
  • 为滚动升级配置progressDeadlineSeconds

小结

  • kubectl rolling-update 过时的原因:伸缩的请求时由kubectl发起的,如果因为任何原因丢失了网络连接,升级将处于中间状态
  • Deployment是一种更高阶的资源,用于部署程序并以声明的方式升级应用,而不是通过ReplicationController或ReplicaSet进行部署。
  • 创建Deployment时指定 --record 记录历史版本号
  • Deployment下的ReplicaSet命名是DeploymentName+Pod模板Hash,而ReplicaSet下的Pod是在此基础拼接个随机字符串。
  • 升级策略由deployment.spec.strategy.type定义,值是Recreate或RollingUpdate,默认RollingUpdate。
  • 定义deployment.spec.minReadySeconds来减慢滚动升级时间
  • maxSurge与maxUnavailable控制滚动升级速率
  • 命令:patch、set、rollout
  • kubectl rollout:status、undo、pause、resume、history。

Kubernetes学习笔记(八):Deployment--声明式的升级应用的更多相关文章

  1. k8s之Deployment 声明式地升级应用(五)

    Deployment 声明式地升级应用 现在你已经知道如何将应用程序组件打包进容器,将他们分组到pod中,并为它们提供临时或者持久存储,将密钥或配置文件注入,并可以使pod之间互相通信.这就是微服务化 ...

  2. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring声明式事务管理(基于Annotation注解方式实现)

    在 Spring 中,除了使用基于 XML 的方式可以实现声明式事务管理以外,还可以通过 Annotation 注解的方式实现声明式事务管理. 使用 Annotation 的方式非常简单,只需要在项目 ...

  3. Struts2学习第八课 声明式异常处理

    异常处理:exception-mapping元素 exception-mapping元素:配置当前的action的声明式异常处理 exception-mapping元素有两个属性: --excepti ...

  4. deployment:声明式的升级应用

    9.1.使用RC实现滚动升级 #kubectl rolling-update kubia-v1 kubia-v2 --image=luksa/kubia:v2 使用kubia-v2版本应用来替换运行着 ...

  5. Kubernetes 学习笔记(一):基础概念

    个人笔记,仅本人查阅使用,不保证正确. 零.微服务 微服务架构专注于应用解耦合,通过将应用彻底地组件化和服务化,每个微服务只包含一个非常小的功能,比如权限管理.日志收集等等.由这一组微服务组合起来,提 ...

  6. Learning ROS forRobotics Programming Second Edition学习笔记(八)indigo rviz gazebo

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS forRobotics Pro ...

  7. python3.4学习笔记(八) Python第三方库安装与使用,包管理工具解惑

    python3.4学习笔记(八) Python第三方库安装与使用,包管理工具解惑 许多人在安装Python第三方库的时候, 经常会为一个问题困扰:到底应该下载什么格式的文件?当我们点开下载页时, 一般 ...

  8. Go语言学习笔记八: 数组

    Go语言学习笔记八: 数组 数组地球人都知道.所以只说说Go语言的特殊(奇葩)写法. 我一直在想一个人参与了两种语言的设计,但是最后两种语言的语法差异这么大.这是自己否定自己么,为什么不与之前统一一下 ...

  9. 【opencv学习笔记八】创建TrackBar轨迹条

    createTrackbar这个函数我们以后会经常用到,它创建一个可以调整数值的轨迹条,并将轨迹条附加到指定的窗口上,使用起来很方便.首先大家要记住,它往往会和一个回调函数配合起来使用.先看下他的函数 ...

随机推荐

  1. Linked List-3

    第一篇终结Linked List(一).终结Linked List(二)主要讲了单链表的基础知识,接下来的第二篇主要讲一些比较经典的问题. 一.Count() 给一个单链表和一个整数,返回这个整数在链 ...

  2. JSbridge 在Vue的封装与交互

    原文转自: 点我 写在 JSbridge.js let isAndroid = navigator.userAgent.indexOf('Android') > -1 || navigator. ...

  3. muduo网络库源码学习————线程池实现

    muduo库里面的线程池是固定线程池,即创建的线程池里面的线程个数是一定的,不是动态的.线程池里面一般要包含线程队列还有任务队列,外部程序将任务存放到线程池的任务队列中,线程池中的线程队列执行任务,也 ...

  4. 最长公共子串(Longest common substring)

    问题描述: 给定两个序列 X=<x1, x2, ..., xm>, Y<y1, y2, ..., yn>,求X和Y长度最长的公共子串.(子串中的字符要求连续) 这道题和最长公共 ...

  5. Java笔记(day23-day26)

     IO流1,复制一个文本文件. 1,明确体系:        源:InputStream ,Reader        目的:OutputStream ,Writer    2,明确数据:       ...

  6. spring学习笔记(三)我对AOP理解

    首先我们要知道AOP是什么?AOP全称Aspect OrientedProgramming,即面向切面编程.在这里我不想去说什么是切面,什么是切点,什么是通知等等,相关博客很多,如果大家想知道可以自己 ...

  7. Qt之分模块log

    说明 对于一般的log,使用 qInstallMessageHandler 重定向到文件即可,甚至可以根据日志等级,分类存储.但是并不是适用所有情况,比如,程序运行时动态创建模块,而每个模块需要创建不 ...

  8. 【Spark】不熟悉Spark-shell常用参数?这一张图就够了

  9. Linux dts 设备树详解(二) 动手编写设备树dts

    Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 前言 硬件结构 设备树dts文件 前言 在简单了解概念之后,我们可以开始尝试写一个 ...

  10. uCOS2014.1.11

    typedef unsigned char  BOOLEAN;typedef unsigned char  INT8U;      /* Unsigned  8 bit quantity   */ty ...