本文目录导读:

我来详细介绍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
最佳实践建议
- 版本控制:使用Git标签管理版本
- 配置管理:分离配置和代码,使用环境变量
- 日志记录:记录详细部署日志
- 通知机制:集成Slack/邮件通知
- 自动化测试:部署前运行自动化测试
- 渐进式部署:先部署少量实例验证
- 监控告警:部署后持续监控服务状态
这样的自动发布策略可以显著提高部署效率,减少人为错误,并支持快速回滚。