一、灰度发布

  灰度发布是一种发布方式,也叫金丝雀发布,起源是矿工在下井之前会先放一只金丝雀到井里,如果金丝雀不叫了,就代表瓦斯浓度高。原因是金丝雀对瓦斯气体很敏感。灰度发布的做法是:会在现存旧应用的基础上,启动一个新版应用,但是新版应用并不会直接让用户访问。而是先让测试同学去进行测试。如果没有问题,则可以将真正的用户流量慢慢导入到新版,在这中间,持续对新版本运行状态做观察,直到慢慢切换过去,这就是所谓的A/B测试。当然,你也可以招募一些灰度用户,给他们设置独有的灰度标示(Cookie,Header),来让他们可以访问到新版应用,当然,如果中间切换出现问题,也应该将流量迅速地切换到老应用上。

1)准备新版本的service

  拷贝一份deployment文件:

cp deployment-user-v1.yaml deployment-user-v2.yaml

  修改之前写过的内容:

apiVersion: apps/v1  #API 配置版本
kind: Deployment #资源类型
metadata:
+ name: user-v2 #资源名称
spec:
selector:
matchLabels:
+ app: user-v2 #告诉deployment根据规则匹配相应的Pod进行控制和管理,matchLabels字段匹配Pod的label值
replicas: 3 #声明一个 Pod,副本的数量
template:
metadata:
labels:
+ app: user-v2 #Pod的名称
spec: #组内创建的 Pod 信息
containers:
- name: nginx #容器的名称
+ image: registry.cn-beijing.aliyuncs.com/zhangrenyang/nginx:user-v2
ports:
- containerPort: 80 #容器内映射的端口

  然后service的文件内容是这样的:

apiVersion: v1
kind: Service
metadata:
+ name: service-user-v2
spec:
selector:
+ app: user-v2
ports:
- protocol: TCP
port: 80
targetPort: 80
type: NodePort

  启动:

kubectl apply -f deployment-user-v2.yaml service-user-v2.yaml

2)根据cookie切分流量

  基于 Cookie 切分流量。这种实现原理主要根据用户请求中的 Cookie 是否存在灰度标示 Cookie去判断是否为灰度用户,再决定是否返回灰度版本服务

  • nginx.ingress.kubernetes.io/canary:可选值为 true / false 。代表是否开启灰度功能
  • nginx.ingress.kubernetes.io/canary-by-cookie:灰度发布 cookie 的 key。当 key 值等于 always 时,灰度触发生效。等于其他值时,则不会走灰度环境 ingress-gray.yaml

  我们创建一个ingress-gray.yaml文件:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: user-canary
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "vip_user"
spec:
rules:
- http:
paths:
- backend:
serviceName: service-user-v2
servicePort: 80
backend:
serviceName: service-user-v2
servicePort: 80

  使文件生效:

kubectl apply -f ./ingress-gray.yaml 

  获取外部接口:

kubectl -n ingress-nginx get svc

  测试:

curl http://172.31.178.169:31234/user
curl http://118.190.156.138:31234/user
curl --cookie "vip_user=always" http://172.31.178.169:31234/user

3)基于header切分流量

  基于 Header 切分流量,这种实现原理主要根据用户请求中的 header 是否存在灰度标示 header去判断是否为灰度用户,再决定是否返回灰度版本服务。

  修改下上面的ingress-gray.yml文件即可:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: user-canary
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/canary: "true"
+ nginx.ingress.kubernetes.io/canary-by-header: "name"
+ nginx.ingress.kubernetes.io/canary-by-header-value: "vip"
spec:
rules:
- http:
paths:
- backend:
serviceName: service-user-v2
servicePort: 80
backend:
serviceName: service-user-v2
servicePort: 80

  同样的:

kubectl apply -f ingress-gray.yaml
curl --header "name:vip" http://172.31.178.169:31234/user

4)基于权重切分流量

  这种实现原理主要是根据用户请求,通过根据灰度百分比决定是否转发到灰度服务环境中

  • nginx.ingress.kubernetes.io/canary-weight:值是字符串,为 0-100 的数字,代表灰度环境命中概率。如果值为 0,则表示不会走灰度。值越大命中概率越大。当值 = 100 时,代表全走灰度。

  一样一样的,修改下配置参数罢了:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: user-canary
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/canary: "true"
+ nginx.ingress.kubernetes.io/canary-weight: "50"
spec:
rules:
- http:
paths:
- backend:
serviceName: service-user-v2
servicePort: 80
backend:
serviceName: service-user-v2
servicePort: 80

  测试下:

