Skip to content

使用蓝绿部署进行服务不中断更新

前言

在生产环境中,服务更新是一个高风险操作。传统的部署方式(直接替换运行中的服务)存在以下问题:

  • 服务中断:部署过程中服务不可用,影响用户体验
  • 回滚困难:如果新版本有问题,回滚需要时间,可能导致更长的服务中断
  • 风险高:一旦部署失败,可能造成生产事故
  • 影响范围大:所有用户同时受到影响

蓝绿部署(Blue-Green Deployment)是一种零停机时间的部署策略,通过维护两个完全相同的生产环境(蓝色和绿色)来实现:

  • 零停机时间:切换流量时用户无感知
  • 快速回滚:出现问题可以立即切回旧版本
  • 降低风险:新版本可以在绿色环境充分测试后再切换
  • 平滑过渡:流量切换是瞬间完成的

蓝绿部署原理

蓝绿部署的核心思想是:

  1. 蓝色环境(Blue):当前正在运行的生产环境,处理所有用户流量
  2. 绿色环境(Green):新版本部署的环境,与蓝色环境完全隔离
  3. 流量切换:通过负载均衡器或反向代理,将流量从蓝色切换到绿色
  4. 回滚机制:如果绿色环境有问题,可以立即切回蓝色环境
部署前:
用户请求 → 负载均衡器 → 蓝色环境(旧版本,运行中)

部署新版本到绿色环境:
用户请求 → 负载均衡器 → 蓝色环境(旧版本,运行中)

                    绿色环境(新版本,已部署,未接收流量)

切换流量:
用户请求 → 负载均衡器 → 绿色环境(新版本,接收所有流量)

                    蓝色环境(旧版本,保留作为回滚备份)

部署架构假设

本文以 Nginx + 应用服务为例,假设以下目录结构:

text
/home/app/
├── blue/              # 蓝色环境(当前生产环境)
│   ├── app.jar        # 应用文件
│   ├── config/        # 配置文件
│   └── logs/          # 日志目录
├── green/             # 绿色环境(新版本环境)
│   ├── app.jar        # 应用文件
│   ├── config/        # 配置文件
│   └── logs/          # 日志目录
└── nginx/
    └── conf.d/
        └── app.conf   # Nginx 配置文件

重要提示:在实际部署前,请根据你的实际环境调整路径和配置。

详细部署步骤

第一步:准备工作(必须执行)

1.1 备份当前环境

⚠️ 警告:部署前必须备份,这是回滚的基础!

bash
# 创建备份目录
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.info

1.2 检查蓝色环境状态

⚠️ 必须确保蓝色环境正常运行,否则不要进行部署!

bash
# 检查应用进程是否运行
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 准备绿色环境目录

bash
# 如果绿色环境目录已存在,先清理(谨慎操作)
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 上传新版本文件

bash
# 方式一:使用 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.jar

2.2 复制配置文件

⚠️ 重要:配置文件可能需要根据新版本调整,请仔细检查!

bash
# 复制蓝色环境的配置文件到绿色环境(作为基础)
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 端口:

bash
# 修改配置文件中的端口
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 设置文件权限

bash
# 确保应用文件有执行权限
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 启动应用

bash
# 切换到绿色环境目录
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 服务文件示例:

