本文目录导读:

我来详细介绍Shell脚本实现全自动发布策略的几种方式:
基础发布脚本框架
#!/bin/bash
# 配置变量
PROJECT_NAME="my-app"
GIT_REPO="git@github.com:user/repo.git"
BRANCH="main"
DEPLOY_DIR="/var/www/$PROJECT_NAME"
BACKUP_DIR="/var/backups/$PROJECT_NAME"
LOG_FILE="/var/log/deploy/$PROJECT_NAME-deploy.log"
# 颜色输出
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 日志函数
log() {
echo -e "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
# 健康检查
health_check() {
local max_retries=30
local retry_count=0
local url="http://localhost:8080/health"
while [ $retry_count -lt $max_retries ]; do
if curl -f -s $url > /dev/null 2>&1; then
log "${GREEN}Health check passed${NC}"
return 0
fi
sleep 1
((retry_count++))
done
log "${RED}Health check failed after $max_retries retries${NC}"
return 1
}
蓝绿部署策略
#!/bin/bash
BLUE_DIR="/var/www/app-blue"
GREEN_DIR="/var/www/app-green"
ACTIVE_SYMLINK="/var/www/app"
NGINX_CONFIG="/etc/nginx/sites-enabled/app"
blue_green_deploy() {
# 确定当前活跃环境
if [ -L "$ACTIVE_SYMLINK" ] && [ "$(readlink $ACTIVE_SYMLINK)" == "$BLUE_DIR" ]; then
INACTIVE="$GREEN_DIR"
ACTIVE="$BLUE_DIR"
NEW_ENV="green"
else
INACTIVE="$GREEN_DIR"
ACTIVE="$BLUE_DIR"
NEW_ENV="blue"
fi
log "Deploying to $NEW_ENV environment"
# 部署到非活跃环境
rsync -av --delete --exclude='.env' "$BUILD_DIR/" "$INACTIVE/"
# 更新配置
cp "$ACTIVE/.env" "$INACTIVE/"
# 执行数据库迁移
cd $INACTIVE && ./artisan migrate --force
# 切换流量
ln -sfn "$INACTIVE" "$ACTIVE_SYMLINK"
# 重启服务
sudo systemctl reload nginx
# 健康检查
if health_check; then
log "${GREEN}Blue-Green deploy to $NEW_ENV successful${NC}"
else
# 回滚
ln -sfn "$ACTIVE" "$ACTIVE_SYMLINK"
sudo systemctl reload nginx
log "${RED}Deploy failed, rolled back to $ACTIVE${NC}"
return 1
fi
}
滚动更新策略
#!/bin/bash
SERVICE_NAME="my-service"
INSTANCES=("instance-1" "instance-2" "instance-3")
BATCH_SIZE=1
HEALTH_CHECK_URL="http://localhost:8080/health"
rolling_update() {
local total=${#INSTANCES[@]}
local batch=0
for ((i=0; i<$total; i+=BATCH_SIZE)); do
batch=$((batch + 1))
log "Starting batch $batch of $(( (total + BATCH_SIZE - 1) / BATCH_SIZE ))"
# 获取当前批次实例
local batch_instances=("${INSTANCES[@]:i:BATCH_SIZE}")
# 停止当前批次实例
for instance in "${batch_instances[@]}"; do
log "Draining connections for $instance"
docker stop $instance
docker rm $instance
done
# 启动新版本实例
for instance in "${batch_instances[@]}"; do
log "Starting new version of $instance"
docker run -d --name $instance $NEW_IMAGE
# 等待实例就绪
sleep 10
# 健康检查
if ! health_check; then
log "${RED}Health check failed for $instance, rolling back batch${NC}"
return 1
fi
done
# 批次间等待
if [ $((i + BATCH_SIZE)) -lt $total ]; then
log "Waiting 30 seconds before next batch..."
sleep 30
fi
done
log "${GREEN}Rolling update completed successfully${NC}"
}
金丝雀发布策略
#!/bin/bash
CANARY_PERCENTAGE=20
CANARY_INSTANCES=1
PRODUCTION_INSTANCES=4
canary_deploy() {
local canary_count=$CANARY_INSTANCES
local production_count=$PRODUCTION_INSTANCES
log "Starting canary deployment (${CANARY_PERCENTAGE}% traffic)"
# 部署金丝雀实例
log "Deploying $canary_count canary instances"
docker-compose scale app_canary=$canary_count
# 等待金丝雀稳定
sleep 60
# 监控金丝雀
local error_rate=$(check_canary_errors)
if [ $(echo "$error_rate > 0.01" | bc) -eq 1 ]; then
log "${RED}Canary error rate too high: ${error_rate}%, rolling back${NC}"
docker-compose scale app_canary=0
return 1
fi
# 逐步增加流量
for percentage in 50 80 100; do
log "Increasing traffic to ${percentage}%"
adjust_traffic $percentage
sleep 120
if ! check_deployment_health; then
log "${RED}Deployment health check failed at ${percentage}%${NC}"
rollback_canary
return 1
fi
done
# 替换生产环境
log "Replacing production instances with new version"
docker-compose up -d --scale app=$production_count app
docker-compose scale app_canary=0
log "${GREEN}Canary deployment completed successfully${NC}"
}
完整发布流程
#!/bin/bash
# 主发布函数
auto_deploy() {
local version=$1
local strategy=${2:-"blue-green"} # 默认蓝绿部署
log "=========================================="
log "Starting auto deploy v${version}"
log "Strategy: $strategy"
log "=========================================="
# 1. 前置检查
log "Phase 1: Pre-deployment checks"
if ! pre_deploy_checks; then
log "${RED}Pre-deployment checks failed${NC}"
notify_failure "Pre-deployment checks failed"
return 1
fi
# 2. 代码获取
log "Phase 2: Fetching code"
if ! fetch_code $version; then
log "${RED}Code fetch failed${NC}"
notify_failure "Code fetch failed"
return 1
fi
# 3. 构建
log "Phase 3: Building application"
if ! build_application; then
log "${RED}Build failed${NC}"
notify_failure "Build failed"
return 1
fi
# 4. 运行测试
log "Phase 4: Running tests"
if ! run_tests; then
log "${RED}Tests failed${NC}"
notify_failure "Tests failed"
return 1
fi
# 5. 部署
log "Phase 5: Deploying"
case $strategy in
"blue-green")
blue_green_deploy
;;
"rolling")
rolling_update
;;
"canary")
canary_deploy
;;
*)
log "${RED}Unknown strategy: $strategy${NC}"
return 1
;;
esac
if [ $? -ne 0 ]; then
log "${RED}Deploy failed${NC}"
notify_failure "Deploy failed"
return 1
fi
# 6. 部署后检查
log "Phase 6: Post-deployment checks"
if ! post_deploy_checks; then
log "${RED}Post-deployment checks failed, rolling back${NC}"
rollback
return 1
fi
# 7. 通知成功
log "${GREEN}Deploy v${version} completed successfully${NC}"
notify_success "Deploy v${version} completed"
# 清理旧版本
cleanup_old_versions
}
# 执行入口
if [ $# -lt 1 ]; then
echo "Usage: $0 <version> [strategy]"
exit 1
fi
auto_deploy "$@"
辅助函数
#!/bin/bash
# 通知函数(支持多种通知方式)
notify() {
local level=$1
local message=$2
# Slack通知
if [ -n "$SLACK_WEBHOOK_URL" ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"[$level] $message\"}" \
$SLACK_WEBHOOK_URL
fi
# 邮件通知
if [ -n "$EMAIL_RECIPIENT" ]; then
echo "$message" | mail -s "[$level] Deploy Notification" $EMAIL_RECIPIENT
fi
# 钉钉/企业微信通知
if [ -n "$DINGTALK_WEBHOOK" ]; then
curl -X POST -H 'Content-Type: application/json' \
--data "{\"msgtype\":\"text\",\"text\":{\"content\":\"$message\"}}" \
$DINGTALK_WEBHOOK
fi
}
# 并发执行
parallel_exec() {
local max_parallel=$1
shift
local commands=("$@")
for cmd in "${commands[@]}"; do
eval "$cmd" &
if [ $(jobs -r | wc -l) -ge $max_parallel ]; then
wait -n
fi
done
wait
}
# 超时执行
timeout_exec() {
local timeout=$1
local command=$2
(
eval "$command" &
child=$!
trap '' SIGTERM
(sleep $timeout; kill $child 2>/dev/null) &
wait $child
)
}
# 锁机制防止并发部署
acquire_lock() {
local lock_file="/var/lock/deploy.lock"
if ! mkdir $lock_file 2>/dev/null; then
log "${YELLOW}Another deploy is in progress${NC}"
exit 1
fi
trap 'rm -rf $lock_file' EXIT
}
# 清理函数
cleanup_old_versions() {
log "Cleaning up old versions..."
# 保留最近5个版本
ls -t $DEPLOY_DIR/versions/ | tail -n +6 | while read version; do
rm -rf "$DEPLOY_DIR/versions/$version"
log "Removed old version: $version"
done
}
使用示例
# 基本使用 ./deploy.sh v1.2.3 # 指定策略 ./deploy.sh v1.2.3 rolling # 金丝雀发布 ./deploy.sh v1.2.3 canary # 带参数 CANARY_PERCENTAGE=10 ./deploy.sh v1.2.3 canary
这个脚本框架实现了多种发布策略,具备以下特点:
- 可视化日志
- 自动健康检查
- 自动回滚机制
- 多策略支持
- 通知集成
- 并发控制
- 锁机制防冲突
使用时请根据实际需求调整配置和逻辑。