kubectl apply -f ingress-gray.yaml
for ((i=1; i<=10; i++)); do curl http://172.31.178.169:31234/user; done

  k8s 会优先去匹配 header ,如果未匹配则去匹配 cookie ,最后是 weight。

二、滚动发布

  滚动发布,则是我们一般所说的无宕机发布。其发布方式如同名称一样,一次取出一台/多台服务器(看策略配置)进行新版本更新。当取出的服务器新版确保无问题后,接着采用同等方式更新后面的服务器。k8s创建副本应用程序的最佳方法就是部署(Deployment),部署自动创建副本集(ReplicaSet),副本集可以精确地控制每次替换的Pod数量,从而可以很好的实现滚动更新。k8s每次使用一个新的副本控制器(replication controller)来替换已存在的副本控制器,从而始终使用一个新的Pod模板来替换旧的pod模板

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

  滚动发布的优缺点如下:

  • 优点

    • 不需要停机更新,无感知平滑更新。
    • 版本更新成本小,不需要新旧版本共存
  • 缺点
    • 更新时间长:每次只更新一个/多个镜像,需要频繁连续等待服务启动缓冲
    • 旧版本环境无法得到备份:始终只有一个环境存在
    • 回滚版本异常痛苦:如果滚动发布到一半出了问题,回滚时需要使用同样的滚动策略回滚旧版本

  我们下面来尝试下,先扩容为10个副本:

kubectl get deploy
kubectl scale deployment user-v1 --replicas=10

  修改deployment-user-v1.yaml文件:

apiVersion: apps/v1  #API 配置版本
kind: Deployment #资源类型
metadata:
name: user-v1 #资源名称
spec:
minReadySeconds: 1
+ strategy:
+ type: RollingUpdate
+ rollingUpdate:
+ maxSurge: 1
+ maxUnavailable: 0
+ selector:
+ matchLabels:
+ app: user-v1 #告诉deployment根据规则匹配相应的Pod进行控制和管理,matchLabels字段匹配Pod的label值
replicas: 10 #声明一个 Pod,副本的数量
template:
metadata:
labels:
app: user-v1 #Pod的名称
spec: #组内创建的 Pod 信息
containers:
- name: nginx #容器的名称
+ image: registry.cn-beijing.aliyuncs.com/zhangrenyang/nginx:user-v3 #使用哪个镜像
ports:
- containerPort: 80 #容器内映射的端口
参数 含义
minReadySeconds 容器接受流量延缓时间:单位为秒,默认为0。如果没有设置的话,k8s会认为容器启动成功后就可以用了。设置该值可以延缓容器流量切分
strategy.type = RollingUpdate ReplicaSet 发布类型,声明为滚动发布,默认也为滚动发布
strategy.rollingUpdate.maxSurge 最多Pod数量:为数字类型/百分比。如果 maxSurge 设置为1,replicas 设置为10,则在发布过程中pod数量最多为10 + 1个(多出来的为旧版本pod,平滑期不可用状态)。maxUnavailable 为 0 时,该值也不能设置为0
strategy.rollingUpdate.maxUnavailable 升级中最多不可用pod的数量:为数字类型/百分比。当 maxSurge 为 0 时,该值也不能设置为0

  启动:

kubectl apply -f ./deployment-user-v1.yaml
deployment.apps/user-v1 configured

  然后查看状态:

kubectl rollout status deployment/user-v1

三、服务可用性探针

  当 Pod 的状态为 Running 时,该 Pod 就可以被分配流量(可以访问到)了。一个后端容器启动成功,不一定不代表服务启动成功。

3.2.1 存活探针 LivenessProbe

  第一种是存活探针。存活探针是对运行中的容器检测的。如果想检测你的服务在运行中有没有发生崩溃,服务有没有中途退出或无响应,可以使用这个探针。如果探针探测到错误, Kubernetes 就会杀掉这个 Pod;否则就不会进行处理。如果默认没有配置这个探针, Pod 不会被杀死。

3.2.2 可用探针 ReadinessProbe

  第二种是可用探针。作用是用来检测 Pod 是否允许被访问到(是否准备好接受流量)。如果你的服务加载很多数据,或者有其他需求要求在特定情况下不被分配到流量,那么可以用这个探针。如果探针检测失败,流量就不会分配给该 Pod。在没有配置该探针的情况下,会一直将流量分配给 Pod。当然,探针检测失败,Pod 不会被杀死。

3.2.3 启动探针 StartupProbe

  第三种是启动探针。作用是用来检测 Pod 是否已经启动成功。如果你的服务启动需要一些加载时长(例如初始化日志,等待其他调用的服务启动成功)才代表服务启动成功,则可以用这个探针。如果探针检测失败,该 Pod 就会被杀死重启。在没有配置该探针的情况下,默认不会杀死 Pod 。在启动探针运行时,其他所有的探针检测都会失效。

