refactor: 全面改进部署脚本,增强健壮性和可维护性
高优先级改进: - 使用更精确的容器状态检查方法(docker inspect) - 添加容器日志命令的错误处理 - 将nginx容器名称改为变量(NGINX_CONTAINER_NAME) 中优先级改进: - 添加部署前文件检查(检查必要文件和工具) - 添加部署后验证(HTTP/HTTPS服务响应检查) - 添加日志记录功能(自动创建日志文件) - 改进健康检查机制(检查容器状态和服务响应) 低优先级改进: - 添加参数化配置(支持命令行参数) - 添加帮助信息(-h选项) 其他改进: - 更新.gitignore,忽略部署日志文件 - 支持自定义服务器IP、用户名、项目名、容器名、版本号 - 提供详细的帮助信息和使用说明
This commit is contained in:
+3
-1
@@ -179,10 +179,12 @@ logs/
|
|||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
pnpm-debug.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Deployment logs
|
||||||
|
deploy_*.log
|
||||||
|
|
||||||
# IDE
|
# IDE
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|||||||
@@ -8,19 +8,78 @@ DEPLOY_ROOT="/home/novalon/docker-app"
|
|||||||
PROJECT_NAME="novalon-website"
|
PROJECT_NAME="novalon-website"
|
||||||
PROJECT_DIR="$DEPLOY_ROOT/$PROJECT_NAME"
|
PROJECT_DIR="$DEPLOY_ROOT/$PROJECT_NAME"
|
||||||
CONTAINER_NAME="novalon-website"
|
CONTAINER_NAME="novalon-website"
|
||||||
|
NGINX_CONTAINER_NAME="novalon-nginx"
|
||||||
|
VERSION="1.0.0"
|
||||||
|
|
||||||
|
while getopts "i:u:p:c:v:h" opt; do
|
||||||
|
case $opt in
|
||||||
|
i) SERVER_IP="$OPTARG" ;;
|
||||||
|
u) SERVER_USER="$OPTARG" ;;
|
||||||
|
p) PROJECT_NAME="$OPTARG" ;;
|
||||||
|
c) CONTAINER_NAME="$OPTARG" ;;
|
||||||
|
v) VERSION="$OPTARG" ;;
|
||||||
|
h)
|
||||||
|
echo "用法: $0 [选项]"
|
||||||
|
echo "选项:"
|
||||||
|
echo " -i IP地址 服务器IP地址 (默认: 139.155.109.62)"
|
||||||
|
echo " -u 用户名 SSH用户名 (默认: root)"
|
||||||
|
echo " -p 项目名 项目名称 (默认: novalon-website)"
|
||||||
|
echo " -c 容器名 容器名称 (默认: novalon-website)"
|
||||||
|
echo " -v 版本号 版本号 (默认: 1.0.0)"
|
||||||
|
echo " -h 显示帮助信息"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
\?)
|
||||||
|
echo "无效选项: -$OPTARG" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
PROJECT_DIR="$DEPLOY_ROOT/$PROJECT_NAME"
|
||||||
|
|
||||||
|
LOG_DIR="./logs"
|
||||||
|
LOG_FILE="$LOG_DIR/deploy_$(date +%Y%m%d_%H%M%S).log"
|
||||||
|
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
exec > >(tee -a "$LOG_FILE") 2>&1
|
||||||
|
|
||||||
echo "🚀 开始部署Novalon网站到服务器 $SERVER_IP"
|
echo "🚀 开始部署Novalon网站到服务器 $SERVER_IP"
|
||||||
echo "📁 部署根目录: $DEPLOY_ROOT"
|
echo "📁 部署根目录: $DEPLOY_ROOT"
|
||||||
echo "📁 项目目录: $PROJECT_DIR"
|
echo "📁 项目目录: $PROJECT_DIR"
|
||||||
echo "🐳 容器名称: $CONTAINER_NAME"
|
echo "🐳 容器名称: $CONTAINER_NAME"
|
||||||
echo "📦 版本号: 1.0.0"
|
echo "📦 版本号: $VERSION"
|
||||||
|
echo "📋 部署日志: $LOG_FILE"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
echo "📋 步骤0: 部署前检查..."
|
||||||
|
|
||||||
|
for file in docker-compose.yml Dockerfile nginx.conf .env.example setup-ssl.sh; do
|
||||||
|
if [ ! -f "$file" ]; then
|
||||||
|
echo "❌ 缺少必要文件: $file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! command -v docker-compose &> /dev/null; then
|
||||||
|
echo "❌ 本地docker-compose不可用"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ 部署前检查通过"
|
||||||
|
|
||||||
|
echo ""
|
||||||
echo "📋 步骤1: 验证SSH连接..."
|
echo "📋 步骤1: 验证SSH连接..."
|
||||||
if ! ssh -o ConnectTimeout=5 "$SERVER_USER@$SERVER_IP" exit; then
|
if ! ssh -o ConnectTimeout=5 "$SERVER_USER@$SERVER_IP" exit; then
|
||||||
echo "❌ 无法连接到服务器 $SERVER_IP"
|
echo "❌ 无法连接到服务器 $SERVER_IP"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! ssh "$SERVER_USER@$SERVER_IP" "docker --version"; then
|
||||||
|
echo "❌ 服务器上Docker不可用"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "✅ SSH连接验证成功"
|
echo "✅ SSH连接验证成功"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
@@ -55,16 +114,29 @@ docker-compose up -d
|
|||||||
echo "📋 等待服务启动..."
|
echo "📋 等待服务启动..."
|
||||||
timeout=60
|
timeout=60
|
||||||
elapsed=0
|
elapsed=0
|
||||||
|
check_interval=3
|
||||||
|
|
||||||
while [ $elapsed -lt $timeout ]; do
|
while [ $elapsed -lt $timeout ]; do
|
||||||
if docker ps | grep -q "$CONTAINER_NAME"; then
|
if docker inspect --format='{{.State.Status}}' "$CONTAINER_NAME" 2>/dev/null | grep -q "running"; then
|
||||||
echo "✅ 服务已启动"
|
if curl -f -s -o /dev/null "http://localhost:3000" --max-time 5 2>/dev/null; then
|
||||||
|
echo "✅ 服务已启动并响应正常"
|
||||||
break
|
break
|
||||||
|
else
|
||||||
|
echo "⏳ 容器运行中,等待服务响应..."
|
||||||
fi
|
fi
|
||||||
sleep 2
|
else
|
||||||
elapsed=$((elapsed + 2))
|
echo "⏳ 等待容器启动..."
|
||||||
|
fi
|
||||||
|
sleep $check_interval
|
||||||
|
elapsed=$((elapsed + check_interval))
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ $elapsed -ge $timeout ]; then
|
if [ $elapsed -ge $timeout ]; then
|
||||||
echo "❌ 服务启动超时"
|
echo "❌ 服务启动超时"
|
||||||
|
echo "📋 当前容器状态:"
|
||||||
|
docker ps -a | grep "$CONTAINER_NAME"
|
||||||
|
echo "📋 容器日志:"
|
||||||
|
docker logs "$CONTAINER_NAME" --tail 20
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -72,12 +144,15 @@ echo "📋 检查容器状态..."
|
|||||||
docker ps | grep "$CONTAINER_NAME"
|
docker ps | grep "$CONTAINER_NAME"
|
||||||
|
|
||||||
echo "📋 检查容器日志..."
|
echo "📋 检查容器日志..."
|
||||||
docker logs "$CONTAINER_NAME" --tail 50
|
if docker logs "$CONTAINER_NAME" --tail 50 2>/dev/null; then
|
||||||
|
echo "✅ 容器日志检查完成"
|
||||||
|
else
|
||||||
|
echo "⚠️ 容器日志为空或无法访问"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "📋 配置SSL证书自动续期..."
|
echo "📋 配置SSL证书自动续期..."
|
||||||
# 添加certbot自动续期cron任务
|
|
||||||
if ! crontab -l | grep -q "certbot renew"; then
|
if ! crontab -l | grep -q "certbot renew"; then
|
||||||
if ! (crontab -l 2>/dev/null; echo "0 0,12 * * * certbot renew --quiet --post-hook 'docker restart novalon-nginx'") | crontab -; then
|
if ! (crontab -l 2>/dev/null; echo "0 0,12 * * * certbot renew --quiet --post-hook 'docker restart $NGINX_CONTAINER_NAME'") | crontab -; then
|
||||||
echo "❌ SSL证书自动续期任务配置失败"
|
echo "❌ SSL证书自动续期任务配置失败"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -89,6 +164,28 @@ fi
|
|||||||
echo "✅ 部署完成!"
|
echo "✅ 部署完成!"
|
||||||
ENDSSH
|
ENDSSH
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "📋 步骤4: 部署后验证..."
|
||||||
|
|
||||||
|
if ! ssh "$SERVER_USER@$SERVER_IP" "docker ps | grep -q '$CONTAINER_NAME'"; then
|
||||||
|
echo "❌ 容器未运行"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! curl -f -s -o /dev/null "http://$SERVER_IP" --max-time 10; then
|
||||||
|
echo "⚠️ HTTP服务响应异常"
|
||||||
|
else
|
||||||
|
echo "✅ HTTP服务正常"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! curl -f -s -o /dev/null "https://$SERVER_IP" --max-time 10; then
|
||||||
|
echo "⚠️ HTTPS服务响应异常"
|
||||||
|
else
|
||||||
|
echo "✅ HTTPS服务正常"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ 部署后验证通过"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "🎉 部署脚本执行完成!"
|
echo "🎉 部署脚本执行完成!"
|
||||||
echo "📋 访问地址:"
|
echo "📋 访问地址:"
|
||||||
|
|||||||
Reference in New Issue
Block a user