Nginx 负载均衡 + Keepalived 高可用部署教程

一、目标

在两台 Ubuntu 24.04 服务器上部署一套高可用入口架构:

  • 两台 Nginx 互为备份,通过 Keepalived 维护一个 VIP
  • VIP 始终在主节点上,主节点挂了,VIP 自动漂移到备节点
  • 用户只访问 VIP,感知不到后端切换
  • 后端挂掉时,Nginx 自动把请求转到健康的后端

二、环境信息

项目server1server2
操作系统Ubuntu 24.04.4 LTSUbuntu 24.04.4 LTS
IP192.168.136.134192.168.136.155
网卡名ens33ens33
角色Nginx 主 + Keepalived MASTERNginx 备 + Keepalived BACKUP
  • VIP:192.168.136.200/24
  • 后端服务:Ech0(轻量开源社区系统,Docker 部署)

三、架构图

                    ┌─────────────────┐
                    │   用户请求       │
                    └────────┬────────┘
                             │
                    ┌────────▼────────┐
                    │   VIP            │
                    │  192.168.136.200 │
                    └────────┬────────┘
                             │
              ┌──────────────┴──────────────┐
              │                             │
     ┌────────▼────────┐          ┌────────▼────────┐
     │  Nginx Master   │          │  Nginx Backup   │
     │  192.168.136.134 │          │  192.168.136.155 │
     │  (Keepalived)   │          │  (Keepalived)   │
     └────────┬────────┘          └────────┬────────┘
              │                             │
              └──────────────┬──────────────┘
                             │
              ┌──────────────┴──────────────┐
              │                             │
     ┌────────▼────────┐          ┌────────▼────────┐
     │  Ech0 实例 1     │          │  Ech0 实例 2     │
     │  134:6277        │          │  155:6277        │
     └─────────────────┘          └─────────────────┘

四、部署步骤

第 1 步:基础环境准备(两台都做)

sudo apt update && sudo apt upgrade -y
sudo apt install -y nginx keepalived

nginx -v
keepalived --version
ip addr | grep ens33
⚠️ 注意apt upgrade 时可能弹出键盘布局和字符集选择。终端不支持图形对话框时,用键盘选:布局选 34(English UK),字符集选 14(Latin1)。

第 2 步:配置 Nginx 负载均衡(两台一样)

sudo rm -f /etc/nginx/sites-enabled/default
sudo vim /etc/nginx/conf.d/lb.conf

写入以下内容:

upstream backend {
    ip_hash;

    server 192.168.136.134:6277 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.136.155:6277 weight=1 max_fails=3 fail_timeout=30s;

    keepalive 32;
}

server {
    listen 80;
    server_name _;
    client_max_body_size 200m;

    location / {
        proxy_pass http://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_next_upstream error timeout http_502 http_503 http_504;
        proxy_connect_timeout 5s;
        proxy_read_timeout 60s;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location /health {
        access_log off;
        return 200 "OK\n";
    }
}

参数说明

  • ip_hash:同一客户端固定访问同一后端,解决会话保持问题
  • max_fails=3 fail_timeout=30s:连续失败 3 次标记为不可用,30 秒后重新探测
  • proxy_next_upstream:后端返回 502/503/504 或超时,自动转下一个后端
  • keepalive 32:与后端保持 32 个长连接,减少握手开销

验证并重启:

sudo nginx -t
sudo systemctl restart nginx
curl http://192.168.136.134/health   # 应返回 OK

第 3 步:配置 Keepalived

server1(主节点)

sudo vim /etc/keepalived/keepalived.conf
global_defs {
    router_id nginx_master
    enable_script_security
    script_user root
}

vrrp_script check_nginx {
    script "/usr/bin/killall -0 nginx"
    interval 2
    weight -20
    fall 2
    rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface ens33
    virtual_router_id 51
    priority 100
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass 1111
    }

    virtual_ipaddress {
        192.168.136.200/24
    }

    track_script {
        check_nginx
    }
}

server2(备节点),只有三处不同:

global_defs {
    router_id nginx_backup      # 不同
    enable_script_security
    script_user root
}

vrrp_script check_nginx {
    script "/usr/bin/killall -0 nginx"
    interval 2
    weight -20
    fall 2
    rise 2
}

vrrp_instance VI_1 {
    state BACKUP                # 不同
    interface ens33
    virtual_router_id 51        # 必须一致
    priority 90                 # 不同
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass 1111
    }

    virtual_ipaddress {
        192.168.136.200/24
    }

    track_script {
        check_nginx
    }
}