探针名称 在哪个环节触发 作用 检测失败对Pod的反应
启动探针 Pod 运行时 检测服务是否启动成功 杀死 Pod 并重启
存活探针 Pod 运行时 检测服务是否崩溃,是否需要重启服务 杀死 Pod 并重启
可用探针 Pod 运行时 检测服务是不是允许被访问到 停止Pod的访问调度,不会被杀死重启

检测方式

1、ExecAction

  通过在 Pod 的容器内执行预定的 Shell 脚本命令。如果执行的命令没有报错退出(返回值为0),代表容器状态健康。否则就是有问题的

  我们来新建一个文件,vi shell-probe.yaml,内容如下:

apiVersion: v1
kind: Pod
metadata:
labels:
test: shell-probe
name: shell-probe
spec:
containers:
- name: shell-probe
image: registry.aliyuncs.com/google_containers/busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5

  然后执行下面的命令,查看情况:

kubectl apply -f liveness.yaml
kubectl get pods | grep liveness-exec
kubectl describe pods liveness-exec

2、TCPSocketAction

  这种方式是使用 TCP 套接字检测。 Kubernetes 会尝试在 Pod 内与指定的端口进行连接。如果能建立连接(Pod的端口打开了),这个容器就代表是健康的,如果不能,则代表这个 Pod 就是有问题的。

  创建文件如下,tcp-probe.yaml:

apiVersion: v1
kind: Pod
metadata:
name: tcp-probe
labels:
app: tcp-probe
spec:
containers:
- name: tcp-probe
image: nginx
ports:
- containerPort: 80
readinessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 5
periodSeconds: 10

  类似的:

kubectl apply -f tcp-probe.yaml
kubectl get pods | grep tcp-probe
kubectl describe pods tcp-probe

  进入到容器内部:

kubectl exec -it tcp-probe  -- /bin/sh

  更新apt-get并安装vim:

apt-get update
apt-get install vim -y
vi /etc/nginx/conf.d/default.conf

  修改nginx文件配置,把80端口修改为8080,然后重载一下nginx:

nginx -s reload

  看一下状态:

kubectl describe pod tcp-probe

3、HTTPGetAction

  这种方式是使用 HTTP GET 请求。Kubernetes 会尝试访问 Pod 内指定的API路径。如果返回200,代表容器就是健康的。如果不能,代表这个 Pod 是有问题的。

  添加http-probe.yaml文件:

apiVersion: v1
kind: Pod
metadata:
labels:
test: http-probe
name: http-probe
spec:
containers:
- name: http-probe
image: registry.cn-beijing.aliyuncs.com/zhangrenyang/http-probe:1.0.0
livenessProbe:
httpGet:
path: /liveness
port: 80
httpHeaders:
- name: source
value: probe
initialDelaySeconds: 3
periodSeconds: 3

  然后,运行并查看状态:

kubectl apply -f ./http-probe.yaml
kubectl describe pods http-probe
kubectl replace --force -f http-probe.yaml

  Dockerfile内容如下:

FROM node
COPY ./app /app
WORKDIR /app
EXPOSE 3000
CMD node index.js

  node服务文件如下:

let http = require('http');
let start = Date.now();
http.createServer(function(req,res){
if(req.url === '/liveness'){
let value = req.headers['source'];
if(value === 'probe'){
let duration = Date.now()-start;
if(duration>10*1000){
res.statusCode=500;
res.end('error');
}else{
res.statusCode=200;
res.end('success');
}
}else{
res.statusCode=200;
res.end('liveness');
}
}else{
res.statusCode=200;
res.end('liveness');
}
}).listen(3000,function(){console.log("http server started on 3000")});

  好了今天的内容就到这里了。

