本文目录导读:

我来为你详细介绍Shell脚本实现蓝绿部署策略的方法。
蓝绿部署的基本原理
蓝绿部署维护两套完全相同的生产环境:蓝色(当前运行)和绿色(待部署),流量在两者之间切换,实现零停机部署。
完整实现脚本
基础配置脚本
#!/bin/bash
# 配置参数
APP_NAME="myapp"
BLUE_DIR="/www/${APP_NAME}/blue"
GREEN_DIR="/www/${APP_NAME}/green"
NGINX_CONF="/etc/nginx/conf.d/${APP_NAME}.conf"
BACKUP_DIR="/backup/${APP_NAME}"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
# 错误处理
error_exit() {
log "ERROR: $1"
exit 1
}
部署核心函数
# 获取当前活跃环境
get_active_env() {
# 检查nginx指向哪个目录
if grep -q "$BLUE_DIR" "$NGINX_CONF" 2>/dev/null; then
echo "blue"
elif grep -q "$GREEN_DIR" "$NGINX_CONF" 2>/dev/null; then
echo "green"
else
echo "unknown"
fi
}
# 构建新版本
build_new_version() {
local target_dir=$1
local version_tag=$2
log "开始构建新版本到 $target_dir"
# 创建部署目录
mkdir -p "$target_dir"
# 构建或复制应用代码
# 示例:从git拉取代码
# git clone -b $version_tag https://github.com/yourrepo/app.git "$target_dir"
# 或者复制本地构建的代码
cp -r /tmp/build/* "$target_dir/"
# 执行构建命令
cd "$target_dir" && npm install 2>&1 || {
log "构建失败"
return 1
}
log "版本构建完成"
return 0
}
# 部署到非活跃环境
deploy_to_inactive() {
local active_env=$(get_active_env)
local deploy_dir
if [ "$active_env" = "blue" ]; then
deploy_dir="$GREEN_DIR"
elif [ "$active_env" = "green" ]; then
deploy_dir="$BLUE_DIR"
else
# 首次部署,默认部署到blue
deploy_dir="$BLUE_DIR"
fi
log "部署到非活跃环境: $deploy_dir"
# 构建新版本
build_new_version "$deploy_dir" "v1.2.0" || {
error_exit "构建失败"
}
# 运行测试
run_health_check "$deploy_dir" || {
log "健康检查失败,回滚部署"
return 1
}
echo "$deploy_dir"
}
切换流量函数
# 切换Nginx配置
switch_nginx() {
local new_env=$1
local new_dir
if [ "$new_env" = "blue" ]; then
new_dir="$BLUE_DIR"
new_color="blue"
else
new_dir="$GREEN_DIR"
new_color="green"
fi
log "切换Nginx到 $new_color 环境"
# 备份当前配置
cp "$NGINX_CONF" "${NGINX_CONF}.backup.$(date +%Y%m%d%H%M%S)"
# 生成新配置
cat > "$NGINX_CONF" << EOF
upstream ${APP_NAME}_backend {
server 127.0.0.1:8000; # 修改为实际端口
}
server {
listen 80;
server_name ${APP_NAME}.example.com;
root ${new_dir};
index index.html index.php;
location / {
try_files \$uri \$uri/ /index.php?\$query_string;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME ${new_dir}\$fastcgi_script_name;
include fastcgi_params;
}
}
EOF
# 测试配置
nginx -t || {
log "Nginx配置测试失败,恢复备份"
cp "${NGINX_CONF}.backup"* "$NGINX_CONF"
return 1
}
# 重载Nginx
systemctl reload nginx || nginx -s reload || {
log "Nginx重载失败"
return 1
}
log "Nginx配置切换成功"
return 0
}
# 优雅切换(使用upstream)
graceful_switch() {
local target_env=$1
log "执行优雅切换到 $target_env"
# 创建或更新upstream配置
cat > "/etc/nginx/conf.d/${APP_NAME}_upstream.conf" << EOF
upstream ${APP_NAME}_backend {
server 127.0.0.1:8001; # 蓝环境
server 127.0.0.1:8002; # 绿环境
}
EOF
# 根据目标环境调整权重
if [ "$target_env" = "blue" ]; then
# 逐渐将流量导向蓝环境
for i in 10 30 50 70 90 100; do
sed -i "s/server 127.0.0.1:8001 weight=[0-9]*/server 127.0.0.1:8001 weight=$i/" "/etc/nginx/conf.d/${APP_NAME}_upstream.conf"
sed -i "s/server 127.0.0.1:8002 weight=[0-9]*/server 127.0.0.1:8002 weight=$((100-i))/" "/etc/nginx/conf.d/${APP_NAME}_upstream.conf"
nginx -s reload
sleep 5
done
fi
}
健康检查函数
# 健康检查
run_health_check() {
local check_dir=$1
local check_url="http://localhost:8080/health"
log "执行健康检查..."
# 检查进程是否运行
if ! pgrep -f "node.*server.js" >/dev/null; then
log "应用进程未运行"
return 1
fi
# HTTP健康检查
for i in {1..5}; do
if curl -sf "$check_url" >/dev/null 2>&1; then
log "健康检查通过"
return 0
fi
sleep 2
done
log "健康检查失败"
return 1
}
# 验证部署成功
verify_deployment() {
local verify_url=$1
local expected_content=$2
log "验证部署..."
# 发送测试请求
response=$(curl -s "$verify_url")
if echo "$response" | grep -q "$expected_content"; then
log "部署验证通过"
return 0
else
log "部署验证失败"
return 1
fi
}
回滚函数
# 回滚部署
rollback() {
local previous_env=$1
log "执行回滚到 $previous_env 环境"
# 直接切换回之前的活跃环境
switch_nginx "$previous_env" || {
error_exit "回滚失败"
}
# 停止新环境
stop_env "$(get_inactive_env)"
log "回滚完成"
}
# 停止环境
stop_env() {
local env_dir=$1
local env_name=$(basename "$env_dir")
log "停止 $env_name 环境"
# 停止应用服务
if [ -f "$env_dir/scripts/stop.sh" ]; then
bash "$env_dir/scripts/stop.sh"
fi
# 清理进程
pkill -f "$env_dir" 2>/dev/null || true
}
主部署流程
# 主部署函数
blue_green_deploy() {
log "开始蓝绿部署..."
# 1. 获取当前活跃环境
local active_env=$(get_active_env)
log "当前活跃环境: $active_env"
# 2. 备份当前版本
local backup_file="${BACKUP_DIR}/${APP_NAME}_${active_env}_$(date +%Y%m%d%H%M%S).tar.gz"
tar -czf "$backup_file" -C "/www/${APP_NAME}/" "$active_env" 2>/dev/null || {
log "备份失败,继续部署"
}
# 3. 部署到非活跃环境
local deploy_dir=$(deploy_to_inactive)
[ $? -eq 0 ] || {
log "部署到非活跃环境失败"
return 1
}
# 4. 预检查(可选)
if [ -f "pre_check.sh" ]; then
bash pre_check.sh "$deploy_dir" || {
log "预检查失败"
rollback "$active_env"
return 1
}
fi
# 5. 切换流量
local new_env=$(basename "$deploy_dir")
switch_nginx "$new_env" || {
log "流量切换失败"
rollback "$active_env"
return 1
}
# 6. 验证新环境
verify_deployment "http://test.example.com/health" "OK" || {
log "新环境验证失败,执行回滚"
rollback "$active_env"
return 1
}
# 7. 保持旧环境一段时间(便于快速回滚)
log "保持旧环境运行30分钟..."
(sleep 1800 && clean_old_env "$active_env") &
log "蓝绿部署成功完成!"
return 0
}
# 清理旧环境
clean_old_env() {
local old_env=$1
local old_dir="/www/${APP_NAME}/$old_env"
log "清理旧环境: $old_dir"
# 询问确认
read -p "确认删除旧环境? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
rm -rf "$old_dir"
log "旧环境已清理"
else
log "保留旧环境"
fi
}
使用示例
#!/bin/bash
# 加载部署脚本
source ./blue_green_deploy.sh
# 显示帮助信息
show_help() {
echo "蓝绿部署管理脚本"
echo "Usage:"
echo " ./deploy.sh deploy - 执行蓝绿部署"
echo " ./deploy.sh status - 查看部署状态"
echo " ./deploy.sh rollback - 回滚到上一版本"
echo " ./deploy.sh clean - 清理旧版本"
}
# 显示状态
show_status() {
local active_env=$(get_active_env)
echo "=================================="
echo "应用状态:"
echo " 活跃环境: $active_env"
echo " 蓝环境: $([ -d "$BLUE_DIR" ] && echo '运行中' || echo '未部署')"
echo " 绿环境: $([ -d "$GREEN_DIR" ] && echo '运行中' || echo '未部署')"
echo ""
echo "最后部署时间: $(stat -c %y "$BLUE_DIR" 2>/dev/null || echo 'N/A')"
echo "=================================="
}
# 主程序
case "${1:-help}" in
deploy)
blue_green_deploy
;;
status)
show_status
;;
rollback)
local prev_env=$(get_inactive_env)
rollback "$prev_env"
;;
clean)
local inactive_env=$(get_inactive_env)
clean_old_env "$inactive_env"
;;
help|*)
show_help
;;
esac
高级特性
灰度发布扩展
# 灰度发布(渐进式切换)
canary_deploy() {
local percentage=$1 # 10-90
# 逐步增加新环境的流量比例
for step in $(seq 10 $percentage 10); do
log "设置流量比例: 新环境 $step%"
set_traffic_weight $((100-step)) $step
sleep 10
# 监控错误率
check_error_rate || {
log "错误率异常,执行回滚"
return 1
}
done
return 0
}
数据库兼容性检查
# 数据库迁移检查
check_db_migration() {
local new_version=$1
# 检查数据库迁移脚本是否存在
if [ -f "migrations/${new_version}.sql" ]; then
log "发现数据库迁移,需先执行"
# 只读模式检查
mysql -e "SELECT 1" || {
error_exit "数据库连接失败"
}
return 0
fi
}
使用建议
- 测试环境验证:先在测试环境验证脚本
- 监控告警:配置关键指标的监控告警
- 回滚计划:始终准备好回滚方案
- 数据一致性:确保数据库迁移的向后兼容性
- 日志记录:详细记录部署过程中的所有操作
这个脚本提供了完整的蓝绿部署实现,你可以根据具体的技术栈和业务需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播