229 lines
8.7 KiB
Bash
229 lines
8.7 KiB
Bash
|
|
#!/usr/bin/env bash
|
|||
|
|
# deploy.sh — admin-xy 生产发布脚本
|
|||
|
|
#
|
|||
|
|
# 用法:
|
|||
|
|
# ./deploy.sh # 构建镜像并部署(首次或更新)
|
|||
|
|
# ./deploy.sh --no-cache # 强制全量重新构建镜像
|
|||
|
|
# ./deploy.sh --stop # 停止并移除 admin-xy 前后端容器(保留数据和配置)
|
|||
|
|
# ./deploy.sh --restart # 重启 admin-xy 前后端容器(不重新构建)
|
|||
|
|
#
|
|||
|
|
# 前提:
|
|||
|
|
# - Docker 及 Docker Compose 已安装
|
|||
|
|
# - /opt/admin-xy/.env 已配置(首次运行时自动生成模板)
|
|||
|
|
|
|||
|
|
set -euo pipefail
|
|||
|
|
|
|||
|
|
# ── 常量 ────────────────────────────────────────────────────────────────────
|
|||
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||
|
|
RELEASE_DIR="/opt/admin-xy"
|
|||
|
|
ENV_FILE="${RELEASE_DIR}/.env"
|
|||
|
|
COMPOSE_FILE="${RELEASE_DIR}/docker-compose.yml"
|
|||
|
|
GIT_CONFIG_DIR="${RELEASE_DIR}/git"
|
|||
|
|
ADMIN_SERVICES=(server web)
|
|||
|
|
|
|||
|
|
# ── 辅助函数 ─────────────────────────────────────────────────────────────────
|
|||
|
|
log() { echo "[$(date '+%H:%M:%S')] $*"; }
|
|||
|
|
err() { echo "[ERROR] $*" >&2; exit 1; }
|
|||
|
|
warn() { echo "[WARN] $*" >&2; }
|
|||
|
|
|
|||
|
|
require_root() {
|
|||
|
|
if [[ $EUID -ne 0 ]]; then
|
|||
|
|
err "该脚本需要 root 权限(请使用 sudo ./deploy.sh)"
|
|||
|
|
fi
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
load_env_file() {
|
|||
|
|
local line key value
|
|||
|
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
|||
|
|
[[ "$line" =~ ^[[:space:]]*$ ]] && continue
|
|||
|
|
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
|||
|
|
[[ "$line" == *"="* ]] || continue
|
|||
|
|
|
|||
|
|
key="${line%%=*}"
|
|||
|
|
value="${line#*=}"
|
|||
|
|
key="${key#"${key%%[![:space:]]*}"}"
|
|||
|
|
key="${key%"${key##*[![:space:]]}"}"
|
|||
|
|
value="${value#"${value%%[![:space:]]*}"}"
|
|||
|
|
value="${value%"${value##*[![:space:]]}"}"
|
|||
|
|
|
|||
|
|
if [[ "$value" != \"*\" && "$value" != \'*\' ]]; then
|
|||
|
|
value="${value%%[[:space:]]#*}"
|
|||
|
|
fi
|
|||
|
|
[[ "$value" =~ ^\"(.*)\"$ ]] && value="${BASH_REMATCH[1]}"
|
|||
|
|
[[ "$value" =~ ^\'(.*)\'$ ]] && value="${BASH_REMATCH[1]}"
|
|||
|
|
export "${key}=${value}"
|
|||
|
|
done < "${ENV_FILE}"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
write_git_config_files() {
|
|||
|
|
local git_name git_email credentials_file
|
|||
|
|
git_name="${GIT_AUTHOR_NAME:-dev-assistant}"
|
|||
|
|
git_email="${GIT_AUTHOR_EMAIL:-dev-assistant@example.com}"
|
|||
|
|
credentials_file="${GIT_CONFIG_DIR}/.git-credentials"
|
|||
|
|
|
|||
|
|
mkdir -p "${GIT_CONFIG_DIR}"
|
|||
|
|
chmod 700 "${GIT_CONFIG_DIR}"
|
|||
|
|
|
|||
|
|
cat > "${GIT_CONFIG_DIR}/.gitconfig" <<EOF
|
|||
|
|
[user]
|
|||
|
|
name = ${git_name}
|
|||
|
|
email = ${git_email}
|
|||
|
|
[credential]
|
|||
|
|
helper = store
|
|||
|
|
[safe]
|
|||
|
|
directory = /workspace
|
|||
|
|
EOF
|
|||
|
|
|
|||
|
|
: > "${credentials_file}"
|
|||
|
|
if [[ -n "${GITEE_USERNAME:-}" && -n "${GITEE_TOKEN:-}" ]]; then
|
|||
|
|
printf 'https://%s:%s@gitee.com\n' "${GITEE_USERNAME}" "${GITEE_TOKEN}" > "${credentials_file}"
|
|||
|
|
else
|
|||
|
|
warn "未配置 GITEE_USERNAME/GITEE_TOKEN,容器内 git push 可能需要重新认证"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
chmod 600 "${GIT_CONFIG_DIR}/.gitconfig" "${credentials_file}"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ── 参数解析 ──────────────────────────────────────────────────────────────────
|
|||
|
|
ACTION="deploy"
|
|||
|
|
NO_CACHE=""
|
|||
|
|
|
|||
|
|
for arg in "$@"; do
|
|||
|
|
case "$arg" in
|
|||
|
|
--no-cache) NO_CACHE="--no-cache" ;;
|
|||
|
|
--stop) ACTION="stop" ;;
|
|||
|
|
--restart) ACTION="restart" ;;
|
|||
|
|
--help|-h)
|
|||
|
|
sed -n '2,13p' "$0" | sed 's/^# \?//'
|
|||
|
|
exit 0
|
|||
|
|
;;
|
|||
|
|
*) err "未知参数:$arg(使用 --help 查看用法)" ;;
|
|||
|
|
esac
|
|||
|
|
done
|
|||
|
|
|
|||
|
|
# ── 发布目录初始化 ────────────────────────────────────────────────────────────
|
|||
|
|
init_release_dir() {
|
|||
|
|
log "初始化发布目录 ${RELEASE_DIR} ..."
|
|||
|
|
|
|||
|
|
mkdir -p "${RELEASE_DIR}"
|
|||
|
|
|
|||
|
|
# 写入 .env 模板(仅首次,避免覆盖已有配置)
|
|||
|
|
if [[ ! -f "${ENV_FILE}" ]]; then
|
|||
|
|
log "生成 .env 配置模板 → ${ENV_FILE}"
|
|||
|
|
cat > "${ENV_FILE}" <<'EOF'
|
|||
|
|
# ── 数据库连接(必填)────────────────────────────────────────────────────────
|
|||
|
|
# JDBC URL 示例:jdbc:mysql://127.0.0.1:3306/adminxy?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia%2FShanghai
|
|||
|
|
SPRING_DATASOURCE_ADMIN_URL=jdbc:mysql://127.0.0.1:3306/adminxy?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia%2FShanghai
|
|||
|
|
SPRING_DATASOURCE_ADMIN_USERNAME=adminxy
|
|||
|
|
SPRING_DATASOURCE_ADMIN_PASSWORD=changeme
|
|||
|
|
|
|||
|
|
# ── JWT 密钥(必填,至少 32 个字符)─────────────────────────────────────────
|
|||
|
|
JWT_SECRET=change-me-in-production-32bytes-min-secret-key-please
|
|||
|
|
|
|||
|
|
# ── 容器内 Git 身份与 Gitee HTTPS 凭据(可选,用于 Agent 提交/推送)────────
|
|||
|
|
GIT_AUTHOR_NAME=dev-assistant
|
|||
|
|
GIT_AUTHOR_EMAIL=dev-assistant@example.com
|
|||
|
|
GITEE_USERNAME=
|
|||
|
|
GITEE_TOKEN=
|
|||
|
|
EOF
|
|||
|
|
warn "已生成 .env 模板,请编辑后再次运行:${ENV_FILE}"
|
|||
|
|
exit 0
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# 校验必填变量
|
|||
|
|
local missing=()
|
|||
|
|
load_env_file
|
|||
|
|
[[ -z "${SPRING_DATASOURCE_ADMIN_URL:-}" ]] && missing+=("SPRING_DATASOURCE_ADMIN_URL")
|
|||
|
|
[[ -z "${SPRING_DATASOURCE_ADMIN_USERNAME:-}" ]] && missing+=("SPRING_DATASOURCE_ADMIN_USERNAME")
|
|||
|
|
[[ -z "${SPRING_DATASOURCE_ADMIN_PASSWORD:-}" ]] && missing+=("SPRING_DATASOURCE_ADMIN_PASSWORD")
|
|||
|
|
[[ -z "${JWT_SECRET:-}" ]] && missing+=("JWT_SECRET")
|
|||
|
|
|
|||
|
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
|||
|
|
err "以下必填项未配置:${missing[*]}(请检查 ${ENV_FILE})"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
write_git_config_files
|
|||
|
|
|
|||
|
|
# 同步 docker-compose.yml
|
|||
|
|
log "同步 docker-compose.yml → ${COMPOSE_FILE}"
|
|||
|
|
cp "${SCRIPT_DIR}/docker-compose.yml" "${COMPOSE_FILE}"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ── 构建镜像 ──────────────────────────────────────────────────────────────────
|
|||
|
|
build_images() {
|
|||
|
|
log "构建 Docker 镜像 ..."
|
|||
|
|
"${SCRIPT_DIR}/build-images.sh" ${NO_CACHE}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ── 部署 ─────────────────────────────────────────────────────────────────────
|
|||
|
|
deploy() {
|
|||
|
|
log "启动 admin-xy 前后端服务 ..."
|
|||
|
|
docker compose \
|
|||
|
|
--project-directory "${RELEASE_DIR}" \
|
|||
|
|
--file "${COMPOSE_FILE}" \
|
|||
|
|
--env-file "${ENV_FILE}" \
|
|||
|
|
up -d "${ADMIN_SERVICES[@]}"
|
|||
|
|
|
|||
|
|
log "当前 admin-xy 前后端容器状态:"
|
|||
|
|
docker compose \
|
|||
|
|
--project-directory "${RELEASE_DIR}" \
|
|||
|
|
--file "${COMPOSE_FILE}" \
|
|||
|
|
ps "${ADMIN_SERVICES[@]}"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ── 停止 ─────────────────────────────────────────────────────────────────────
|
|||
|
|
stop_services() {
|
|||
|
|
if [[ ! -f "${COMPOSE_FILE}" ]]; then
|
|||
|
|
err "未找到 ${COMPOSE_FILE},无法停止(是否已部署?)"
|
|||
|
|
fi
|
|||
|
|
log "停止并移除 admin-xy 前后端容器 ..."
|
|||
|
|
docker compose \
|
|||
|
|
--project-directory "${RELEASE_DIR}" \
|
|||
|
|
--file "${COMPOSE_FILE}" \
|
|||
|
|
stop "${ADMIN_SERVICES[@]}"
|
|||
|
|
docker compose \
|
|||
|
|
--project-directory "${RELEASE_DIR}" \
|
|||
|
|
--file "${COMPOSE_FILE}" \
|
|||
|
|
rm -f "${ADMIN_SERVICES[@]}"
|
|||
|
|
log "admin-xy 前后端容器已停止并移除。"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ── 重启 ─────────────────────────────────────────────────────────────────────
|
|||
|
|
restart_services() {
|
|||
|
|
if [[ ! -f "${COMPOSE_FILE}" ]]; then
|
|||
|
|
err "未找到 ${COMPOSE_FILE},请先执行完整部署:./deploy.sh"
|
|||
|
|
fi
|
|||
|
|
log "重启 admin-xy 前后端服务 ..."
|
|||
|
|
docker compose \
|
|||
|
|
--project-directory "${RELEASE_DIR}" \
|
|||
|
|
--file "${COMPOSE_FILE}" \
|
|||
|
|
--env-file "${ENV_FILE}" \
|
|||
|
|
restart "${ADMIN_SERVICES[@]}"
|
|||
|
|
log "当前 admin-xy 前后端容器状态:"
|
|||
|
|
docker compose \
|
|||
|
|
--project-directory "${RELEASE_DIR}" \
|
|||
|
|
--file "${COMPOSE_FILE}" \
|
|||
|
|
ps "${ADMIN_SERVICES[@]}"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# ── 主流程 ────────────────────────────────────────────────────────────────────
|
|||
|
|
require_root
|
|||
|
|
|
|||
|
|
case "${ACTION}" in
|
|||
|
|
deploy)
|
|||
|
|
log "=== admin-xy 生产部署开始 ==="
|
|||
|
|
init_release_dir
|
|||
|
|
build_images
|
|||
|
|
deploy
|
|||
|
|
log "=== 部署完成 ==="
|
|||
|
|
log "前端:http://<server-ip>:9001"
|
|||
|
|
log "后端:http://<server-ip>:9010"
|
|||
|
|
;;
|
|||
|
|
stop)
|
|||
|
|
stop_services
|
|||
|
|
;;
|
|||
|
|
restart)
|
|||
|
|
restart_services
|
|||
|
|
;;
|
|||
|
|
esac
|