@TOC
前言
首先在案例之前,先认识一下被业界广泛采用的服务发布有哪些,也是我们之后要实现的东西什么
发布策略
在现代软件开发和运维中,服务发布策略至关重要,以确保新版本能够顺利上线并最小化风险。以下是几种被业界广泛采用的服务发布策略:
蓝绿发布(Blue-Green Deployment)
概念:
蓝绿发布是一种减少停机时间和风险的部署策略。它通过维护两套几乎完全相同的生产环境——蓝色环境和绿色环境——来实现平滑的版本切换。
流程:
蓝色环境:当前活跃的生产环境,正在处理实际的用户流量。
绿色环境:待更新的新版本被部署到绿色环境中。
切换流量:一旦新版本在绿色环境中通过所有测试,流量从蓝色环境切换到绿色环境。
回滚:如果新版本出现问题,可以迅速切换回蓝色环境。
优点:
无缝切换,最小化停机时间。
容易回滚,风险较低。
缺点:
需要两套生产环境,成本较高。
资源利用率可能不高。A/B 测试(A/B Testing)
概念:
A/B 测试是通过将用户流量分成两组或多组,分别体验不同版本的应用,从而比较其效果和性能差异的一种发布策略。
流程:
版本划分:创建版本A(现有版本)和版本B(新版本)。
流量分配:随机将用户流量划分到A/B两个版本中。
数据收集:收集用户在不同版本下的行为数据。
分析结果:分析数据确定哪个版本表现更好。
优点:
可以在真实环境中验证新功能的效果。
数据驱动决策,精确了解用户偏好。
缺点:
需要数据分析能力强,才能有效评估结果。
对用户体验可能产生不一致的影响。金丝雀发布(Canary Release)
概念:
金丝雀发布是一种逐步发布策略,通过向一小部分用户发布新版本,观察其表现并逐步扩大覆盖面,以确保新版本的稳定性和可靠性。
流程:
小规模发布:将新版本发布给少量用户(通常是内部用户或早期测试用户)。
监控和评估:密切监控新版本的性能和用户反馈。
扩大发布范围:如果新版本表现良好,逐步增加覆盖用户直到全量发布。
优点:
风险较小,可以早期发现问题。
逐步发布,问题排查和修复较为容易。
缺点:
发布和监控过程较为复杂,需要持续观察。
需要良好的监控和反馈机制。
应用
环境
虚拟机
Ip | 主机名 | cpu | 内存 | 硬盘 |
---|---|---|---|---|
192.168.10.11 | master01 | 2cpu双核 | 4G | 100G |
192.168.10.12 | worker01 | 2cpu双核 | 4G | 100G |
192.168.10.13 | worker02 | 2cpu双核 | 4G | 100G |
版本 centos7.9
已部署k8s-1.27
通过ingress-nginx实现灰度发布系统
一、负载均衡器metallb部署
1. 修改kube-proxy代理模式
kubectl edit configmap kube-proxy -n kube-syste
更改两处
strictARP 后的flase改为true
node 后添加ipvs
没看见往下翻
重启
kubectl rollout restart daemonset kube-proxy -n kube-system
2. metallb部署
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml
服务器连接不了时,可在vpn连接后,浏览器中访问https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml
看到内容后复制创建文件
也可以使用离线下载后的文件部署
kubectl apply -f metallb-native.yaml
查看
kubectl -n metallb-system get pod
等待一会,可通过查看描述信息跟踪pod的运行状态,长时间无法完成下载时,各节点重启docker
kubectl -n metallb-system describe pod controller-6b9fd67ff4-rzvg2
3. IP地址池准备
vim ippool.yaml
addresses下是范围
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: ippool
namespace: metallb-system
spec:
addresses:
- 192.168.10.240-192.168.10.250
yaml应用
kubectl apply -f ippool.yaml
若出现故障提示,等上面pod全部运行起来再部署
还不行,各节点重启docker
查看地址池信息
kubectl -n metallb-system describe ipaddresspools.metallb.io ippool
4.开启二层通告
vim L2.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
应用yaml
kubectl apply -f L2.yaml
二、 服务代理ingress nginx部署
(1)获取ingress nginx部署文件
创建目录
mkdir tsdir
cd tsdir
windows浏览器打开文件:
https://github.com/kubernetes/ingress-nginx/blob/main/deploy/static/provider/baremetal/deploy.yaml
复制文件内容到linux中deploy.yaml文件
vim deploy.yaml
(2)修改部署文件deploy.yaml
vim deploy.yaml
修改此行 type: NodePort
为 type: LoadBalancer
修改前
修改后
(3)部署ingress nginx
kubectl apply -f deploy.yaml
稍等几分钟后查看 需要vpn,没有的话查看信息时会显示连接不到镜像仓库
kubectl -n ingress-nginx get pod
可以看到已经成功运行了
修改configmap
kubectl get configmaps ingress-nginx-controller -n ingress-nginx
kubectl edit configmaps ingress-nginx-controller -n ingress-nginx
将false改为true
修改前
修改后
重启ingress-nginx应用:
kubectl rollout restart deployment ingress-nginx-controller -n ingress-nginx
三、应用服务部署
1.v1版本部署
vim 01-deploy-nginx-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-v1
spec:
replicas: 1
selector:
matchLabels:
app: nginx
version: v1
template:
metadata:
labels:
app: nginx
version: v1
spec:
containers:
- name: nginx
image: "openresty/openresty:centos"
ports:
- name: http
protocol: TCP
containerPort: 80
volumeMounts:
- mountPath: /usr/local/openresty/nginx/conf/nginx.conf
name: config
subPath: nginx.conf
volumes:
- name: config
configMap:
name: nginx-v1
---
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app: nginx
version: v1
name: nginx-v1
data:
nginx.conf: |-
worker_processes 1;
events {
accept_mutex on;
multi_accept on;
use epoll;
worker_connections 1024;
}
http {
ignore_invalid_headers off;
server {
listen 80;
location / {
access_by_lua '
local header_str = ngx.say("nginx-v1")
';
}
}
}
---
apiVersion: v1
kind: Service
metadata:
name: nginx-v1
spec:
type: ClusterIP
ports:
- port: 80
protocol: TCP
name: http
selector:
app: nginx
version: v1
部署yaml并查看
kubectl apply -f 01-deploy-nginx-v1.yaml
kubectl get pod
查看service
kubectl get svc
看看能不能访问到
curl 10.109.30.198
2.v2版本部署
vim 02-deploy-nginx-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-v2
spec:
replicas: 1
selector:
matchLabels:
app: nginx
version: v2
template:
metadata:
labels:
app: nginx
version: v2
spec:
containers:
- name: nginx
image: "openresty/openresty:centos"
ports:
- name: http
protocol: TCP
containerPort: 80
volumeMounts:
- mountPath: /usr/local/openresty/nginx/conf/nginx.conf
name: config
subPath: nginx.conf
volumes:
- name: config
configMap:
name: nginx-v2
---
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app: nginx
version: v2
name: nginx-v2
data:
nginx.conf: |-
worker_processes 1;
events {
accept_mutex on;
multi_accept on;
use epoll;
worker_connections 1024;
}
http {
ignore_invalid_headers off;
server {
listen 80;
location / {
access_by_lua '
local header_str = ngx.say("nginx-v2")
';
}
}
}
---
apiVersion: v1
kind: Service
metadata:
name: nginx-v2
spec:
type: ClusterIP
ports:
- port: 80
protocol: TCP
name: http
selector:
app: nginx
version: v2
应用yaml文件并查看
kubectl apply -f 02-deploy-nginx-v2.yaml
kubectl get pods
查看service
kubectl get svc
测试
curl 10.105.171.163
3.创建stable版本ingress资源对象(对外发布)
vim 03-stable-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-v1 #自定义ingress名称
namespace: default
spec:
ingressClassName: nginx
rules:
- host: www.test.com # 自定义域名
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nginx-v1 # 对应上面创建的service名称
port:
number: 80
应用ingress.yaml文件并查看
kubectl apply -f 03-stable-ingress.yaml
kubectl -n ingress-nginx get svc
在hosts添加域名解析
vim /etc/hosts
添加
192.168.10.240 www.test.com
测试
curl www.test.com
创建目录并进入
mkdir nginx && cd nginx
四、流量切分
1.基于服务权重的流量切分
效果就是百分之九十的流量访问v1
百分之十的流量访问v2
创建yaml文件
vim 04-canary-ingress-weight.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-v2 #自定义ingress名称
namespace: default
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
ingressClassName: nginx
rules:
- host: www.test.com # 自定义域名
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nginx-v2 # 对应上面创建的service名称
port:
number: 80
应用yaml文件
kubectl apply -f 04-canary-ingress-weight.yaml
kubectl get ingress
注:虽然这里显示的是192.168.10.13但实际上还是通过域名访问到192.168.10.240的
测试
简单的shell脚本应用,测试10次
for i in {1..10};do curl http://www.test.com;done
虽然设置的是百分之十的流量,但实际应用不一定是10个里只有一个访问v2
2.基于用户请求头Header的流量切分
效果就是来自shenzhen的用户访问v2
其他访问v1
为了不影响,先删除上个yaml文件生成的应用,然后创建新的yaml文件
kubectl delete -f 04-canary-ingress-weight.yaml
vim 05-canary-ingress-header.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-v2 #自定义ingress名称
namespace: default
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "Region"
nginx.ingress.kubernetes.io/canary-by-header-pattern: "shenzhen"
spec:
ingressClassName: nginx
rules:
- host: www.test.com # 自定义域名
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nginx-v2 # 对应上面创建的service名称
port:
number: 80
应用新的yaml文件并查看
kubectl apply -f 05-canary-ingress-header.yaml
kubectl get ingress
测试
-H 大概意思就是模拟请求头内容
curl www.test.com
curl -H "Region:beijing" www.test.com
curl -H "Region:shanghai" www.test.com
curl -H "Region:shenzhen" www.test.com
可以看到效果
3.基于Cookie的流量切分
使用 Cookie 则无法自定义 value,以模拟灰度shenzhen地域用户为例,仅将带有名为 user_from_shenzhen的 Cookie 的请求转发给当前 Canary Ingress
照旧
kubectl delete -f 05-canary-ingress-header.yaml
vim 06-canary-ingress-cookie.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-v2 #自定义ingress名称
namespace: default
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "user_from_shenzhen"
spec:
ingressClassName: nginx
rules:
- host: www.test.com # 自定义域名
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nginx-v2 # 对应上面创建的service名称
port:
number: 80
应用yaml文件并查看
kubectl apply -f 06-canary-ingress-cookie.yaml
kubectl get ingress
测试
curl --cookie "user_from_beijing" http://www.test.com
curl --cookie "user_from_shenzhen" http://www.test.com
curl --cookie "user_from_shenzhen=always" http://www.test.com
可查看当仅有 cookie user_from_shenzhen 为 always 的请求才由 v2 版本的服务响应。
至此 完成
总结
每种发布策略都有其特定的优缺点,选择合适的策略需要根据项目规模、团队能力和业务需求来综合考虑。蓝绿发布适合对稳定性要求极高的项目,A/B 测试适合需要数据驱动决策的功能优化,金丝雀发布则适合希望逐步发布、降低风险的场景。通过合理运用这些策略,可以有效提升发布过程的效率和质量。