应用背景:应用发布需要基于指定IP进行灰度测试,这个指定的IP段可能是测试机,也可能是某个网段。这些IP地址访问同域名应用自动转发请求到灰度服务。
组件支持:需要对ingress-nginx-controller做二次开发改造,这里略过改造部分,重点关注测试流程。
测试步骤:准备两套环境,生产环境/测试环境,准备测试应用镜像,根据环境变量输出日志方便观察日志判断流量是被路由到哪个环境的服务,分别部署应用到生产和测试环境,编写测试脚本进行测试。接下来重点展示部署和测试脚本。
一、测试应用app.py
import os
import logging
from flask import Flask, jsonify
app = Flask(__name__)
# 日志配置
logging.basicConfig(
format='%(asctime)s [%(levelname)s] %(message)s',
level=logging.INFO
)
logger = logging.getLogger(__name__)
@app.route('/')
def main():
# 从环境变量获取配置
service_name = os.getenv('SERVICE_NAME', 'default')
log_message = os.getenv('LOG_MESSAGE', 'Default log message')
version = os.getenv('VERSION', 'v1')
# 记录日志
logger.info(f"[{service_name}-{version}] {log_message}")
return jsonify({
"service": service_name,
"version": version,
"message": log_message
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
二、Dockerfile文件
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]
三、requirements.txt
flask==2.0.3
werkzeug==2.0.3 # 固定兼容版本
四、部署脚本k8s.yaml
# 生产版本部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: production
namespace: python
spec:
replicas: 3
selector:
matchLabels:
app: demo
track: stable
template:
metadata:
labels:
app: demo
track: stable
spec:
imagePullSecrets:
- name: harbor-admin
containers:
- name: web
image: harbor-lite.tech.21cn.com/python/my-service:v4
env:
- name: SERVICE_NAME
value: "production"
- name: LOG_MESSAGE
value: "This is production service"
- name: VERSION
value: "v1"
ports:
- containerPort: 5000
---
# 灰度版本部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: canary
namespace: python-gray
spec:
replicas: 1
selector:
matchLabels:
app: demo
track: canary
template:
metadata:
labels:
app: demo
track: canary
spec:
imagePullSecrets:
- name: harbor-admin
containers:
- name: web
image: harbor-lite.tech.21cn.com/python/my-service:v5
env:
- name: SERVICE_NAME
value: "canary"
- name: LOG_MESSAGE
value: "This is canary service"
- name: VERSION
value: "v2"
ports:
- containerPort: 5000
---
# 生产环境 Service
apiVersion: v1
kind: Service
metadata:
name: prod-svc
namespace: python
spec:
selector:
app: demo
track: stable # 精确匹配生产 Pod
ports:
- protocol: TCP
port: 80
targetPort: 5000
---
# 灰度环境 Service
apiVersion: v1
kind: Service
metadata:
name: canary-svc
namespace: python-gray
spec:
selector:
app: demo
track: canary # 精确匹配灰度 Pod
ports:
- protocol: TCP
port: 80
targetPort: 5000
---
# 主Ingress(90%流量)
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: main-ingress
namespace: python
annotations:
nginx.ingress.kubernetes.io/canary: "false"
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: canary.demo.com
http:
paths:
- path: /
backend:
serviceName: prod-svc
servicePort: 80
---
# 灰度Ingress(10%流量)
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: canary-ingress
namespace: python-gray
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
rules:
- host: canary.demo.com
http:
paths:
- path: /
backend:
serviceName: canary-svc
servicePort: 80
五、测试脚本
#!/bin/bash
INGRESS_IP="your_ingress_ip" # 替换为实际IP
TOTAL=100
SUCCESS=0
FAILED=0
V1_COUNT=0
V2_COUNT=0
# 创建临时文件记录结果
result_file=$(mktemp)
trap 'rm -f "$result_file"' EXIT
for i in $(seq 1 $TOTAL); do
# 发送请求并记录结果
{
response=$(curl -sSf -m 5 -H "Host: canary.demo.com" http://172.19.0.93/ 2>&1)
exit_code=$?
if [ $exit_code -eq 0 ]; then
version=$(echo "$response" | jq -r '.version' 2>/dev/null)
if [[ "$version" == "v1" || "$version" == "v2" ]]; then
echo "success $version" >> "$result_file"
else
echo "invalid" >> "$result_file"
fi
else
echo "failed" >> "$result_file"
fi
} &
# 控制并发数
if (( i % 10 == 0 )); then
wait
fi
done
# 等待所有后台任务完成
wait
# 统计结果
while read -r line; do
case $line in
"success v1")
((SUCCESS++))
((V1_COUNT++))
;;
"success v2")
((SUCCESS++))
((V2_COUNT++))
;;
"invalid")
((FAILED++))
;;
"failed")
((FAILED++))
;;
esac
done < "$result_file"
# 生成报告
echo "=== 精准测试报告 ==="
echo "总请求数: $TOTAL"
echo "成功请求: $SUCCESS (v1: $V1_COUNT, v2: $V2_COUNT)"
echo "失败请求: $FAILED"
echo "灰度比例: $(( V2_COUNT * 100 / SUCCESS ))% (预期10%)"
# 验证总数
if [ $(( SUCCESS + FAILED )) -ne $TOTAL ]; then
echo "[警告] 总数校验失败:$SUCCESS + $FAILED ≠ $TOTAL"
else
echo "[校验] 总数匹配成功"
fi
测试结果:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有