ini
[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
bash
# 加载服务配置
sudo systemctl daemon-reload

# 启动绿色环境
sudo systemctl start app-green

# 检查启动状态
sudo systemctl status app-green

3.2 验证绿色环境启动成功

⚠️ 必须验证绿色环境完全启动并正常运行,才能进行流量切换!

bash
# 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 配置

bash
# 备份当前配置
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 配置文件:

bash
sudo vim /etc/nginx/conf.d/app.conf

配置示例(使用 upstream 实现流量切换):

nginx
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 配置

⚠️ 必须测试配置语法,错误的配置会导致服务中断!

bash
# 测试 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 灰度切换(推荐,降低风险)

⚠️ 建议先进行灰度切换,观察一段时间后再全量切换!

bash
# 修改 Nginx 配置,将 10% 流量切换到绿色环境
sudo vim /etc/nginx/conf.d/app.conf
nginx
upstream app_backend {
    # 蓝色环境接收 90% 流量
    server 127.0.0.1:8080 weight=90;
    # 绿色环境接收 10% 流量
    server 127.0.0.1:8081 weight=10;
}
bash
# 测试配置
sudo nginx -t

# 重新加载 Nginx(不中断服务)
sudo nginx -s reload

# 观察绿色环境日志和指标
tail -f /home/app/green/logs/app.log

观察 10-30 分钟,确认绿色环境运行正常:

bash
# 监控绿色环境错误日志
tail -f /home/app/green/logs/app.log | grep -i error

# 监控绿色环境性能指标(如果有监控系统)
# 检查响应时间、错误率、CPU、内存等

5.2 全量切换到绿色环境

⚠️ 只有在灰度切换观察无问题后,才能进行全量切换!

bash
# 修改 Nginx 配置,将所有流量切换到绿色环境
sudo vim /etc/nginx/conf.d/app.conf
nginx
upstream app_backend {
    # 绿色环境接收所有流量
    server 127.0.0.1:8081 weight=100;
    # 蓝色环境保留但不接收流量(作为回滚备份)
    server 127.0.0.1:8080 weight=0 backup;
}
bash
# 测试配置
sudo nginx -t

# 重新加载 Nginx
sudo nginx -s reload

# 立即验证服务是否正常
curl http://your-domain.com/health

5.3 验证切换成功

⚠️ 切换后必须验证服务正常运行!

bash
# 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 分钟)

bash
# 监控绿色环境日志
tail -f /home/app/green/logs/app.log

# 监控系统资源
top
# 或
htop

# 监控网络连接
netstat -an | grep 8081 | wc -l

6.2 确认部署成功

在以下情况下,可以确认部署成功:

  • ✅ 绿色环境运行稳定,无错误日志
  • ✅ 所有关键功能测试通过
  • ✅ 系统资源使用正常
  • ✅ 用户反馈正常(如果有用户反馈渠道)
  • ✅ 监控指标正常(响应时间、错误率等)

6.3 清理蓝色环境(可选,建议保留 24 小时)

⚠️ 建议保留蓝色环境至少 24 小时,作为回滚备份!

bash
# 24 小时后,如果确认新版本稳定,可以停止蓝色环境
sudo systemctl stop app-blue

# 如果需要完全清理(谨慎操作)
# sudo systemctl disable app-blue
# sudo rm -rf /home/app/blue

回滚方案

⚠️ 如果新版本出现问题,必须能够快速回滚!

快速回滚步骤

1. 立即切回蓝色环境

bash
# 修改 Nginx 配置,切回蓝色环境
sudo vim /etc/nginx/conf.d/app.conf
nginx
upstream app_backend {
    # 切回蓝色环境
    server 127.0.0.1:8080 weight=100;
    # 绿色环境停止接收流量
    # server 127.0.0.1:8081 weight=0;
}
bash
# 测试配置
sudo nginx -t

# 重新加载 Nginx(立即生效)
sudo nginx -s reload

# 验证回滚成功
curl http://your-domain.com/health

2. 停止绿色环境

bash
# 停止绿色环境服务
sudo systemctl stop app-green

# 确认停止
sudo systemctl status app-green

3. 记录回滚原因

bash
# 记录回滚信息
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

注意事项和最佳实践

⚠️ 关键注意事项

  1. 必须备份:部署前必须完整备份当前环境
  2. 必须验证:每个步骤后都要验证,确保成功
  3. 必须测试配置:Nginx 配置修改后必须测试语法
  4. 必须监控:切换后必须持续监控至少 30 分钟
  5. 必须保留备份:蓝色环境至少保留 24 小时作为回滚备份
  6. 必须准备回滚方案:部署前就要准备好回滚步骤

✅ 最佳实践

  1. 使用灰度发布:先切换少量流量,观察无问题后再全量切换
  2. 选择低峰期部署:在用户访问量低的时间段进行部署
  3. 自动化脚本:将部署步骤写成脚本,减少人为错误
  4. 监控告警:设置监控告警,及时发现问题
  5. 文档记录:记录每次部署的版本、时间、操作人员等信息
  6. 演练回滚:定期演练回滚流程,确保能够快速回滚

📋 部署检查清单

部署前检查:

  • [ ] 已备份当前环境
  • [ ] 已检查蓝色环境运行状态
  • [ ] 已准备新版本文件
  • [ ] 已检查配置文件
  • [ ] 已确认端口不冲突
  • [ ] 已准备回滚方案

部署中检查:

  • [ ] 绿色环境启动成功
  • [ ] 绿色环境健康检查通过
  • [ ] 绿色环境功能测试通过
  • [ ] Nginx 配置语法正确
  • [ ] 灰度切换后观察无异常

部署后检查:

  • [ ] 全量切换成功
  • [ ] 服务运行正常
  • [ ] 无错误日志
  • [ ] 监控指标正常
  • [ ] 用户反馈正常

自动化部署脚本示例

为了减少人为错误,可以将部署步骤写成脚本。以下是简化示例:

bash
#!/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

⚠️ 脚本使用提示:

  1. 脚本只是示例,必须根据实际环境修改
  2. 使用前请在测试环境充分测试
  3. 建议先手动执行一次,确认流程正确后再使用脚本
  4. 脚本中的关键操作建议保留人工确认步骤

总结

蓝绿部署是一种可靠的零停机部署策略,通过以下关键步骤实现:

  1. 充分准备:备份、检查、准备环境
  2. 隔离部署:在绿色环境部署新版本,不影响蓝色环境
  3. 验证测试:确保绿色环境完全正常
  4. 平滑切换:通过 Nginx 等负载均衡器切换流量
  5. 持续监控:切换后持续观察,及时发现问题
  6. 快速回滚:出现问题立即切回蓝色环境

记住:部署过程一定要仔细、谨慎,每个步骤都要验证,这是避免运维事故的关键!