Linux服务器零停机部署方案:蓝绿发布与Nginx平滑切换实操

Linux服务器零停机部署方案:蓝绿发布与Nginx平滑切换实操

部署新版本为什么会有停机时间?

传统的部署方式是:停止旧服务 → 替换代码 → 启动新服务。在这个过程中,服务不可用的时间窗口少则几秒,多则几分钟。对于有用户在线的业务,任何停机都意味着请求失败和用户流失。

零停机部署的核心思想是:新旧版本同时运行,流量平滑切换,切换完成后再关闭旧版本,用户感知不到任何中断。


一、蓝绿部署原理

蓝绿部署维护两套完全相同的生产环境:

  • 蓝环境(Blue):当前线上运行的版本
  • 绿环境(Green):准备上线的新版本

部署流程:在绿环境部署和测试新版本 → 将 Nginx 流量从蓝切换到绿 → 观察绿环境运行稳定 → 将蓝环境保留作为回滚备用。整个切换过程通过修改 Nginx upstream 实现,用户无感知。


二、Nginx upstream 蓝绿切换配置

假设应用有两个版本同时运行:

  • 蓝环境(当前版本):端口 3000
  • 绿环境(新版本):端口 3001
sudo nano /etc/nginx/sites-available/myapp
upstream app_blue {
    server 127.0.0.1:3000;
}

upstream app_green {
    server 127.0.0.1:3001;
}

# 当前激活的 upstream(修改这里实现切换)
upstream app_current {
    server 127.0.0.1:3000;  # 蓝环境
    # server 127.0.0.1:3001;  # 切换到绿环境时改这行
}

server {
    listen 80;
    server_name your-domain.com;

    location / {
        proxy_pass http://app_current;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

切换流量时,修改 app_current 中的端口,然后平滑重载 Nginx(不中断现有连接):

sudo nginx -t && sudo nginx -s reload

nginx -s reload 会优雅地处理完当前所有连接后再切换,不会中断正在处理的请求


三、编写蓝绿部署脚本

sudo nano /usr/local/bin/deploy.sh
#!/bin/bash
# 蓝绿部署脚本

APP_DIR="/home/youruser/myapp"
BLUE_PORT=3000
GREEN_PORT=3001
NGINX_CONF="/etc/nginx/sites-available/myapp"
LOG="/var/log/deploy.log"

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG"; }

# 判断当前激活的是哪个环境
CURRENT=$(grep -oP '(?<=server 127.0.0.1:)\d+' "$NGINX_CONF" | head -1) if [ "$CURRENT" = "$BLUE_PORT" ]; then ACTIVE="blue"; ACTIVE_PORT=$BLUE_PORT NEW="green"; NEW_PORT=$GREEN_PORT else ACTIVE="green"; ACTIVE_PORT=$GREEN_PORT NEW="blue"; NEW_PORT=$BLUE_PORT fi log "当前激活: $ACTIVE ($ACTIVE_PORT) → 准备切换到: $NEW ($NEW_PORT)" # 1. 在新环境端口启动新版本 log "拉取最新代码..." cd "$APP_DIR" && git pull origin main log "在 $NEW_PORT 端口启动新版本..." PORT=$NEW_PORT node server.js & NEW_PID=$! sleep 3 # 2. 健康检查 HEALTH=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:$NEW_PORT/health) if [ "$HEALTH" != "200" ]; then log "ERROR: 健康检查失败 (HTTP $HEALTH),回滚..." kill $NEW_PID 2>/dev/null
    exit 1
fi
log "健康检查通过 (HTTP $HEALTH)"

# 3. 切换 Nginx 流量
log "切换 Nginx 流量到 $NEW ($NEW_PORT)..."
sed -i "s/server 127.0.0.1:$ACTIVE_PORT/server 127.0.0.1:$NEW_PORT/" "$NGINX_CONF"
sudo nginx -t && sudo nginx -s reload

# 4. 停止旧版本(等待10秒让现有连接处理完)
log "等待旧版本连接处理完毕..."
sleep 10
log "停止旧版本 ($ACTIVE_PORT)..."
pkill -f "PORT=$ACTIVE_PORT" 2>/dev/null

log "部署完成!当前激活: $NEW ($NEW_PORT)"
sudo chmod +x /usr/local/bin/deploy.sh

四、systemd 服务的平滑重启(适合单实例应用)

对于使用 systemd 管理的服务,reloadrestart 更优雅:

# restart:立即停止再启动,有短暂停机
sudo systemctl restart myapp

# reload:发送 SIGHUP 信号,应用自行处理平滑重载
# 前提:应用代码需要处理 SIGHUP 信号
sudo systemctl reload myapp

# 对于 Gunicorn(Python),支持平滑重载:
sudo kill -HUP $(cat /run/gunicorn.pid)

五、简化方案:适合中小项目的滚动重启

如果业务规模不需要完整的蓝绿部署,可以用 Nginx 的 proxy_next_upstream + 多个 worker 进程实现简化版零停机:

# 使用 PM2 管理 Node.js 应用,支持零停机重载
pm2 reload myapp --update-env

# Gunicorn 热重载(替换 worker 进程,不中断请求)
kill -USR2 $(cat /run/gunicorn.pid)

总结

零停机部署的核心是:新版本先启动并通过健康检查 → Nginx 平滑切换流量(reload 不中断现有连接)→ 旧版本优雅退出。蓝绿部署适合有明确切换节点的场景,滚动重启适合快速迭代的中小项目。两种方案都可以将用户感知到的停机时间降至零。

需要稳定的香港服务器运行生产业务,IDC.Net 香港独立服务器提供独占资源,CN2 GIA 直连大陆,月付 299 元起,7×24 工单支持,支付宝 / USDT 付款。

Telegram