Kubernetes金丝雀发布
华子目录
- Canary金丝雀发布
- 什么是金丝雀发布
- Canary发布方式
- 基于header(http包头)灰度发布
- 基于权重的金丝雀发布
Canary金丝雀发布

什么是金丝雀发布
金丝雀发布也称为灰度发布,是一种软件发布策略- 主要
目的是在将新版本的软件全面推广到生产环境之前,先在一小部分用户或服务器上进行测试和验证,以降低因新版本引入重大问题而对整个系统造成的影响 - 是一种
Pod的发布方式。金丝雀发布采取先添加、再删除的方式,保证Pod的总量不低于期望值。并且在更新部分Pod后,暂停更新,当确认新Pod版本运行正常后再进行其他版本的Pod的更新
Canary发布方式
三种发布方式:
- 优先级:
head大于cookie大于weight - 其中
header和weight用的最多
基于header(http包头)灰度发布

我们可以看到如果包头中有stage=gray的键值对,就访问新版本,包头中没有那个键值对,就访问旧版本
- 通过
Annotaion扩展 - 创建灰度
ingress,配置灰度头部key以及value 灰度流量验证完毕后,切换正式ingress到新版本- 之前我们在
做升级时可以通过控制器做滚动更新,默认25%利用header可以使升级更为平滑,通过key和value测试新的业务体系是否有问题
创建2个deployment控制器
#发现没有运行的pod
[root@k8s-master service]# kubectl get pods
No resources found in default namespace.#创建一个deployment控制器,控制器中运行一个pod
[root@k8s-master service]# kubectl create deployment deployment --image myapp:v1 --dry-run=client -o yaml > deployment-v1.yml[root@k8s-master service]# vim deployment-v1.yml
[root@k8s-master service]# cat deployment-v1.yml
apiVersion: apps/v1
kind: Deployment #指明这是一个deployment控制器
metadata: #控制器的元数据labels: #控制器的标签app: deployment1 #控制器的标签name: deployment1 #控制器的名字
spec: 控制器的规格replicas: 1 #pod数量selector: #pod选择器matchLabels: #声明的要管理的podapp: myappv1 #标签为app=myappv1的pod会被管理template: #pod的模板metadata: #pod的元数据labels: #pod的标签app: myappv1spec: #pod的规格containers:- image: myapp:v1name: myappv1#在克隆一份
[root@k8s-master service]# cp deployment-v1.yml deployment-v2.yml
[root@k8s-master service]# vim deployment-v2.yml
[root@k8s-master services]# cat deployment-v2.yml
apiVersion: apps/v1
kind: Deployment #指明这个一个deployment控制器
metadata: #控制器的元数据labels: app: deployment2 #控制器的标签name: deployment2 #控制器的名字
spec: #控制器的规格replicas: 1 #pod数量selector: #pod选择器matchLabels: app: myappv2 #声明需要管理的标签template: #pod的模板metadata: #pod的元数据labels: app: myappv2 #pod的标签spec: #pod的规格containers:- image: myapp:v2name: myappv2
[root@k8s-master service]# kubectl apply -f deployment-v1.yml
deployment.apps/deployment1 created
[root@k8s-master service]# kubectl apply -f deployment-v2.yml
deployment.apps/deployment2 created[root@k8s-master service]# kubectl get pods -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
deployment1-5c47495d84-ds4cl 1/1 Running 0 3m20s 10.244.2.15 k8s-node2.org <none> <none> app=myappv1,pod-template-hash=5c47495d84
deployment2-67cc8c4845-bfnvx 1/1 Running 0 6m49s 10.244.2.14 k8s-node2.org <none> <none> app=myappv2,pod-template-hash=67cc8c4845
创建2个service微服务
[root@k8s-master service]# kubectl expose deployment deployment1 --port 8080 --target-port 80 --dry-run=client -o yaml >> deployment-v1.yml[root@k8s-master service]# kubectl expose deployment deployment2 --port 8080 --target-port 80 --dry-run=client -o yaml >> deployment-v2.yml
[root@k8s-master service]# vim deployment-v1.yml
[root@k8s-master service]# cat deployment-v1.yml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: deployment1name: deployment1
spec:replicas: 1selector:matchLabels:app: myappv1template:metadata:labels:app: myappv1spec:containers:- image: myapp:v1name: myappv1---
apiVersion: v1
kind: Service #指明这是一个service微服务
metadata: #微服务元数据labels: app: deployment1 #微服务标签 name: deployment1 #微服务的名字
spec: #微服务的规格ports: #是一个端口列表,用于描述service应该监听的端口以及如何将流量转发给pod- port: 8080 #service微服务监听的端口号protocol: TCP #使用的协议,这里是TCPtargetPort: 80 #pod上应用程序监听的端口selector: #标签选择器,用于确定哪些pods应该被这个service管理app: myappv1 #pod标签为app=myappv1的被该service管理
[root@k8s-master service]# vim deployment-v2.yml
[root@k8s-master service]# cat deployment-v2.yml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: deployment2name: deployment2
spec:replicas: 1selector:matchLabels:app: myappv2template:metadata:labels:app: myappv2spec:containers:- image: myapp:v2name: myappv2---
apiVersion: v1
kind: Service
metadata:labels:app: deployment2name: deployment2
spec:ports:- port: 8080protocol: TCPtargetPort: 80selector:app: myappv2
[root@k8s-master service]# kubectl apply -f deployment-v1.yml
deployment.apps/deployment1 unchanged
service/deployment1 created
[root@k8s-master service]# kubectl apply -f deployment-v2.yml
deployment.apps/deployment2 unchanged
service/deployment2 created
[root@k8s-master service]# kubectl get pods -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
deployment1-5c47495d84-ds4cl 1/1 Running 0 15m 10.244.2.15 k8s-node2.org <none> <none> app=myappv1,pod-template-hash=5c47495d84
deployment2-67cc8c4845-bfnvx 1/1 Running 0 18m 10.244.2.14 k8s-node2.org <none> <none> app=myappv2,pod-template-hash=67cc8c4845[root@k8s-master service]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
deployment1 ClusterIP 10.108.37.167 <none> 8080/TCP 3m8s app=myappv1
deployment2 ClusterIP 10.96.202.197 <none> 8080/TCP 3m2s app=myappv2
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d <none>[root@k8s-master service]# kubectl describe svc deployment1
Name: deployment1
Namespace: default
Labels: app=deployment1
Annotations: <none>
Selector: app=myappv1
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.108.37.167
IPs: 10.108.37.167
Port: <unset> 8080/TCP
TargetPort: 80/TCP
Endpoints: 10.244.2.15:80
Session Affinity: None
Events: <none>[root@k8s-master service]# kubectl describe svc deployment2
Name: deployment2
Namespace: default
Labels: app=deployment2
Annotations: <none>
Selector: app=myappv2
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.202.197
IPs: 10.96.202.197
Port: <unset> 8080/TCP
TargetPort: 80/TCP
Endpoints: 10.244.2.14:80
Session Affinity: None
Events: <none>
- 创建
ingress1.yml
[root@k8s-master service]# kubectl create ingress ingress1 --class nginx --rule='/=deployment1:8080' --dry-run=client -o yaml > ingress1.yml[root@k8s-master service]# vim ingress1.yml
[root@k8s-master service]# cat ingress1.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: ingress1
spec:ingressClassName: nginxrules:- http:paths:- backend:service:name: deployment1port:number: 8080path: /pathType: Prefix
- 创建
ingress2.yml
[root@k8s-master service]# kubectl create ingress ingress2 --class nginx --rule='/=deployment2:8080' --dry-run=client -o yaml > ingress2.yml[root@k8s-master service]# vim ingress2.yml
[root@k8s-master service]# cat ingress2.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:nginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-by-header: "name" #键nginx.ingress.kubernetes.io/canary-by-header-value: "huazi" #值name: ingress2
spec:ingressClassName: nginxrules:- http:paths:- backend:service:name: deployment2port:number: 8080path: /pathType: Prefix
[root@k8s-master service]# kubectl apply -f ingress1.yml
ingress.networking.k8s.io/ingress1 created
[root@k8s-master service]# kubectl apply -f ingress2.yml
ingress.networking.k8s.io/ingress2 created
[root@k8s-master service]# kubectl describe ingress ingress1
Name: ingress1
Labels: <none>
Namespace: default
Address: 172.25.254.10
Ingress Class: nginx
Default backend: <default>
Rules:Host Path Backends---- ---- --------*/ deployment1:8080 (10.244.2.15:80)
Annotations: <none>
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Sync 12m (x2 over 13m) nginx-ingress-controller Scheduled for sync[root@k8s-master service]# kubectl describe ingress ingress2
Name: ingress2
Labels: <none>
Namespace: default
Address: 172.25.254.10
Ingress Class: nginx
Default backend: <default>
Rules:Host Path Backends---- ---- --------*/ deployment2:8080 (10.244.2.14:80)
Annotations: nginx.ingress.kubernetes.io/canary: truenginx.ingress.kubernetes.io/canary-by-header: namenginx.ingress.kubernetes.io/canary-by-header-value: huazi
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Sync 2m21s (x2 over 3m3s) nginx-ingress-controller Scheduled for sync

