《前端运维》五、k8s--3灰度发布、滚动更新与探针
一、灰度发布
灰度发布是一种发布方式,也叫金丝雀发布,起源是矿工在下井之前会先放一只金丝雀到井里,如果金丝雀不叫了,就代表瓦斯浓度高。原因是金丝雀对瓦斯气体很敏感。灰度发布的做法是:会在现存旧应用的基础上,启动一个新版应用,但是新版应用并不会直接让用户访问。而是先让测试同学去进行测试。如果没有问题,则可以将真正的用户流量慢慢导入到新版,在这中间,持续对新版本运行状态做观察,直到慢慢切换过去,这就是所谓的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灰度发布、滚动更新与探针的更多相关文章
- 【运维工具】Git代码发布系统
引言 代码发布系统是互联网公司必备的运维系统,作用主要用户发布业务代码 到 业务服务器 为什么需要代码发布系统 有的同学可能说,我们公司服务器就那么一台,做个发布系统太麻烦了? 不认同这说法 发布系统 ...
- k8s实现灰度发布
灰度发布在实际生产部署中是经常被使用的方式,常规的方法是手动从前端LB(负载均衡)上将后端服务器摘掉,然后,停服务,最后上传代码,完成软连接更新.在使用CI/CD工具时,这个过程变得自动化了,我们只需 ...
- Windows运维之Windows8.1-KB2999226-x64安装提示 此更新不适用你的计算机
摘要:本文主要向大家介绍了Windows运维之Windows8.1-KB2999226-x64安装提示 此更新不适用你的计算机,通过具体的内容向大家展现,希望对大家学习Windows运维有所帮助. 本 ...
- Linux运维五:定时任务crond服务
一.crond简介 crond是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动cro ...
- 真正云原生的智能运维体系,阿里云发布ECS自动化运维套件
云计算的发展,推动了自动化运维.DevOps.AIOps 等趋势的兴起,在业务快速变化的今天,企业希望通过一套自动化运维的专家系统提高运维效率,为业务提供支撑. 传统的方式下,打造一套成熟的 DevO ...
- docker swarm实现java项目的发布/滚动更新/回滚/镜像管理
使用docker swarm滚动更新java项目,部署集群,这一切的前提是使用Jenkins+maven进行项目打包,分发等功能 具体可以参考我的另外三篇文章 https://www.cnblogs. ...
- 《前端运维》五、k8s--1安装与基本配置
一.k8s基础概念与安装 k8s,即kubernetes是用于自动部署,扩展和管理容器化应用程序的开源系统.详细的描述就不多说了,官网有更详细的内容.简单来说,k8s,是一个可以操作多台机器调度部署镜 ...
- 《前端运维》三、Docker--2其他
一.制作DockerFile docker的镜像类似于用一层一层的文件组成.inspect命令可以查看镜像或容器的的信息,其中Layers就是镜像的层文件,只读不能修改,基于镜像创建的容器会共享这些层 ...
- 高级运维(五):构建memcached服务、LNMP+memcached、使用Tomcat设置Session、Tomcat实现session共享
一.构建memcached服务 目标: 本案例要求先快速搭建好一台memcached服务器,并对memcached进行简单的添.删.改.查操作: 1> 安装memcached软件,并启动服务d ...
随机推荐
- code-server服务端开发利器,再也不用vim装逼了!!!
一直有个需求,就是万不得已在服务修改代码的时候能有个好的工具,至少比vim要强吧!虽然vim也还行,但是如果比vscode那一定是差了点!这个微软洗心革面的新工具着实不错!从刚开始的鄙视到真香我用了不 ...
- Spring Cloud之微服务注册到Eureka Server集群
在Spring Cloud之服务注册中心搭建Eureka Server服务注册中⼼ - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中已经搭建好了Eureka Server集群,本文就利用 ...
- Spring Boot 学习-基础
一.Spring Boot 概述 SpringBoot 定义 Spring Boot 并不是用来替代 Spring 的新框架,而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具 ...
- hydra安装及破解rdp方法
hydra暴力破解工具 下载:https://github.com/vanhauser-thc/thc-hydra 安装步骤: ./configure make&&make insta ...
- 【C# 线程】线程局部存储(TLS)理论部分 ThreadStatic|LocalDataStoreSlot|ThreadLocal<T>
线程本地存储(TLS:Thread Local Storage) 线程本地存储(Thread Local Storage),字面意思就是专属某个线程的存储空间.变量大体上分为全局变量和局部变量,一个进 ...
- 给bootstrap-table填坑
由于设计变更,需要把数据由分页展示改为全部展示(才3500条数据),结果chrome浏览器页面卡顿,火狐浏览器直接卡死! console.time分析之后,竟然是bootstrap-table插件的坑 ...
- javaScript(js)手写原生任务定时器源码
javaScript(js)手写原生任务定时器 功能介绍 定时器顾名思义就是在某个特定的时间去执行一些任务,现代的应用程序早已不是以前的那些由简单的增删改查拼凑而成的程序了,高复杂性早已是标配,而任务 ...
- Windows Server 2012 在桌面上显示”我的电脑”
转至:https://jingyan.baidu.com/article/f25ef2544f6883482c1b82e5.html Windows Server 2012 沒有快捷方式显示我的电脑到 ...
- POJ2749 题解
题目大意:有若干牛圈和两个连接起来的的中转点S1,S2.每个牛圈需要选择其中一个中转点与之连接,从而使任意两个牛圈能够连通.有若干对牛圈里的牛互相hate或是互相like.若两个牛圈里的牛互相hate ...
- QT:Qt Creator快捷键与使用技巧
功能 快捷键 解释 Switch Header/Source F4 在同名.h与.cpp文件间切换 Follow Symbol Under Cursor F2 跟踪光标下的变量或函数 变量:跟踪到变量 ...