参数说明

  • state:初始角色,MASTER / BACKUP
  • virtual_router_id:VRRP 组 ID,两台必须一致
  • priority:优先级,主节点高、备节点低,决定谁是 MASTER
  • advert_int 1:每秒发一次心跳
  • authentication:VRRP 认证密码,两台必须一致
  • vrrp_script:每 2 秒检测 Nginx 进程,连续失败 2 次降权 20

启动并设置开机自启:

sudo systemctl enable keepalived
sudo systemctl restart keepalived
sudo systemctl status keepalived
⚠️ 注意:Ubuntu 24.04 默认只带 keepalived.conf.sample,没有 keepalived.conf,需要手动创建。

第 4 步:部署后端 Ech0(两台都做)

docker run -d \
  --name ech0 \
  --restart unless-stopped \
  -p 6277:6277 \
  -v /opt/ech0/data:/app/data \
  -e JWT_SECRET="请替换为强密钥" \
  sn0wl1n/ech0:latest

验证:

curl -I http://localhost:6277
# 应返回 200 OK,X-Powered-By: Ech0/5.7.0

第 5 步:接入 Nginx

确认 upstream 里的端口与 Ech0 一致(默认 6277),重载 Nginx:

sudo nginx -t && sudo systemctl reload nginx

五、验证

5.1 验证 VIP 漂移

查看当前 VIP 位置

ip addr show ens33 | grep 192.168.136.200

预期:server1 上能看到 VIP,server2 上看不到。

模拟主节点故障

# 在 server1 上停掉 keepalived
sudo systemctl stop keepalived

再次查看 VIP

# 在 server2 上执行
ip addr show ens33 | grep 192.168.136.200

预期:VIP 出现在 server2 上。

恢复主节点

# 在 server1 上启动 keepalived
sudo systemctl start keepalived

预期:VIP 回到 server1。

5.2 验证负载均衡

for i in {1..6}; do curl -I -s http://192.168.136.200 | head -1; done

如果配置的是 ip_hash,同一客户端会固定访问同一后端;如果配置的是 least_conn,请求会在两个后端间轮询。

5.3 验证后端故障转移

停掉一个后端

# 在 server2 上执行
docker stop ech0

访问 VIP

curl -I http://192.168.136.200

预期:仍然返回 200 OK,请求自动转到 server1。

恢复后端

docker start ech0

六、常见问题

Q1:keepalived.conf 不存在

Ubuntu 24.04 默认只带 .sample 文件,手动创建 keepalived.conf 即可。

Q2:apt upgrade 弹交互界面

终端不支持图形对话框时,用键盘选:布局选 34(English UK),字符集选 14(Latin1)。

Q3:VIP 漂移后账号丢失

这是有状态服务的数据不共享问题。两台后端各自存数据,切换后会话不保留。解决方案:

  • 短期:用 ip_hash 让同一用户固定访问同一后端
  • 长期:换支持外部数据库的服务(如 WordPress + MySQL),或引入 Redis 存 session

Q4:Nginx 后端故障转移不生效

检查 proxy_next_upstream 是否包含 errortimeouthttp_502http_503http_504,以及 max_failsfail_timeout 是否配置正确。

七、关键配置文件速查

文件路径
Nginx 负载均衡配置/etc/nginx/conf.d/lb.conf
Keepalived 配置/etc/keepalived/keepalived.conf
Nginx 访问日志/var/log/nginx/access.log
Keepalived 日志sudo journalctl -u keepalived
Ech0 容器日志docker logs -f ech0

八、常用运维命令

# 查看 VIP 位置
ip addr show ens33 | grep 192.168.136.200

# 重载 Nginx
sudo nginx -t && sudo systemctl reload nginx

# 重启 Keepalived
sudo systemctl restart keepalived

# 查看 Keepalived 状态
sudo systemctl status keepalived

# 查看 Keepalived 日志
sudo journalctl -u keepalived -n 30 --no-pager

# 查看后端容器
docker ps | grep ech0

# 停 / 启后端
docker stop ech0
docker start ech0

# 连续访问 VIP 测试
for i in {1..6}; do curl -I -s http://192.168.136.200 | head -1; done

九、注意事项

  • virtual_router_idauth_pass 两台必须一致,否则 VRRP 无法通信
  • priority 主节点必须高于备节点
  • 后端服务的数据不共享,切换时会话会丢失,这是架构层面的限制
  • VIP 只适合同局域网,跨机房需要 DNS 或 GSLB