如何实现集群环境下的Tomcat自动化部署

集群环境下 Tomcat 自动化部署的核心是:Nginx 流量切分 + 分批滚动 + 健康检查 + 版本回滚 + 会话共享,全程零停机、可回滚、可审计。下面给你一套可直接落地的生产级方案。

一、生产环境必备前提(先做这几步)

1. Tomcat 集群基础配置

  • 关闭自动部署(避免误触发)
    xml
    <!-- conf/server.xml Host 节点 -->
    <Host name="localhost" appBase="webapps"
          autoDeploy="false" deployOnStartup="false"
          unpackWARs="true">
    
  • 开启 Manager 文本接口(用于脚本调用)
    xml
    <!-- conf/tomcat-users.xml -->
    <role rolename="manager-script"/>
    <user username="deploy" password="StrongPass123" roles="manager-script"/>
    
  • 会话共享(避免热部署时用户掉线)
    • 方案 1:Redis 存储 Session(推荐)
    • 方案 2:Tomcat 集群 Session 复制(小集群可用)

2. Nginx 负载均衡配置(关键)

nginx
# /etc/nginx/nginx.conf 或 sites-available/xxx
upstream tomcat_cluster {
    server 192.168.1.101:8080 max_fails=2 fail_timeout=30s;
    server 192.168.1.102:8080 max_fails=2 fail_timeout=30s;
    server 192.168.1.103:8080 max_fails=2 fail_timeout=30s;
    keepalive 64;
}

