使用蓝绿部署进行服务不中断更新
前言
在生产环境中,服务更新是一个高风险操作。传统的部署方式(直接替换运行中的服务)存在以下问题:
- 服务中断:部署过程中服务不可用,影响用户体验
- 回滚困难:如果新版本有问题,回滚需要时间,可能导致更长的服务中断
- 风险高:一旦部署失败,可能造成生产事故
- 影响范围大:所有用户同时受到影响
蓝绿部署(Blue-Green Deployment)是一种零停机时间的部署策略,通过维护两个完全相同的生产环境(蓝色和绿色)来实现:
- 零停机时间:切换流量时用户无感知
- 快速回滚:出现问题可以立即切回旧版本
- 降低风险:新版本可以在绿色环境充分测试后再切换
- 平滑过渡:流量切换是瞬间完成的
蓝绿部署原理
蓝绿部署的核心思想是:
- 蓝色环境(Blue):当前正在运行的生产环境,处理所有用户流量
- 绿色环境(Green):新版本部署的环境,与蓝色环境完全隔离
- 流量切换:通过负载均衡器或反向代理,将流量从蓝色切换到绿色
- 回滚机制:如果绿色环境有问题,可以立即切回蓝色环境
部署前:
用户请求 → 负载均衡器 → 蓝色环境(旧版本,运行中)
部署新版本到绿色环境:
用户请求 → 负载均衡器 → 蓝色环境(旧版本,运行中)
↓
绿色环境(新版本,已部署,未接收流量)
切换流量:
用户请求 → 负载均衡器 → 绿色环境(新版本,接收所有流量)
↓
蓝色环境(旧版本,保留作为回滚备份)部署架构假设
本文以 Nginx + 应用服务为例,假设以下目录结构:
/home/app/
├── blue/ # 蓝色环境(当前生产环境)
│ ├── app.jar # 应用文件
│ ├── config/ # 配置文件
│ └── logs/ # 日志目录
├── green/ # 绿色环境(新版本环境)
│ ├── app.jar # 应用文件
│ ├── config/ # 配置文件
│ └── logs/ # 日志目录
└── nginx/
└── conf.d/
└── app.conf # Nginx 配置文件重要提示:在实际部署前,请根据你的实际环境调整路径和配置。
详细部署步骤
第一步:准备工作(必须执行)
1.1 备份当前环境
⚠️ 警告:部署前必须备份,这是回滚的基础!
# 创建备份目录
sudo mkdir -p /home/app/backup/$(date +%Y%m%d_%H%M%S)
# 备份蓝色环境
sudo cp -r /home/app/blue /home/app/backup/$(date +%Y%m%d_%H%M%S)/blue
# 备份 Nginx 配置
sudo cp /etc/nginx/conf.d/app.conf /home/app/backup/$(date +%Y%m%d_%H%M%S)/app.conf
# 记录当前运行的版本信息(用于回滚时确认)
echo "Blue Environment Version: $(cat /home/app/blue/VERSION 2>/dev/null || echo 'unknown')" > /home/app/backup/$(date +%Y%m%d_%H%M%S)/version.info
echo "Deployment Time: $(date)" >> /home/app/backup/$(date +%Y%m%d_%H%M%S)/version.info1.2 检查蓝色环境状态
⚠️ 必须确保蓝色环境正常运行,否则不要进行部署!
# 检查应用进程是否运行
ps aux | grep -i "app.jar" | grep -v grep
# 检查应用端口是否监听(假设应用端口是 8080)
netstat -tlnp | grep 8080
# 或使用 ss 命令
ss -tlnp | grep 8080
# 检查应用健康状态(如果有健康检查接口)
curl http://localhost:8080/health
# 或
curl http://localhost:8080/actuator/health
# 检查应用日志是否有错误
tail -n 100 /home/app/blue/logs/app.log | grep -i error如果发现任何异常,立即停止部署流程,先解决问题!
1.3 准备绿色环境目录
# 如果绿色环境目录已存在,先清理(谨慎操作)
if [ -d "/home/app/green" ]; then
echo "⚠️ 绿色环境目录已存在,是否清理?(yes/no)"
read -r confirm
if [ "$confirm" = "yes" ]; then
sudo rm -rf /home/app/green
echo "✅ 已清理旧绿色环境"
else
echo "❌ 取消部署"
exit 1
fi
fi
# 创建绿色环境目录结构
sudo mkdir -p /home/app/green/{config,logs}
sudo chown -R app:app /home/app/green第二步:部署新版本到绿色环境
2.1 上传新版本文件
# 方式一:使用 scp 上传(从本地)
scp app-v2.0.0.jar user@server:/home/app/green/app.jar
# 方式二:使用 rsync 同步(推荐,支持断点续传)
rsync -avz --progress app-v2.0.0.jar user@server:/home/app/green/app.jar
# 方式三:如果文件已经在服务器上
sudo cp /tmp/app-v2.0.0.jar /home/app/green/app.jar2.2 复制配置文件
⚠️ 重要:配置文件可能需要根据新版本调整,请仔细检查!
# 复制蓝色环境的配置文件到绿色环境(作为基础)
sudo cp -r /home/app/blue/config/* /home/app/green/config/
# 检查配置文件,根据新版本需求进行修改
sudo vim /home/app/green/config/application.properties
# 或
sudo vim /home/app/green/config/application.yml
# 特别注意以下配置项:
# - 数据库连接(如果新版本需要新的数据库)
# - 端口号(绿色环境必须使用不同的端口,例如 8081)
# - 日志路径
# - 缓存配置2.3 修改绿色环境端口
⚠️ 关键:绿色环境必须使用不同的端口,避免与蓝色环境冲突!
假设蓝色环境使用 8080 端口,绿色环境使用 8081 端口:
# 修改配置文件中的端口
sudo sed -i 's/server.port=8080/server.port=8081/g' /home/app/green/config/application.properties
# 或者如果使用 yml 格式
sudo sed -i 's/port: 8080/port: 8081/g' /home/app/green/config/application.yml
# 验证端口配置
grep -E "port|PORT" /home/app/green/config/application.*2.4 设置文件权限
# 确保应用文件有执行权限
sudo chmod +x /home/app/green/app.jar
# 确保日志目录有写权限
sudo chmod 755 /home/app/green/logs
sudo chown -R app:app /home/app/green第三步:启动绿色环境
3.1 启动应用
# 切换到绿色环境目录
cd /home/app/green
# 启动应用(根据实际启动方式调整)
# 方式一:直接运行
sudo -u app nohup java -jar app.jar --spring.config.location=config/application.properties > logs/startup.log 2>&1 &
# 方式二:使用 systemd 服务(推荐)
# 首先创建绿色环境的 systemd 服务文件
sudo vim /etc/systemd/system/app-green.service绿色环境的 systemd 服务文件示例:
[Unit]
Description=Application Green Environment
After=network.target
[Service]
Type=simple
User=app
Group=app
WorkingDirectory=/home/app/green
ExecStart=/usr/bin/java -jar /home/app/green/app.jar --spring.config.location=/home/app/green/config/application.properties
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target# 加载服务配置
sudo systemctl daemon-reload
# 启动绿色环境
sudo systemctl start app-green
# 检查启动状态
sudo systemctl status app-green3.2 验证绿色环境启动成功
⚠️ 必须验证绿色环境完全启动并正常运行,才能进行流量切换!
# 1. 检查进程是否运行
ps aux | grep "app.jar" | grep 8081
# 2. 检查端口是否监听
netstat -tlnp | grep 8081
# 或
ss -tlnp | grep 8081
# 3. 检查健康状态(等待应用完全启动,通常需要 30-60 秒)
sleep 30
curl http://localhost:8081/health
# 或
curl http://localhost:8081/actuator/health
# 4. 检查应用日志
tail -f /home/app/green/logs/app.log
# 5. 测试关键功能(根据实际业务调整)
curl http://localhost:8081/api/test如果绿色环境启动失败或健康检查不通过,立即停止部署,检查问题!
第四步:配置 Nginx 进行流量切换
4.1 备份当前 Nginx 配置
# 备份当前配置
sudo cp /etc/nginx/conf.d/app.conf /etc/nginx/conf.d/app.conf.backup.$(date +%Y%m%d_%H%M%S)4.2 配置 Nginx upstream
编辑 Nginx 配置文件:
sudo vim /etc/nginx/conf.d/app.conf配置示例(使用 upstream 实现流量切换):
upstream app_backend {
# 当前指向蓝色环境(8080端口)
server 127.0.0.1:8080 weight=100;
# 绿色环境(8081端口)暂时不接收流量,weight=0
# server 127.0.0.1:8081 weight=0;
}
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://app_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}4.3 测试 Nginx 配置
⚠️ 必须测试配置语法,错误的配置会导致服务中断!
# 测试 Nginx 配置语法
sudo nginx -t
# 如果测试通过,会显示:
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful如果测试失败,不要执行 reload,先修复配置!
第五步:执行流量切换
5.1 灰度切换(推荐,降低风险)
⚠️ 建议先进行灰度切换,观察一段时间后再全量切换!
# 修改 Nginx 配置,将 10% 流量切换到绿色环境
sudo vim /etc/nginx/conf.d/app.confupstream app_backend {
# 蓝色环境接收 90% 流量
server 127.0.0.1:8080 weight=90;
# 绿色环境接收 10% 流量
server 127.0.0.1:8081 weight=10;
}# 测试配置
sudo nginx -t
# 重新加载 Nginx(不中断服务)
sudo nginx -s reload
# 观察绿色环境日志和指标
tail -f /home/app/green/logs/app.log观察 10-30 分钟,确认绿色环境运行正常:
# 监控绿色环境错误日志
tail -f /home/app/green/logs/app.log | grep -i error
# 监控绿色环境性能指标(如果有监控系统)
# 检查响应时间、错误率、CPU、内存等5.2 全量切换到绿色环境
⚠️ 只有在灰度切换观察无问题后,才能进行全量切换!
# 修改 Nginx 配置,将所有流量切换到绿色环境
sudo vim /etc/nginx/conf.d/app.confupstream app_backend {
# 绿色环境接收所有流量
server 127.0.0.1:8081 weight=100;
# 蓝色环境保留但不接收流量(作为回滚备份)
server 127.0.0.1:8080 weight=0 backup;
}# 测试配置
sudo nginx -t
# 重新加载 Nginx
sudo nginx -s reload
# 立即验证服务是否正常
curl http://your-domain.com/health5.3 验证切换成功
⚠️ 切换后必须验证服务正常运行!
# 1. 检查 Nginx 状态
sudo systemctl status nginx
# 2. 检查绿色环境是否接收流量
tail -f /home/app/green/logs/app.log
# 3. 测试关键接口
curl http://your-domain.com/api/test
# 4. 检查错误日志
tail -n 100 /home/app/green/logs/app.log | grep -i error
# 5. 监控系统指标(响应时间、错误率等)第六步:观察和确认
6.1 持续监控(至少 30 分钟)
# 监控绿色环境日志
tail -f /home/app/green/logs/app.log
# 监控系统资源
top
# 或
htop
# 监控网络连接
netstat -an | grep 8081 | wc -l6.2 确认部署成功
在以下情况下,可以确认部署成功:
- ✅ 绿色环境运行稳定,无错误日志
- ✅ 所有关键功能测试通过
- ✅ 系统资源使用正常
- ✅ 用户反馈正常(如果有用户反馈渠道)
- ✅ 监控指标正常(响应时间、错误率等)
6.3 清理蓝色环境(可选,建议保留 24 小时)
⚠️ 建议保留蓝色环境至少 24 小时,作为回滚备份!
# 24 小时后,如果确认新版本稳定,可以停止蓝色环境
sudo systemctl stop app-blue
# 如果需要完全清理(谨慎操作)
# sudo systemctl disable app-blue
# sudo rm -rf /home/app/blue回滚方案
⚠️ 如果新版本出现问题,必须能够快速回滚!
快速回滚步骤
1. 立即切回蓝色环境
# 修改 Nginx 配置,切回蓝色环境
sudo vim /etc/nginx/conf.d/app.confupstream app_backend {
# 切回蓝色环境
server 127.0.0.1:8080 weight=100;
# 绿色环境停止接收流量
# server 127.0.0.1:8081 weight=0;
}# 测试配置
sudo nginx -t
# 重新加载 Nginx(立即生效)
sudo nginx -s reload
# 验证回滚成功
curl http://your-domain.com/health2. 停止绿色环境
# 停止绿色环境服务
sudo systemctl stop app-green
# 确认停止
sudo systemctl status app-green3. 记录回滚原因
# 记录回滚信息
echo "Rollback Time: $(date)" >> /home/app/backup/rollback.log
echo "Rollback Reason: [填写回滚原因]" >> /home/app/backup/rollback.log
echo "Green Environment Version: $(cat /home/app/green/VERSION 2>/dev/null || echo 'unknown')" >> /home/app/backup/rollback.log注意事项和最佳实践
⚠️ 关键注意事项
- 必须备份:部署前必须完整备份当前环境
- 必须验证:每个步骤后都要验证,确保成功
- 必须测试配置:Nginx 配置修改后必须测试语法
- 必须监控:切换后必须持续监控至少 30 分钟
- 必须保留备份:蓝色环境至少保留 24 小时作为回滚备份
- 必须准备回滚方案:部署前就要准备好回滚步骤
✅ 最佳实践
- 使用灰度发布:先切换少量流量,观察无问题后再全量切换
- 选择低峰期部署:在用户访问量低的时间段进行部署
- 自动化脚本:将部署步骤写成脚本,减少人为错误
- 监控告警:设置监控告警,及时发现问题
- 文档记录:记录每次部署的版本、时间、操作人员等信息
- 演练回滚:定期演练回滚流程,确保能够快速回滚
📋 部署检查清单
部署前检查:
- [ ] 已备份当前环境
- [ ] 已检查蓝色环境运行状态
- [ ] 已准备新版本文件
- [ ] 已检查配置文件
- [ ] 已确认端口不冲突
- [ ] 已准备回滚方案
部署中检查:
- [ ] 绿色环境启动成功
- [ ] 绿色环境健康检查通过
- [ ] 绿色环境功能测试通过
- [ ] Nginx 配置语法正确
- [ ] 灰度切换后观察无异常
部署后检查:
- [ ] 全量切换成功
- [ ] 服务运行正常
- [ ] 无错误日志
- [ ] 监控指标正常
- [ ] 用户反馈正常
自动化部署脚本示例
为了减少人为错误,可以将部署步骤写成脚本。以下是简化示例:
#!/bin/bash
# 蓝绿部署脚本示例
# 使用前请根据实际环境修改配置
set -e # 遇到错误立即退出
# 配置变量
BLUE_DIR="/home/app/blue"
GREEN_DIR="/home/app/green"
BLUE_PORT=8080
GREEN_PORT=8081
APP_USER="app"
NGINX_CONF="/etc/nginx/conf.d/app.conf"
BACKUP_DIR="/home/app/backup/$(date +%Y%m%d_%H%M%S)"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查命令执行结果
check_result() {
if [ $? -eq 0 ]; then
log_info "$1 成功"
else
log_error "$1 失败"
exit 1
fi
}
# 备份函数
backup() {
log_info "开始备份..."
sudo mkdir -p "$BACKUP_DIR"
sudo cp -r "$BLUE_DIR" "$BACKUP_DIR/blue"
sudo cp "$NGINX_CONF" "$BACKUP_DIR/app.conf"
check_result "备份"
}
# 检查蓝色环境
check_blue() {
log_info "检查蓝色环境状态..."
if ! netstat -tlnp | grep -q ":$BLUE_PORT "; then
log_error "蓝色环境未运行在端口 $BLUE_PORT"
exit 1
fi
check_result "蓝色环境检查"
}
# 部署绿色环境
deploy_green() {
log_info "部署绿色环境..."
# 这里添加实际的部署逻辑
# 例如:复制文件、修改配置等
check_result "绿色环境部署"
}
# 启动绿色环境
start_green() {
log_info "启动绿色环境..."
sudo systemctl start app-green
sleep 10 # 等待启动
if netstat -tlnp | grep -q ":$GREEN_PORT "; then
log_info "绿色环境启动成功"
else
log_error "绿色环境启动失败"
exit 1
fi
}
# 切换流量
switch_traffic() {
log_info "切换流量到绿色环境..."
# 修改 Nginx 配置
# 这里需要根据实际配置格式修改
sudo nginx -t
check_result "Nginx 配置测试"
sudo nginx -s reload
check_result "流量切换"
}
# 主函数
main() {
log_info "开始蓝绿部署..."
backup
check_blue
deploy_green
start_green
switch_traffic
log_info "部署完成!请持续监控服务状态。"
}
# 执行主函数
main⚠️ 脚本使用提示:
- 脚本只是示例,必须根据实际环境修改
- 使用前请在测试环境充分测试
- 建议先手动执行一次,确认流程正确后再使用脚本
- 脚本中的关键操作建议保留人工确认步骤
总结
蓝绿部署是一种可靠的零停机部署策略,通过以下关键步骤实现:
- ✅ 充分准备:备份、检查、准备环境
- ✅ 隔离部署:在绿色环境部署新版本,不影响蓝色环境
- ✅ 验证测试:确保绿色环境完全正常
- ✅ 平滑切换:通过 Nginx 等负载均衡器切换流量
- ✅ 持续监控:切换后持续观察,及时发现问题
- ✅ 快速回滚:出现问题立即切回蓝色环境
记住:部署过程一定要仔细、谨慎,每个步骤都要验证,这是避免运维事故的关键!