fix(deploy): 支持 full-themes 六合一包部署并统一 shell 脚本 LF 换行

This commit is contained in:
mars
2026-07-10 13:58:34 +08:00
parent cca74310ed
commit 4a95793d21
7 changed files with 212 additions and 21 deletions

View File

@@ -3,6 +3,7 @@
DEPLOY_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$DEPLOY_LIB_DIR/.." && pwd)"
COMPOSE_FILE="$ROOT/docker-compose.prod.yml"
COMPOSE_THEMES_FILE="$ROOT/docker-compose.themes.yml"
ENV_FILE="$ROOT/.env.docker"
ENV_EXAMPLE_FILE="$ROOT/.env.docker.example"
BACKUP_DIR="$ROOT/backups"
@@ -12,6 +13,7 @@ CURRENT_RELEASE_FILE="$DEPLOY_STATE_DIR/current-release.env"
PREVIOUS_RELEASE_FILE="$DEPLOY_STATE_DIR/previous-release.env"
DEPLOY_IMAGE_TAG="${DEPLOY_IMAGE_TAG:-}"
DEPLOY_WITH_THEMES="${DEPLOY_WITH_THEMES:-false}"
LAST_DB_BACKUP=""
LAST_UPLOADS_BACKUP=""
@@ -55,18 +57,95 @@ infer_image_tag_from_tar() {
local base tag
base="$(basename "$image_tar")"
tag="${base#thebet365-full-themes-}"
tag="${tag%.tar}"
if [ "$tag" != "$base" ] && [ -n "$tag" ]; then
printf '%s' "$tag"
return 0
fi
tag="${base#thebet365-images-}"
tag="${tag%.tar}"
if [ "$tag" != "$base" ] && [ -n "$tag" ]; then
printf '%s' "$tag"
fi
}
compose() {
is_full_themes_tar() {
local image_tar="$1"
case "$(basename "$image_tar")" in
thebet365-full-themes-*.tar) return 0 ;;
*) return 1 ;;
esac
}
themes_enabled() {
[ "$DEPLOY_WITH_THEMES" = true ]
}
player_image_tag() {
local tag
tag="$(env_value PLAYER_IMAGE_TAG)"
tag="${tag:-main}"
validate_image_tag "$tag"
printf '%s' "$tag"
}
theme_player_tag() {
local key="$1"
local default_tag="$2"
local tag
tag="$(env_value "$key")"
tag="${tag:-$default_tag}"
validate_image_tag "$tag"
printf '%s' "$tag"
}
compose() {
local tag player_tag compose_args=(-f "$COMPOSE_FILE")
tag="$(current_image_tag)"
IMAGE_TAG="$tag" docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" "$@"
player_tag="$(player_image_tag)"
if themes_enabled; then
[ -f "$COMPOSE_THEMES_FILE" ] || die "缺少 $COMPOSE_THEMES_FILE,无法启动四套 player"
compose_args+=(-f "$COMPOSE_THEMES_FILE")
fi
IMAGE_TAG="$tag" \
PLAYER_IMAGE_TAG="$player_tag" \
docker compose "${compose_args[@]}" --env-file "$ENV_FILE" "$@"
}
stack_app_services() {
if themes_enabled; then
printf '%s' "api player player2 player3 player4 admin"
else
printf '%s' "api player admin"
fi
}
enable_themes_deploy() {
DEPLOY_WITH_THEMES=true
export DEPLOY_WITH_THEMES
log "四套 player 主题部署已启用"
}
maybe_enable_themes_from_tar() {
local image_tar="$1"
if is_full_themes_tar "$image_tar"; then
enable_themes_deploy
fi
}
load_themes_from_release() {
local val
[ -f "$CURRENT_RELEASE_FILE" ] || return 1
val="$(grep -E '^deploy_with_themes=' "$CURRENT_RELEASE_FILE" 2>/dev/null | tail -1 | cut -d= -f2- || true)"
if [ "$val" = true ]; then
enable_themes_deploy
return 0
fi
return 1
}
ensure_env_file() {
@@ -203,6 +282,11 @@ wait_for_service_health() {
wait_for_stack_ready() {
wait_for_service_health api 180
wait_for_service_health player 120
if themes_enabled; then
wait_for_service_health player2 120
wait_for_service_health player3 120
wait_for_service_health player4 120
fi
wait_for_service_health admin 120
}
@@ -214,8 +298,13 @@ start_infra() {
}
build_app_images() {
log "构建 api / player / admin 镜像: $(current_image_tag)"
compose build api player admin
if themes_enabled; then
log "构建 api / player / player2 / player3 / player4 / admin 镜像"
compose build api player player2 player3 player4 admin
else
log "构建 api / player / admin 镜像: $(current_image_tag)"
compose build api player admin
fi
}
load_image_tar() {
@@ -225,12 +314,28 @@ load_image_tar() {
docker load -i "$image_tar"
}
require_image() {
local ref="$1"
docker image inspect "$ref" >/dev/null 2>&1 || die "缺少镜像: $ref"
}
require_images_for_current_tag() {
local tag
local tag player_tag t2 t3 t4
tag="$(current_image_tag)"
docker image inspect "thebet365-api:$tag" >/dev/null 2>&1 || die "缺少镜像: thebet365-api:$tag"
docker image inspect "thebet365-player:$tag" >/dev/null 2>&1 || die "缺少镜像: thebet365-player:$tag"
docker image inspect "thebet365-admin:$tag" >/dev/null 2>&1 || die "缺少镜像: thebet365-admin:$tag"
player_tag="$(player_image_tag)"
require_image "thebet365-api:$tag"
require_image "thebet365-player:$player_tag"
require_image "thebet365-admin:$tag"
if themes_enabled; then
t2="$(theme_player_tag PLAYER2_IMAGE_TAG theme-2)"
t3="$(theme_player_tag PLAYER3_IMAGE_TAG theme-3)"
t4="$(theme_player_tag PLAYER4_IMAGE_TAG theme-4)"
require_image "thebet365-player:$t2"
require_image "thebet365-player:$t3"
require_image "thebet365-player:$t4"
fi
}
run_prisma_migrations() {
@@ -343,9 +448,10 @@ current_release_tag() {
record_release_state() {
local source="${1:-deploy}"
local tag stamp safe_tag manifest previous_tag
local tag player_tag t2 t3 t4 stamp safe_tag manifest previous_tag
tag="$(current_image_tag)"
player_tag="$(player_image_tag)"
stamp="$(date -u +%Y%m%dT%H%M%SZ)"
safe_tag="$(printf '%s' "$tag" | tr -c 'A-Za-z0-9_.-' '-')"
manifest="$RELEASES_DIR/${stamp}-${safe_tag}.env"
@@ -361,9 +467,18 @@ record_release_state() {
printf 'previous_tag=%s\n' "$previous_tag"
printf 'deployed_at=%s\n' "$stamp"
printf 'source=%s\n' "$source"
printf 'deploy_with_themes=%s\n' "$DEPLOY_WITH_THEMES"
printf 'api_image=thebet365-api:%s\n' "$tag"
printf 'player_image=thebet365-player:%s\n' "$tag"
printf 'player_image=thebet365-player:%s\n' "$player_tag"
printf 'admin_image=thebet365-admin:%s\n' "$tag"
if themes_enabled; then
t2="$(theme_player_tag PLAYER2_IMAGE_TAG theme-2)"
t3="$(theme_player_tag PLAYER3_IMAGE_TAG theme-3)"
t4="$(theme_player_tag PLAYER4_IMAGE_TAG theme-4)"
printf 'player2_image=thebet365-player:%s\n' "$t2"
printf 'player3_image=thebet365-player:%s\n' "$t3"
printf 'player4_image=thebet365-player:%s\n' "$t4"
fi
[ -n "$LAST_DB_BACKUP" ] && printf 'db_backup=%s\n' "$LAST_DB_BACKUP"
[ -n "$LAST_UPLOADS_BACKUP" ] && printf 'uploads_backup=%s\n' "$LAST_UPLOADS_BACKUP"
} > "$manifest"
@@ -373,21 +488,40 @@ record_release_state() {
}
print_stack_urls() {
local player_port admin_port bind_addr tag
local player_port player2_port player3_port player4_port admin_port bind_addr tag player_tag
player_port="$(env_value PLAYER_PORT)"
player2_port="$(env_value PLAYER2_PORT)"
player3_port="$(env_value PLAYER3_PORT)"
player4_port="$(env_value PLAYER4_PORT)"
admin_port="$(env_value ADMIN_PORT)"
bind_addr="$(env_value BIND_ADDR)"
tag="$(current_image_tag)"
player_tag="$(player_image_tag)"
player_port="${player_port:-8082}"
player2_port="${player2_port:-8083}"
player3_port="${player3_port:-8084}"
player4_port="${player4_port:-8085}"
admin_port="${admin_port:-8081}"
bind_addr="${bind_addr:-127.0.0.1}"
printf '\n'
printf '%s\n' "部署完成:"
printf '%s\n' " 镜像 tag: ${tag}"
printf '%s\n' " 玩家端: http://${bind_addr}:${player_port}"
printf '%s\n' " api/admin 镜像 tag: ${tag}"
printf '%s\n' " player 镜像 tag: ${player_tag}"
if themes_enabled; then
printf '%s\n' " 玩家端 main: http://${bind_addr}:${player_port}"
printf '%s\n' " 玩家端 theme-2: http://${bind_addr}:${player2_port}"
printf '%s\n' " 玩家端 theme-3: http://${bind_addr}:${player3_port}"
printf '%s\n' " 玩家端 theme-4: http://${bind_addr}:${player4_port}"
else
printf '%s\n' " 玩家端: http://${bind_addr}:${player_port}"
fi
printf '%s\n' " 管理端: http://${bind_addr}:${admin_port}"
printf '%s\n' " API: 仅在 Docker 网络内暴露,由 player/admin 容器和宝塔反代链路访问"
printf '%s\n' " 状态: docker compose -f docker-compose.prod.yml --env-file .env.docker ps"
if themes_enabled; then
printf '%s\n' " 状态: docker compose -f docker-compose.prod.yml -f docker-compose.themes.yml --env-file .env.docker ps"
else
printf '%s\n' " 状态: docker compose -f docker-compose.prod.yml --env-file .env.docker ps"
fi
printf '%s\n' " 当前发布: .deploy/current-release.env"
}