server {
    listen 80;
    location / {
        proxy_pass http://tomcat_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

二、自动化部署核心方案(3 种主流)

方案 1:Shell 脚本 + Nginx 流量切分(最通用)

1. 集群部署脚本(deploy_cluster.sh)

bash
运行
#!/bin/bash
# 集群零停机部署:Nginx 下线 → 部署 → 健康检查 → 上线
# 用法:./deploy_cluster.sh myapp /path/to/app.war

APP_NAME=$1
WAR_PATH=$2
# 集群节点列表
TOMCAT_NODES=("192.168.1.101:8080" "192.168.1.102:8080" "192.168.1.103:8080")
NGINX_CONF="/etc/nginx/nginx.conf"
DEPLOY_USER="deploy"
DEPLOY_PASS="StrongPass123"
BACKUP_DIR="/data/tomcat_backup/${APP_NAME}"
LOG_FILE="/var/log/deploy_${APP_NAME}_$(date +%Y%m%d).log"

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

# 1. Nginx 下线节点
nginx_offline() {
    local node=$1
    log "下线节点: $node"
    sed -i "s/server $node;/server $node backup;/g" $NGINX_CONF
    nginx -s reload
    sleep 3
}

# 2. Nginx 上线节点
nginx_online() {
    local node=$1
    log "上线节点: $node"
    sed -i "s/server $node backup;/server $node;/g" $NGINX_CONF
    nginx -s reload
}

# 3. 健康检查
health_check() {
    local node=$1
    local url="http://$node/$APP_NAME/health"
    log "健康检查: $url"
    for i in {1..10}; do
        code=$(curl -s -o /dev/null -w "%{http_code}" $url)
        if [ $code -eq 200 ]; then
            log "健康检查通过"
            return 0
        fi
        log "第 $i 次失败,5秒后重试"
        sleep 5
    done
    log "健康检查失败"
    return 1
}

# 4. 部署单个节点
deploy_node() {
    local node=$1
    local ip=$(echo $node | cut -d: -f1)
    local port=$(echo $node | cut -d: -f2)

    nginx_offline $node

    # 热部署
    deploy_result=$(curl -u $DEPLOY_USER:$DEPLOY_PASS \
        -T $WAR_PATH \
        "http://$ip:$port/manager/text/deploy?path=/$APP_NAME&update=true")

    if [[ $deploy_result != *OK* ]]; then
        log "部署失败: $deploy_result"
        nginx_online $node
        return 1
    fi

    # 健康检查
    if ! health_check $node; then
        log "回滚上一版本"
        last_war=$(ls -t $BACKUP_DIR/${APP_NAME}_*.war | head -1)
        curl -u $DEPLOY_USER:$DEPLOY_PASS -T $last_war \
            "http://$ip:$port/manager/text/deploy?path=/$APP_NAME&update=true"
        nginx_online $node
        return 1
    fi

    nginx_online $node
    log "节点 $node 部署完成"
    return 0
}

# 主流程
mkdir -p $BACKUP_DIR
# 备份当前版本(取第一个节点)
first_node=${TOMCAT_NODES[0]}
first_ip=$(echo $first_node | cut -d: -f1)
first_port=$(echo $first_node | cut -d: -f2)
backup_war="${BACKUP_DIR}/${APP_NAME}_$(date +%Y%m%d%H%M%S).war"
curl -u $DEPLOY_USER:$DEPLOY_PASS \
    "http://$first_ip:$first_port/manager/text/undeploy?path=/$APP_NAME" >/dev/null 2>&1
curl -u $DEPLOY_USER:$DEPLOY_PASS \
    "http://$first_ip:$first_port/manager/text/deploy?path=/$APP_NAME&war=file:/opt/tomcat/webapps/${APP_NAME}.war" \
    -o $backup_war 2>&1
log "已备份: $backup_war"

# 分批部署所有节点
for node in "${TOMCAT_NODES[@]}"; do
    if ! deploy_node $node; then
        log "部署终止,集群异常"
        exit 1
    fi
    sleep 5
done

log "✅ 集群部署全部完成"
exit 0

2. 使用方式

bash
运行
chmod +x deploy_cluster.sh
./deploy_cluster.sh myapp /data/build/myapp.war

方案 2:Ansible 批量部署(大规模集群首选)

1. inventory 配置(hosts)

ini
[tomcat_cluster]
192.168.1.101
192.168.1.102
192.168.1.103

[tomcat_cluster:vars]
app_name=myapp
war_path=/data/build/myapp.war
deploy_user=deploy
deploy_pass=StrongPass123

2. Ansible Playbook(deploy_tomcat.yml)

yaml
- name: 零停机部署 Tomcat 集群
  hosts: tomcat_cluster
  serial: 1  # 一次只部署1台,分批滚动
  become: yes
  vars:
    nginx_conf: /etc/nginx/nginx.conf
    backup_dir: /data/tomcat_backup/{{ app_name }}

  tasks:
    - name: 创建备份目录
      file: path={{ backup_dir }} state=directory

    - name: Nginx 下线当前节点
      command: sed -i "s/server {{ inventory_hostname }}:8080;/server {{ inventory_hostname }}:8080 backup;/g" {{ nginx_conf }}
      delegate_to: nginx_server

    - name: 重载 Nginx
      command: nginx -s reload
      delegate_to: nginx_server

    - name: 热部署 WAR
      uri:
        url: "http://{{ inventory_hostname }}:8080/manager/text/deploy?path=/{{ app_name }}&update=true"
        method: PUT
        user: "{{ deploy_user }}"
        password: "{{ deploy_pass }}"
        src: "{{ war_path }}"
        status_code: 200

    - name: 健康检查
      uri:
        url: "http://{{ inventory_hostname }}:8080/{{ app_name }}/health"
        status_code: 200
      retries: 10
      delay: 5

    - name: Nginx 上线当前节点
      command: sed -i "s/server {{ inventory_hostname }}:8080 backup;/server {{ inventory_hostname }}:8080;/g" {{ nginx_conf }}
      delegate_to: nginx_server

    - name: 重载 Nginx
      command: nginx -s reload
      delegate_to: nginx_server

3. 执行部署

bash
运行
ansible-playbook -i hosts deploy_tomcat.yml

方案 3:Tomcat Parallel Deployment(蓝绿部署,零切换)

利用 Tomcat 内置的并行部署能力,同一路径同时运行两个版本,新流量切到新版本,旧版本无流量后自动下线。

1. 版本化 WAR 命名

plaintext
myapp##001.war  # 旧版本
myapp##002.war  # 新版本

2. 脚本部署新版本

bash
运行
# 部署新版本
curl -u deploy:StrongPass123 -T myapp##002.war \
  "http://192.168.1.101:8080/manager/text/deploy?path=/myapp&update=true"

# 验证:访问 /myapp 自动路由到新版本

3. 优势

  • 真正零停机,无需 Nginx 切流量
  • 回滚只需删除新版本 WAR
  • 适合对可用性要求极高的场景

三、生产环境关键保障措施

1. 版本管理与回滚

  • 所有 WAR 包按版本命名:myapp_v1.2.3.war
  • 保留最近 5 个版本,自动清理过期备份
  • 回滚脚本:一键部署上一版本

2. 健康检查标准

  • 提供 /health 接口,返回 200 表示正常
  • 检查内容:数据库连接、缓存、核心依赖
  • 部署后最多重试 10 次,失败立即回滚

3. 权限与审计

  • 脚本仅允许 deploy 用户执行
  • 所有操作记录日志,包含时间、节点、结果
  • 集成 Jenkins/GitLab CI,实现一键触发

4. 会话不丢失

  • 必须使用 Redis 等外部 Session 存储
  • 避免依赖 Tomcat 本地 Session

四、常见问题与避坑

  1. Nginx 下线后仍有流量
    • 检查 Nginx 配置是否正确 reload
    • 增加 backup 标记,确保流量不进入
  2. 健康检查超时
    • 延长检查间隔(5 秒 / 次)
    • 优化应用启动速度
  3. 内存泄漏
    • 热部署后监控 JVM 堆内存
    • 避免在应用中创建非守护线程
  4. 集群不一致
    • 确保所有节点 Tomcat 版本、配置一致
    • 用 Ansible 统一管理配置

五、方案对比与选型建议

表格
方案 适用场景 复杂度 零停机 回滚
Shell + Nginx 中小集群(3–5 节点)
Ansible 大规模集群(>5 节点)
Parallel Deployment 极致可用性场景 ✅✅ ✅✅
推荐组合:中小集群用 Shell 脚本;大规模集群用 Ansible;核心业务用 Parallel Deployment。
上一篇 OSPF邻居建立失败排查流程图
下一篇 大学教学设备运维:常见设备问题与快速解决方法