diff --git a/Dockerfile b/Dockerfile index d387f17..2f3f4d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM node:22-alpine AS build +ARG BASE_IMAGE=node:22-alpine +FROM ${BASE_IMAGE} AS build WORKDIR /app RUN apk add --no-cache openssl COPY package*.json ./ @@ -9,7 +10,7 @@ COPY tsconfig.json ./ COPY src ./src RUN npm run build -FROM node:22-alpine +FROM ${BASE_IMAGE} WORKDIR /app ENV NODE_ENV=production RUN apk add --no-cache openssl diff --git a/scripts/git-build-deploy.ps1 b/scripts/git-build-deploy.ps1 index 9aa69d8..078f586 100644 --- a/scripts/git-build-deploy.ps1 +++ b/scripts/git-build-deploy.ps1 @@ -69,10 +69,13 @@ image_tag="production-${short_sha}" local_commit="localhost:${REGISTRY_HOST##*:}/${IMAGE_NAME}:${image_tag}" local_latest="localhost:${REGISTRY_HOST##*:}/${IMAGE_NAME}:production-latest" remote_commit="${REGISTRY_HOST}/${IMAGE_NAME}:${image_tag}" +base_image="localhost:${REGISTRY_HOST##*:}/yyd-base/node:22-alpine" log "构建提交 ${commit_sha}" +docker pull "$base_image" >/dev/null \ + || fail "内部基础镜像不可用: $base_image" docker pull "$local_latest" >/dev/null 2>&1 || true -build_args=() +build_args=(--build-arg "BASE_IMAGE=$base_image") if docker image inspect "$local_latest" >/dev/null 2>&1; then build_args+=(--cache-from "$local_latest") fi @@ -97,9 +100,42 @@ ssh -o BatchMode=yes "$PRODUCTION_SERVER" \ set -Eeuo pipefail target=/mnt/PoolOne/apps/youyidian-notification-center +backup_root=/mnt/PoolOne/apps/youyidian-notification-center-backups cd "$target" test -f .env test -f docker-compose.yml +mkdir -p "$backup_root" +stamp="$(date +%Y%m%d%H%M%S)" +cp -a .env "$backup_root/env-before-git-release-$stamp" +chmod 600 "$backup_root/env-before-git-release-$stamp" + +if docker container inspect youyidian-notification-center >/dev/null 2>&1; then + was_running="$(docker inspect -f '{{.State.Running}}' youyidian-notification-center)" + if [ "$was_running" = true ]; then + docker pause youyidian-notification-center >/dev/null + cleanup_unpause() { + docker unpause youyidian-notification-center >/dev/null 2>&1 || true + } + trap cleanup_unpause EXIT INT TERM + fi + data_backup="$backup_root/notification-data-before-git-release-$stamp" + mkdir -p "$data_backup" + # 整体复制可同时保存 notifications.db、-journal、-wal 与 -shm。 + if ! docker cp youyidian-notification-center:/app/data/. "$data_backup/" \ + || ! test -s "$data_backup/notifications.db"; then + fail_message='通知中心 SQLite 备份失败,拒绝重建生产容器' + if [ "$was_running" = true ]; then + docker unpause youyidian-notification-center >/dev/null || true + trap - EXIT INT TERM + fi + printf '[ERR] %s\n' "$fail_message" >&2 + exit 1 + fi + if [ "$was_running" = true ]; then + docker unpause youyidian-notification-center >/dev/null + trap - EXIT INT TERM + fi +fi old_image="$(docker inspect -f '{{.Config.Image}}' youyidian-notification-center 2>/dev/null || true)" if [ -n "$old_image" ] && docker image inspect "$old_image" >/dev/null 2>&1; then