本文目录导读:

- 核心原理
- 方案一:基于Nginx upstream的动态切换(最常用)
- 方案二:基于HAProxy的切换(适合高并发)
- 方案三:基于Kubernetes Service的切换(容器化PHP)
- 方案四:基于DNS的切换(相对粗粒度)
- 切换时的关键注意事项
- 推荐实践:最小中断切换流水线
在PHP项目的蓝绿部署中,负载切换服务节点主要涉及流量调度层(如Nginx、HAProxy、Kubernetes Service)的配置更新,以下是几种常见且实用的实现方案:
核心原理
保持两套完全相同的生产环境(蓝组、绿组),但只有一组接收实时流量,另一组待命或用于预发布验证,切换时,只需要修改负载均衡器的目标服务器组即可。
基于Nginx upstream的动态切换(最常用)
配置示例
# /etc/nginx/conf.d/php-app.conf
upstream php-backend {
# 默认指向绿色组
server 10.0.1.10:9000 weight=10; # 绿组节点1
server 10.0.1.11:9000 weight=10; # 绿组节点2
# server 10.0.2.10:9000 weight=10; # 蓝组节点1(备用,切换时启用)
# server 10.0.2.11:9000 weight=10; # 蓝组节点2(备用)
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://php-backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# PHP-FPM 相关配置(如果直接连接FPM)
include fastcgi_params;
fastcgi_pass php-backend;
}
}
切换脚本(bash)
#!/bin/bash
# blue-green-switch.sh
CURRENT="$(grep '#' /etc/nginx/conf.d/php-app.conf | grep -v '^$' | wc -l)"
if [ "$CURRENT" -eq 0 ]; then
# 当前是绿组(无注释),切换到蓝组
sed -i 's/server 10.0.1/sd server 10.0.1/' /etc/nginx/conf.d/php-app.conf
sed -i 's/sd server 10.0.2/server 10.0.2/' /etc/nginx/conf.d/php-app.conf
sed -i 's/# server 10.0.1/server 10.0.1/' /etc/nginx/conf.d/php-app.conf
else
# 当前是蓝组,切换到绿组
sed -i 's/server 10.0.2/sd server 10.0.2/' /etc/nginx/conf.d/php-app.conf
sed -i 's/sd server 10.0.1/server 10.0.1/' /etc/nginx/conf.d/php-app.conf
sed -i 's/# server 10.0.2/server 10.0.2/' /etc/nginx/conf.d/php-app.conf
fi
# 检查配置并重载
nginx -t && nginx -s reload
注意:实际生产中可以维护两组完整的IP列表,通过注释/取消注释来切换。
更优雅的方式:双upstream + map
upstream green {
server 10.0.1.10:9000;
server 10.0.1.11:9000;
}
upstream blue {
server 10.0.2.10:9000;
server 10.0.2.11:9000;
}
# 通过map变量控制
map $cookie_blu_gren $backend {
default green; # 默认绿色
blue blue; # 通过Cookie切换到蓝色
}
server {
# ...
location ~ \.php$ {
fastcgi_pass $backend;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
切换时只需设置Cookie Set-Cookie: blu_gren=blue,或者使用Lua/OpenResty动态从Redis/Etcd读取状态。
基于HAProxy的切换(适合高并发)
haproxy.cfg 配置
frontend php_front
bind *:80
default_backend php_green
backend php_green
balance roundrobin
server node1 10.0.1.10:9000 check weight 10
server node2 10.0.1.11:9000 check weight 10
backend php_blue
balance roundrobin
server node1 10.0.2.10:9000 check weight 10
server node2 10.0.2.11:9000 check weight 10
切换命令(无需重启)
# 切换到蓝组 echo "set weight php_blue/node1 10" | socat /var/run/haproxy.sock stdio echo "set weight php_blue/node2 10" | socat /var/run/haproxy.sock stdio echo "set weight php_green/node1 0" | socat /var/run/haproxy.sock stdio echo "set weight php_green/node2 0" | socat /var/run/haproxy.sock stdio # 或者更彻底:修改default_backend(需reload但几乎无中断) echo "set weight php_blue/node1 10" | socat /var/run/haproxy.sock stdio echo "set weight php_blue/node2 10" | socat /var/run/haproxy.sock stdio echo "disable backend php_green" | socat /var/run/haproxy.sock stdio
更推荐:使用Runtime API实现平滑切换
# 用Python脚本通过API控制
import subprocess
def switch_to_blue():
commands = [
"disable backend php_green",
"enable backend php_blue"
]
for cmd in commands:
subprocess.run(['socat', '/var/run/haproxy.sock', '-'], input=cmd + '\n', text=True)
基于Kubernetes Service的切换(容器化PHP)
创建两个Deployment + 两个Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-app-green
labels:
app: php-app
color: green
spec:
replicas: 2
selector:
matchLabels:
app: php-app
color: green
template:
metadata:
labels:
app: php-app
color: green
spec:
containers:
- name: php-fpm
image: myapp:green-v1
---
apiVersion: v1
kind: Service
metadata:
name: php-app-green-svc
spec:
selector:
app: php-app
color: green
ports:
- port: 9000
类似地创建 php-app-blue 和 php-app-blue-svc。
入口Ingress切换
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: php-app-ingress
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: php-app-green-svc # 切换时改为 blue-svc
port:
number: 9000
一键切换命令
# 切换到蓝色
kubectl patch ingress php-app-ingress -p '{"spec":{"rules":[{"host":"app.example.com","http":{"paths":[{"path":"/","pathType":"Prefix","backend":{"service":{"name":"php-app-blue-svc","port":{"number":9000}}}}]}}]}}'
# 或者使用kubectl edit手动修改
kubectl edit ingress php-app-ingress
基于DNS的切换(相对粗粒度)
- 为两组节点配置不同A记录:
green.app.example.com→ 绿组节点IP列表blue.app.example.com→ 蓝组节点IP列表
- 生产域名
app.example.com的CNAME指向green或blue - 降低DNS TTL到60-120秒
缺点:DNS缓存导致切换延迟不可控,不建议用于关键业务。
切换时的关键注意事项
| 要点 | 说明 |
|---|---|
| Session共享 | PHP Session必须存储在外部(Redis/Memcached),不能依赖本地文件 |
| 数据库兼容 | 新版本代码必须兼容当前数据库结构(或使用读写分离+渐进式迁移) |
| 缓存清理 | 切换后若代码变更,需要清除OPcache(opcache_reset() 或重启PHP-FPM) |
| 健康检查 | 负载均衡器必须配置对新组的健康检查(HTTP 200或PHP探针) |
| 灰度验证 | 推荐先切换部分流量(5%-10%)观察5-10分钟,再全量切换 |
| 回滚预案 | 保留回滚脚本或一键恢复命令,确保切换失败时60秒内恢复 |
推荐实践:最小中断切换流水线
graph LR
A[部署蓝组] --> B[运行自动化测试]
B --> C[健康检查通过?]
C -->|Yes| D[负载均衡切换]
C -->|No| E[回滚]
D --> F[观察5分钟]
F --> G[正常?]
G -->|Yes| H[下线绿组]
G -->|No| I[切回绿组]
E --> J[修复]
I --> J
J --> A
- 中小项目:Nginx upstream配置热加载(方案一)最简单直接
- 高并发/复杂路由:HAProxy + Runtime API(方案二)更灵活
- K8s环境:Ingress + Service切换(方案三)最优雅
- 最重要:无论哪种方案,Session和缓存的外部化 是蓝绿发布成功的前提
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播