Shell脚本如何实现自动发布策略

wen 实用脚本 21

本文目录导读:

Shell脚本如何实现自动发布策略

  1. 基础发布脚本框架
  2. 高级发布策略
  3. 完整的发布配置文件
  4. 使用示例
  5. 最佳实践建议

我来详细介绍Shell脚本实现自动发布策略的方法。

基础发布脚本框架

#!/bin/bash
# 自动发布脚本
set -e  # 出错即停止
# 配置变量
PROJECT_NAME="myapp"
DEPLOY_DIR="/opt/app/${PROJECT_NAME}"
BACKUP_DIR="/opt/backup/${PROJECT_NAME}"
GIT_REPO="git@github.com:user/${PROJECT_NAME}.git"
BRANCH="main"
BUILD_COMMAND="npm run build"  # 或 mvn package, make 等
SERVICE_NAME="${PROJECT_NAME}"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() {
    echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}"
}
error() {
    echo -e "${RED}[ERROR] $1${NC}"
    exit 1
}
warning() {
    echo -e "${YELLOW}[WARNING] $1${NC}"
}
# 1. 代码获取与更新
fetch_code() {
    log "Fetching latest code from ${BRANCH}..."
    if [ ! -d "${DEPLOY_DIR}/.git" ]; then
        git clone -b ${BRANCH} ${GIT_REPO} ${DEPLOY_DIR}
    else
        cd ${DEPLOY_DIR}
        git fetch origin
        git checkout ${BRANCH}
        git rebase origin/${BRANCH}
    fi
    # 获取最新commit信息
    COMMIT_ID=$(git rev-parse --short HEAD)
    log "Latest commit: ${COMMIT_ID}"
}
# 2. 构建项目
build_project() {
    log "Building project..."
    cd ${DEPLOY_DIR}
    # 安装依赖
    if [ -f "package.json" ]; then
        npm install --production
    elif [ -f "pom.xml" ]; then
        mvn clean package -DskipTests
    elif [ -f "Makefile" ]; then
        make build
    fi
    # 执行构建命令
    eval ${BUILD_COMMAND}
    log "Build completed"
}
# 3. 备份当前版本
backup_current() {
    log "Backing up current version..."
    # 创建备份目录
    BACKUP_PATH="${BACKUP_DIR}/$(date '+%Y%m%d_%H%M%S')_${COMMIT_ID}"
    mkdir -p ${BACKUP_PATH}
    # 备份配置文件
    if [ -f "${DEPLOY_DIR}/config/application.yml" ]; then
        cp -r ${DEPLOY_DIR}/config ${BACKUP_PATH}/
    fi
    # 备份数据目录
    if [ -d "${DEPLOY_DIR}/data" ]; then
        cp -r ${DEPLOY_DIR}/data ${BACKUP_PATH}/
    fi
    log "Backup saved to: ${BACKUP_PATH}"
}
# 4. 停止服务
stop_service() {
    log "Stopping service..."
    if systemctl is-active --quiet ${SERVICE_NAME}; then
        systemctl stop ${SERVICE_NAME}
        log "Service stopped"
    else
        warning "Service not running"
    fi
    # 等待进程完全退出
    sleep 3
}
# 5. 部署新版本
deploy_new_version() {
    log "Deploying new version..."
    # 复制构建产物到部署目录
    # 根据具体项目结构调整
    cp -r ${DEPLOY_DIR}/dist/* ${DEPLOY_DIR}/release/
    # 处理配置文件(保留原配置)
    if [ -f "${BACKUP_PATH}/config/application.yml" ]; then
        cp ${BACKUP_PATH}/config/application.yml ${DEPLOY_DIR}/release/config/
    fi
    log "Deployment files ready"
}
# 6. 启动服务
start_service() {
    log "Starting service..."
    systemctl daemon-reload
    systemctl start ${SERVICE_NAME}
    # 等待服务启动
    sleep 5
    if systemctl is-active --quiet ${SERVICE_NAME}; then
        log "Service started successfully"
    else
        error "Failed to start service"
    fi
}
# 7. 健康检查
health_check() {
    log "Performing health check..."
    # HTTP健康检查
    HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health)
    if [ "${HTTP_CODE}" = "200" ]; then
        log "Health check passed (HTTP ${HTTP_CODE})"
    else
        # 回滚到上一版本
        rollback
        error "Health check failed (HTTP ${HTTP_CODE})"
    fi
}
# 8. 回滚函数
rollback() {
    log "Rolling back to previous version..."
    # 停止当前服务
    stop_service
    # 恢复备份
    LATEST_BACKUP=$(ls -t ${BACKUP_DIR} | head -1)
    if [ -n "${LATEST_BACKUP}" ]; then
        cp -r ${BACKUP_DIR}/${LATEST_BACKUP}/* ${DEPLOY_DIR}/
        log "Rolled back to: ${LATEST_BACKUP}"
    else
        error "No backup available for rollback"
    fi
    # 启动服务
    start_service
}
# 主发布流程
main() {
    log "Starting deployment for ${PROJECT_NAME}"
    fetch_code
    build_project
    backup_current
    stop_service
    deploy_new_version
    start_service
    health_check
    log "Deployment completed successfully!"
}
# 执行主函数
main "$@"

高级发布策略

蓝绿部署

#!/bin/bash
# 蓝绿部署脚本
BLUE_PORT=8081
GREEN_PORT=8082
NGINX_CONF="/etc/nginx/conf.d/app.conf"
APP_DIR="/opt/app"
deploy_blue_green() {
    # 确定当前活动环境
    if curl -s http://localhost:${BLUE_PORT}/health > /dev/null 2>&1; then
        ACTIVE="blue"
        INACTIVE="green"
        INACTIVE_PORT=${GREEN_PORT}
    else
        ACTIVE="green"
        INACTIVE="blue"
        INACTIVE_PORT=${BLUE_PORT}
    fi
    log "Current active: ${ACTIVE}, deploying to: ${INACTIVE}"
    # 部署到非活动环境
    cp -r ${APP_DIR}/release/* ${APP_DIR}/${INACTIVE}/
    # 启动非活动环境
    systemctl start app-${INACTIVE}
    # 健康检查新环境
    sleep 10
    if curl -s http://localhost:${INACTIVE_PORT}/health > /dev/null 2>&1; then
        log "New environment healthy, switching traffic"
        # 更新Nginx配置切换流量
        sed -i "s/proxy_pass http:\/\/127.0.0.1:${ACTIVE_PORT}/proxy_pass http:\/\/127.0.0.1:${INACTIVE_PORT}/" ${NGINX_CONF}
        nginx -s reload
        # 停止旧环境
        systemctl stop app-${ACTIVE}
        log "Deployment successful, traffic switched to ${INACTIVE}"
    else
        error "New environment failed health check"
        systemctl stop app-${INACTIVE}
    fi
}

滚动更新

#!/bin/bash
# 滚动更新脚本
SERVERS=("node1" "node2" "node3")
SSH_USER="deploy"
SSH_KEY="/home/deploy/.ssh/id_rsa"
rolling_update() {
    log "Starting rolling update..."
    for SERVER in "${SERVERS[@]}"; do
        log "Updating ${SERVER}..."
        # 从负载均衡移除
        remove_from_lb "${SERVER}"
        # 远程执行更新
        ssh -i ${SSH_KEY} ${SSH_USER}@${SERVER} "
            systemctl stop app
            cp -r /tmp/release/* /opt/app/
            systemctl start app
        "
        # 等待服务就绪
        sleep 15
        # 健康检查
        if check_remote_health "${SERVER}"; then
            # 添加回负载均衡
            add_to_lb "${SERVER}"
            log "${SERVER} updated successfully"
        else
            error "Failed to update ${SERVER}, rolling back..."
            rollback_server "${SERVER}"
        fi
    done
    log "Rolling update completed"
}
remove_from_lb() {
    local server=$1
    # 使用API从负载均衡器移除节点
    curl -X POST "http://loadbalancer:8080/api/pool/remove?server=${server}"
}
add_to_lb() {
    local server=$1
    curl -X POST "http://loadbalancer:8080/api/pool/add?server=${server}"
}
check_remote_health() {
    local server=$1
    ssh -i ${SSH_KEY} ${SSH_USER}@${SERVER} "curl -s http://localhost:8080/health" | grep -q "ok"
}

完整的发布配置文件

# deploy-config.yml
project:
  name: myapp
  repo: git@github.com:user/myapp.git
  branch: main
  build_command: npm run build
environment:
  production:
    servers:
      - 192.168.1.10
      - 192.168.1.11
      - 192.168.1.12
    deploy_dir: /opt/app
    backup_dir: /opt/backup
    service_name: myapp
    port: 8080
  staging:
    servers:
      - 192.168.2.10
    deploy_dir: /opt/staging/app
    backup_dir: /opt/staging/backup
    service_name: myapp-staging
    port: 8081
health_check:
  type: http
  endpoint: /health
  expected_status: 200
  timeout: 30
  retries: 3
rollback:
  enabled: true
  max_backups: 5
  auto_rollback: true

使用示例

# 基本部署
./deploy.sh
# 指定环境
./deploy.sh --env production
# 指定版本
./deploy.sh --tag v1.2.3
# 仅构建
./deploy.sh --build-only
# 跳过测试
./deploy.sh --skip-tests
# 强制部署(忽略错误)
./deploy.sh --force
# 回滚到指定版本
./deploy.sh --rollback v1.2.0

最佳实践建议

  1. 版本控制:使用Git标签管理版本
  2. 配置管理:分离配置和代码,使用环境变量
  3. 日志记录:记录详细部署日志
  4. 通知机制:集成Slack/邮件通知
  5. 自动化测试:部署前运行自动化测试
  6. 渐进式部署:先部署少量实例验证
  7. 监控告警:部署后持续监控服务状态

这样的自动发布策略可以显著提高部署效率,减少人为错误,并支持快速回滚。

抱歉,评论功能暂时关闭!