refactor: deploy工具适配systemd service模式-移除.env依赖

This commit is contained in:
2026-05-25 14:46:07 +08:00
parent 216dd365f6
commit 4240bb6970
2 changed files with 104 additions and 45 deletions

View File

@@ -62,71 +62,101 @@ EOF
curl -s -X POST "${WEBHOOK_URL}" -H "Content-Type: application/json" -d "${payload}" >/dev/null 2>&1 || true
}
# ---------- 环境配置 ----------
check_env_file() {
log_step "检查远程 .env 文件..."
[ "$DRY_RUN" = true ] && { log_dry "test -f ${REMOTE_DIR}/.env"; return 0; }
# ---------- 环境配置systemd service----------
get_service_file_local() { echo "${SCRIPT_DIR}/deploy/rust-backend-${APP_ENV}.service"; }
if ! remote "test -f '${REMOTE_DIR}/.env'" 2>/dev/null; then
log_error ".env 文件不存在: ${REMOTE_DIR}/.env"; exit 1
check_service_file() {
log_step "检查远程 systemd service 文件..."
[ "$DRY_RUN" = true ] && { log_dry "检查 ${SERVICE_NAME}"; return 0; }
if ! remote "systemctl cat '${SERVICE_NAME}'" &>/dev/null; then
log_error "systemd service ${SERVICE_NAME} 不存在,请先用 --deploy-service 安装"
exit 1
fi
local env_content; env_content=$(remote "cat '${REMOTE_DIR}/.env'" 2>/dev/null || echo "")
[ -z "$env_content" ] && { log_error ".env 文件为空"; exit 1; }
local content; content=$(remote "systemctl cat '${SERVICE_NAME}'" 2>/dev/null || echo "")
[ -z "$content" ] && { log_error "service 内容为空"; exit 1; }
local missing=0 ph=0 commented=0
local required_vars=("JWT_SECRET" "WECHAT_SECRET" "WECHAT_APPID" "DATABASE_URL")
[ "${APP_ENV}" = "production" ] && required_vars+=("SSL_KEY_PATH" "SSL_CERT_PATH")
local missing=0 ph=0
local required_vars=("DATABASE_URL" "JWT_SECRET" "WECHAT_APPID" "WECHAT_SECRET")
[ "${APP_ENV}" = "production" ] && required_vars+=("SSL_KEY_PATH" "SSL_CERT_PATH" "ALIPAY_APP_ID")
for var in "${required_vars[@]}"; do
local val; val=$(echo "$env_content" | grep -E "^${var}=" | head -1 | sed "s/^${var}=//")
local val; val=$(echo "$content" | grep -E "^Environment=${var}=" | head -1 | sed "s/^Environment=${var}=//")
if [ -z "$val" ]; then
log_error " 缺少: ${var}="; missing=$((missing+1))
log_error " 缺少: Environment=${var}="; missing=$((missing+1))
elif echo "$val" | grep -qiE "^(your_|placeholder|change_me|xxx|test_)"; then
log_warn " 占位符: ${var}=${val}"; ph=$((ph+1))
fi
echo "$env_content" | grep -qE "^#\s*${var}=" && { log_warn " 已注释: # ${var}="; commented=$((commented+1)); }
done
[ $missing -gt 0 ] && { log_error ".env 检查失败:${missing} 个缺失"; exit 1; }
[ $ph -gt 0 ] || [ $commented -gt 0 ] && log_warn ".env 存在 ${ph} 个占位符${commented} 个注释行,建议修正"
log_info ".env 文件检查通过"
[ $missing -gt 0 ] && { log_error "service 配置检查失败:${missing} 个缺失"; exit 1; }
[ $ph -gt 0 ] && log_warn "service 存在 ${ph} 个占位符,部署后可能无法正常运行"
log_info "service 配置检查通过"
}
deploy_service_file() {
log_step "部署 systemd service 文件..."
[ "$DRY_RUN" = true ] && { log_dry "上传 ${SERVICE_FILE_LOCAL} → /etc/systemd/system/${SERVICE_NAME}"; return 0; }
if [ ! -f "$(get_service_file_local)" ]; then
log_error "本地 service 文件不存在: ${SERVICE_FILE_LOCAL}"
log_info "可通过 --init-env 生成模板"
exit 1
fi
rsync -avzP "$(get_service_file_local)" "${REMOTE_USER}@${REMOTE_HOST}:/etc/systemd/system/${SERVICE_NAME}"
remote "systemctl daemon-reload"
log_info "service 文件部署完成,使用 systemctl restart ${SERVICE_NAME} 重启"
}
init_env() {
log_step "初始化远程 .env 文件..."
[ "$DRY_RUN" = true ] && { log_dry " ${REMOTE_HOST}:${REMOTE_DIR}/.env 生成配置"; return 0; }
log_step "初始化 systemd service 文件(从模板生成)..."
[ "$DRY_RUN" = true ] && { log_dry "生成 ${SERVICE_FILE_LOCAL}"; return 0; }
local exists=false
remote "test -f '${REMOTE_DIR}/.env'" 2>/dev/null && exists=true
if [ "$exists" = true ]; then
log_warn ".env 已存在,继续将覆盖!"
if [ -f "$(get_service_file_local)" ]; then
log_warn "${SERVICE_FILE_LOCAL} 已存在,继续将覆盖!"
read -p "是否覆盖? [y/N] " -n 1 -r; echo
[[ ! $REPLY =~ ^[Yy]$ ]] && { log_warn "已取消"; return 0; }
remote "cp '${REMOTE_DIR}/.env' '${REMOTE_DIR}/.env.backup.$(date +%Y%m%d_%H%M%S)'" 2>/dev/null || true
cp "$(get_service_file_local)" "${SERVICE_FILE_LOCAL}.bak.$(date +%Y%m%d_%H%M%S)"
fi
local jwt_secret
jwt_secret=$(openssl rand -base64 32 2>/dev/null | tr -d '\n' || echo "change-me-$(date +%s)-$$")
cat <<ENV_EOF | remote "cat > '${REMOTE_DIR}/.env' && chmod 600 '${REMOTE_DIR}/.env'"
# ASD Rust Backend - ${APP_ENV} 环境配置
# 由 deploy.sh --init-env 自动生成于 $(date '+%Y-%m-%d %H:%M:%S')
APP_ENV=${APP_ENV}
DATABASE_URL=请替换为实际数据库连接字符串
WECHAT_APPID=请替换为实际微信 AppID
WECHAT_SECRET=请替换为实际微信 Secret
JWT_SECRET=${jwt_secret}
RUST_LOG=info
FREE_USER_DATA_LIMIT=20
# ===== 支付宝支付配置(可选) =====
# ALIPAY_APP_ID=...
# ALIPAY_GATEWAY=...
ENV_EOF
mkdir -p "${SCRIPT_DIR}/deploy"
cat > "$(get_service_file_local)" << SERVEOF
[Unit]
Description=Rust Backend ${APP_ENV^} Service
After=network.target postgresql.service
Wants=network.target
log_info ".env 已生成,文件权限 600"
[Service]
Type=simple
User=root
Group=root
WorkingDirectory=${REMOTE_DIR}
ExecStart=${REMOTE_DIR}/rust-backend
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
Environment=DATABASE_URL=请替换为实际数据库连接
Environment=WECHAT_APPID=请替换为实际微信 AppID
Environment=WECHAT_SECRET=请替换为实际微信 Secret
Environment=JWT_SECRET=${jwt_secret}
Environment=SSL_KEY_PATH=
Environment=SSL_CERT_PATH=
Environment=RUST_LOG=info
Environment=APP_VERSION=0.3.0
Environment=FREE_USER_DATA_LIMIT=20
SERVEOF
chmod 600 "$(get_service_file_local)"
log_info "service 模板已生成: ${SERVICE_FILE_LOCAL}"
log_warn "请手动填写 DATABASE_URL / WECHAT_APPID / WECHAT_SECRET"
log_info "然后使用 ./deploy.sh ${APP_ENV} --deploy-service 上传"
}
# ---------- 编译 ----------
@@ -266,6 +296,11 @@ run_migrations() {
restart_service() {
log_step "重启服务 '${SERVICE_NAME}'..."
[ "$DRY_RUN" = true ] && { log_dry "systemctl restart ${SERVICE_NAME}"; return 0; }
# 部署前先确保 service 文件存在
if ! remote "systemctl cat '${SERVICE_NAME}'" &>/dev/null; then
log_warn "${SERVICE_NAME} 未安装,尝试部署 service 文件..."
deploy_service_file
fi
remote "systemctl restart ${SERVICE_NAME}" && log_info "服务重启成功" || log_error "服务重启失败!"
sleep 3
}
@@ -363,6 +398,25 @@ show_deploy_info() {
echo -e "${BLUE}========================================${NC}"
}
# ---------- SSL 证书检查 ----------
check_ssl_expiry() {
[ "${APP_ENV}" != "production" ] && return 0 # 非生产环境跳过
log_step "检查 SSL 证书到期时间..."
[ "$DRY_RUN" = true ] && { log_dry "openssl x509 -checkend 2592000"; return 0; }
# 从 OpenResty 容器内读取证书
local cert_info; cert_info=$(remote "docker exec 1Panel-openresty-ABu5 openssl x509 -in /www/sites/${TEST_DOMAIN#https://}/ssl/fullchain.pem -noout -enddate -checkend 2592000 2>/dev/null" || echo "")
if echo "$cert_info" | grep -q "Certificate will expire"; then
local expiry; expiry=$(remote "docker exec 1Panel-openresty-ABu5 openssl x509 -in /www/sites/${TEST_DOMAIN#https://}/ssl/fullchain.pem -noout -enddate 2>/dev/null | cut -d= -f2" || echo "未知")
local days_left; days_left=$(remote "docker exec 1Panel-openresty-ABu5 openssl x509 -in /www/sites/${TEST_DOMAIN#https://}/ssl/fullchain.pem -noout -checkend 86400 2>/dev/null | grep -c 'will expire'" || echo "0")
log_warn "SSL 证书将于 ${expiry} 到期(不足 30 天)!"
[ "$days_left" -gt "0" ] && log_warn " 警告:证书将在 1 天内到期,请立即续期!"
else
log_info "SSL 证书有效期超过 30 天 ✅"
fi
}
# ---------- 依赖检查 ----------
check_dependencies() {
log_step "检查依赖..."