基于权重的金丝雀发布

- 通过
Annotaion拓展 - 创建
灰度ingress,配置灰度权重以及总权重 灰度流量验证完毕后,切换正式ingress到新版本
#删掉基于header的ingress
[root@k8s-master service]# kubectl delete -f ingress2.yml
ingress.networking.k8s.io "ingress2" deleted
[root@k8s-master service]# vim ingress2.yml
[root@k8s-master service]# cat ingress2.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:nginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-weight: "10" #10/100=10%,将有10%的流量打到新版本上nginx.ingress.kubernetes.io/canary-weight-total: "100"name: ingress2
spec:ingressClassName: nginxrules:- http:paths:- backend:service:name: deployment2port:number: 8080path: /pathType: Prefix
[root@k8s-master service]# kubectl apply -f ingress2.yml
ingress.networking.k8s.io/ingress2 created
[root@k8s-master service]# kubectl describe ingress ingress1
Name: ingress1
Labels: <none>
Namespace: default
Address: 172.25.254.10
Ingress Class: nginx
Default backend: <default>
Rules:Host Path Backends---- ---- --------*/ deployment1:8080 (10.244.2.15:80)
Annotations: <none>
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Sync 27m (x2 over 27m) nginx-ingress-controller Scheduled for sync[root@k8s-master service]# kubectl describe ingress ingress2
Name: ingress2
Labels: <none>
Namespace: default
Address: 172.25.254.10
Ingress Class: nginx
Default backend: <default>
Rules:Host Path Backends---- ---- --------*/ deployment2:8080 (10.244.2.14:80)
Annotations: nginx.ingress.kubernetes.io/canary: truenginx.ingress.kubernetes.io/canary-weight: 10nginx.ingress.kubernetes.io/canary-weight-total: 100
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Sync 34s (x2 over 44s) nginx-ingress-controller Scheduled for sync
- 写检测脚本
[root@harbor ~]# vim check.sh
#!/bin/bash
v1=0
v2=0
for ((i=0;i<100;i++))
doresponse=`curl -s 172.25.254.50 | grep -c v1`v1=`expr $v1 + $response`v2=`expr $v2 + 1 - $response`
done
echo "v1:$v1 v2:$v2"
[root@harbor ~]# bash check.sh
v1:89 v2:11
[root@harbor ~]# bash check.sh
v1:87 v2:13
#我们发现比例接近于9:1
当我们增加权重后
[root@k8s-master service]# vim ingress2.yml
[root@k8s-master service]# cat ingress2.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:annotations:nginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-weight: "20"nginx.ingress.kubernetes.io/canary-weight-total: "100"name: ingress2
spec:ingressClassName: nginxrules:- http:paths:- backend:service:name: deployment2port:number: 8080path: /pathType: Prefix
[root@k8s-master service]# kubectl apply -f ingress2.yml
ingress.networking.k8s.io/ingress2 configured
[root@harbor ~]# bash check.sh
v1:76 v2:24
[root@harbor ~]# bash check.sh
v1:79 v2:21
#我们发现比例进阶于8:2
相关文章:
Kubernetes金丝雀发布
华子目录 Canary金丝雀发布什么是金丝雀发布Canary发布方式基于header(http包头)灰度发布基于权重的金丝雀发布 Canary金丝雀发布 什么是金丝雀发布 金丝雀发布也称为灰度发布,是一种软件发布策略主要目的是在将新版本的软件全面推广到生产环…...
树形DP讲解
文章目录 树形DP讲解一、引言二、树形DP基础1、树的定义2、树形DP的基本思想3、代码示例:子树大小 三、经典例题解析1、树的平衡点1.1、代码示例 2、没有上司的舞会(树的最大独立集)2.1、代码示例 四、总结 树形DP讲解 一、引言 树形动态规…...
容器:如何调试容器
调试容器,主要是指的调试Dockerfile,调试Dockerfile中的各个命令的执行,大小等 1、docker history查看构建过程和所有的中间层 2、docker run rm -it -u root XXX sh,通过临时容器的方式启动,可以调试中间层文件 3、do…...
用图说明 CPU、MCU、MPU、SoC 的区别
CPU CPU 负责执行构成计算机程序的指令,执行这些指令所指定的算术、逻辑、控制和输入/输出(I/O)操作。 MCU (microcontroller unit) 不同的 MCU 架构如下,注意这里的 MPU 表示 memory protection unit MPU (microprocessor un…...
牛客周赛 Round 65
文章目录 超市思路:Solved: 雨幕思路:Solved: 闺蜜思路:Solved: 医生思路:Solved: 降温(easy)思路:Solved: F-降温(hard&a…...
超级经典的79个软件测试面试题(内含答案)
1、软件的生命周期(prdctrm) 计划阶段(planning)-〉需求分析(requirement)-〉设计阶段(design)-〉编码(coding)->测试(testing)->运行与维护(running maintrnacne) 测试用例 用例编号 测试项目 测试标题 重要级别 预置条件 输入数据 执行步骤 预期结果 2、问…...
【Mac】安装 F5-TTS
1、下载项目 项目地址:【GitHub】 SWivid F5-TTS 2、创建并激活 Python 虚拟环境 # 创建 Python 虚拟环境 userMac F5-TTS-main % python3 -m venv f5-tts# 激活进入 Python 虚拟环境 userMac F5-TTS-main % source f5-tts/bin/activate (f5-tts) userrMac F5-TT…...
Leaflet查询矢量瓦片偏移的问题
1、问题现象 使用Leaflet绘制工具查询出来的结果有偏移 2、问题排查 1)Leaflet中latLngToContainerPoint和latLngToLayerPoint的区别 2)使用Leaflet查询需要使用像素坐标 3)经排查发现,container获取的坐标是地图容器坐标&…...
存储引擎技术进化
B-tree 目前支撑着数据库产业的半壁江山。 50 年来不变而且人们还没有改变它的意向 鉴定一个算法的优劣,有一个学派叫 IO复杂度分析 ,简单推演真假便知。 下面就用此法分析下 B-tree(traditional b-tree) 的 IO 复杂度,对读、写 IO 一目了…...
CentOS 9 Stream 上安装 Maven
CentOS 9 Stream 上安装 Maven 在 CentOS 9 Stream 上安装 Maven,可以按照以下步骤进行: 更新系统软件包: sudo dnf update安装 Maven: CentOS 9 Stream 默认的包管理器中已经包含 Maven,你可以直接安装: s…...
强势改进!TCN-Transformer时间序列预测
强势改进!TCN-Transformer时间序列预测 目录 强势改进!TCN-Transformer时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现TCN-Transformer时间序列预测; 2.运行环境为Matlab2023b; 3.单个变量时间序…...
MyBatis的不同参数传递封装
MyBatis参数传递 传参方式 1. 使用 #{} 占位符 这是 MyBatis 中最常用的参数传递方式。它将参数直接替换到 SQL 语句中的占位符位置。 单个参数: <select id"selectUserById" resultType"User">SELECT * FROM users WHERE id #{id}…...
kotlin 协程方法总结
Kotlin 协程是一套强大的异步编程工具,以下是对 Kotlin 协程常用方法的总结: 1. 协程构建器 launch: 启动一个新的协程,不阻塞当前线程,返回一个 Job 对象。 GlobalScope.launch {// 协程体}async: 启动一个新的协程并返回一个…...
脉冲当量计算方法
脉冲的概念: 脉冲当量是指控制器输出一个定位控制脉冲时,所产生的定位控制移动的位移。在直线运动中,它表示移动的距离;在圆周运动中,它表示转动的角度。简而言之,脉冲当量就是电机接收一个脉冲信号后能够移…...
TongWeb7.0.E.6_P11嵌入式版本使用指引(by lqw)
文章目录 声明相关概念手册的使用示范工程安装工程介质 安装前准备示范工程参考(spring-boot-helloWorld-2.x)示范参考 声明 1.本文参考001_TongWeb_V7.0嵌入式版_JavaEE标准容器用户指南_70E6_P11A01.pdf,实际以最新更新的手册为准。 2.本文…...
Node.js:Express 服务 路由
Node.js:Express 服务 & 路由 创建服务处理请求req对象 静态资源托管托管多个资源挂载路径前缀 路由模块化 Express是Node.js上的一个第三方框架,可以快速开发一个web框架。本质是一个包,可以通过npm直接下载。 创建服务 Express创建一…...
C++之多态(上)
C之多态 多态的概念 多态(polymorphism)的概念:通俗来说,就是多种形态。多态分为编译时多态(静态多态)和运⾏时多 态(动态多态),这⾥我们重点讲运⾏时多态,编译时多态(静态多态)和运⾏时多态(动态多态)。编译时 多态(静态多态)主…...
PySpark单机模式安装教程
目录 1. 环境准备 1.1 安装要求 1.2 检查Python和Java环境 2. 下载并解压Spark 2.1 下载Spark 2.2 解压安装包 3. 配置环境变量 4. 配置Spark 5. 启动Spark Shell 6. 运行测试 7. 关闭Spark Shell 8. 常见问题 8.1 兼容性问题 8.2 环境变量配置 总结 1. 环境准备…...
DEVOPS: 认证与调度
概述 不知道大家有没有意识到一个现实,就是大部分时候,我们已经不像以前一样通过命令行,或者可视窗口来使用一个系统了现在我们上微博、或者网购,操作的其实不是眼前这台设备,而是一个又一个集群 通常,这样…...
ICPC区域赛成都站【赛后回顾+总结】
传送门 前言赛后总结赛后回顾赛后感悟 前言 首先,这是本人本赛季第一场XCPC区域赛,也是本人算竞生涯中第一场XCPC区域赛(之前只打过邀请赛和省赛)。 赛后总结 然后赛后总结一下:我队天崩开局,我队出师不利…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