《前端运维》五、k8s--3灰度发布、滚动更新与探针的更多相关文章

  1. 【运维工具】Git代码发布系统

    引言 代码发布系统是互联网公司必备的运维系统,作用主要用户发布业务代码 到 业务服务器 为什么需要代码发布系统 有的同学可能说,我们公司服务器就那么一台,做个发布系统太麻烦了? 不认同这说法 发布系统 ...

  2. k8s实现灰度发布

    灰度发布在实际生产部署中是经常被使用的方式,常规的方法是手动从前端LB(负载均衡)上将后端服务器摘掉,然后,停服务,最后上传代码,完成软连接更新.在使用CI/CD工具时,这个过程变得自动化了,我们只需 ...

  3. Windows运维之Windows8.1-KB2999226-x64安装提示 此更新不适用你的计算机

    摘要:本文主要向大家介绍了Windows运维之Windows8.1-KB2999226-x64安装提示 此更新不适用你的计算机,通过具体的内容向大家展现,希望对大家学习Windows运维有所帮助. 本 ...

  4. Linux运维五:定时任务crond服务

    一.crond简介 crond是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动cro ...

  5. 真正云原生的智能运维体系,阿里云发布ECS自动化运维套件

    云计算的发展,推动了自动化运维.DevOps.AIOps 等趋势的兴起,在业务快速变化的今天,企业希望通过一套自动化运维的专家系统提高运维效率,为业务提供支撑. 传统的方式下,打造一套成熟的 DevO ...

  6. docker swarm实现java项目的发布/滚动更新/回滚/镜像管理

    使用docker swarm滚动更新java项目,部署集群,这一切的前提是使用Jenkins+maven进行项目打包,分发等功能 具体可以参考我的另外三篇文章 https://www.cnblogs. ...

  7. 《前端运维》五、k8s--1安装与基本配置

    一.k8s基础概念与安装 k8s,即kubernetes是用于自动部署,扩展和管理容器化应用程序的开源系统.详细的描述就不多说了,官网有更详细的内容.简单来说,k8s,是一个可以操作多台机器调度部署镜 ...

  8. 《前端运维》三、Docker--2其他

    一.制作DockerFile docker的镜像类似于用一层一层的文件组成.inspect命令可以查看镜像或容器的的信息,其中Layers就是镜像的层文件,只读不能修改,基于镜像创建的容器会共享这些层 ...

  9. 高级运维(五):构建memcached服务、LNMP+memcached、使用Tomcat设置Session、Tomcat实现session共享

    一.构建memcached服务 目标: 本案例要求先快速搭建好一台memcached服务器,并对memcached进行简单的添.删.改.查操作: 1> 安装memcached软件,并启动服务d ...

随机推荐

  1. 使用Jitpack发布开源Java库

    原文:使用Jitpack发布开源Java库 | Stars-One的杂货小窝 很久之前也写过一篇使用Jitpack发布Android开源库的文章,详见Android开发--发布第三方库到JitPack ...

  2. 详细介绍rar是什么由谁发明

    RAR是一种专利文件格式,用于数据紧缩与归档打包,开发者为尤金·罗谢尔(俄语:Евгений Лазаревич Рошал,拉丁转写:Yevgeny Lazarevich Roshal),RAR的全 ...

  3. 私有化轻量级持续集成部署方案--06-私有镜像仓库-Harbor

    提示:本系列笔记全部存在于 Github, 可以直接在 Github 查看全部笔记 针对私有镜像仓库的问题,Docker 官方提供了搭建仓库服务的镜像服务:registry,使用此镜像就可以部署私有仓 ...

  4. 使用Hot Chocolate和.NET 6构建GraphQL应用(9) —— 实现Mutate更新数据

    系列导航 使用Hot Chocolate和.NET 6构建GraphQL应用文章索引 需求 在上一篇文章中,我们演示了如何使用Hot Chocolate进行GraphQL的Mutate新增数据,这篇文 ...

  5. [镜像转换] ova文件转换成raw文件, 导入到openstack

    ova转raw 使用工具: qemu-img.libguestfs-tools.libguestfs-winsupport # 从vmware导出ova文件, tar 解压导出来的ova文件 $ ta ...

  6. monowall

    https://www.cat-home.org/?action=show&id=158

  7. 思迈特软件Smartbi光鲜亮丽的背后是什么在支撑?

    思迈特软件Smartbi是国内知名BI厂商,自2011年成立以来就以提升和挖掘客户的价值为使命,致力于为客户提供一站式商业智能平台和BI解决方案,发展到如今已经获得了来自国家.地方政府.国内外权威分析 ...

  8. Specified cast is not valid(C#) 引发的思考(装箱,拆箱本质)

    没有很华丽的语言,直接拿代码说事情把. 这段代码,会报错吗?  结论:当然不会 这段代码会报错了.原因是为啥? 这里面的水比较深.也要提醒各位写代码的适合要引起注意.异常:System.Invalid ...

  9. mysql-8.0.12 安装使用教程

    Microsoft Windows [版本 10.0.15063] (c) 2017 Microsoft Corporation.保留所有权利. C:\WINDOWS\system32>D: D ...

  10. PhpStudy代码执行后门

    0x00 概述 只需要两个参数 Accept-Encoding: gzip,deflate Accept-Charset: Base64编码(PHP代码) 0x01 利用代码 加群可以下载:87369 ...