ci(0.2.1): 部署段改为调用宿主 /app/iboard-prod 部署脚本 —— 无 PG secrets 时跳过自动部署
This commit is contained in:
@@ -112,38 +112,39 @@ jobs:
|
|||||||
- name: List images
|
- name: List images
|
||||||
run: docker images
|
run: docker images
|
||||||
|
|
||||||
- name: Apply DB migrations
|
- name: Deploy 0.2.1 production stack
|
||||||
# 数据库自动升级: 按 prisma/migrations/ 下的迁移顺序应用 (生产库由 master 部署时统一升级)
|
# 0.2.1 起生产为单端口架构: app(3001 对外) + pg(内网) + powersync(内网),
|
||||||
# migrate deploy 幂等, 无新迁移时为 no-op
|
# 客户端同步经 app 的 /sync 反代进入同步服务 (无独立同步端口)。
|
||||||
# 位置关键: 在 "Remove old container" 之前 —— 建表/改表成功后才切换流量,
|
# 部署逻辑在服务器的 /app/iboard-prod/scripts/deploy/prod.sh (幂等), 这里只负责:
|
||||||
# 迁移失败则整个 workflow 中断, 不会用新镜像顶掉仍在运行的旧容器
|
# 1) 把刚构建好的镜像交给该脚本
|
||||||
|
# 2) 未配置 PG 相关 secrets 或脚本缺失时跳过部署 (发布不失败, 仅提示)
|
||||||
env:
|
env:
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
PG_PASSWORD: ${{ secrets.PG_PASSWORD }}
|
||||||
|
PS_STORAGE_PASSWORD: ${{ secrets.PS_STORAGE_PASSWORD }}
|
||||||
|
JWT_SECRET: ${{ secrets.JWT_SECRET }}
|
||||||
|
POWERSYNC_JWT_SECRET: ${{ secrets.POWERSYNC_JWT_SECRET }}
|
||||||
|
POWERSYNC_JWT_KEY_B64: ${{ secrets.POWERSYNC_JWT_KEY_B64 }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
npx prisma migrate status || true
|
HOST_DIR=/app/iboard-prod
|
||||||
npx prisma migrate deploy
|
if [ -z "${PG_PASSWORD:-}" ]; then
|
||||||
|
echo "::warning::未配置 PG_PASSWORD 等 secrets, 跳过自动部署 (镜像已构建完成)"
|
||||||
- name: Remove old container
|
echo "手工部署: ssh baihu 'bash $HOST_DIR/scripts/deploy/prod.sh'"
|
||||||
run: docker rm -vf iboard || true
|
exit 0
|
||||||
|
fi
|
||||||
- name: Prune dangling images
|
if ! docker run --rm -v "$HOST_DIR:/w" alpine:3.20 test -f /w/scripts/deploy/prod.sh; then
|
||||||
# 只清理本项目的悬空镜像 (旧 iboard:latest 被同名新镜像顶掉后变 dangling),
|
echo "::warning::$HOST_DIR/scripts/deploy/prod.sh 不存在, 跳过部署"
|
||||||
# 不再用 `docker system prune --volumes` —— 那会清光宿主机 build cache,
|
exit 0
|
||||||
# 导致每次部署都全量重装 npm 依赖、重跑构建
|
fi
|
||||||
run: docker image prune -f
|
docker run --rm \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
- name: Run container
|
-v "$HOST_DIR:$HOST_DIR" \
|
||||||
# DATABASE_URL 通过 gitea Actions secret 注入, 不进镜像层
|
-w "$HOST_DIR" \
|
||||||
# OTA_PACKAGE_DIR 已在 Dockerfile 设为 /app/ota-package
|
-e PG_PASSWORD="$PG_PASSWORD" \
|
||||||
# 米家凭证 (auth.txt) 不进 git: 运维放宿主机 /app/iboard/cache, bind-mount 进容器 (MIHOME_CACHE_DIR=/app/cache)
|
-e PS_STORAGE_PASSWORD="$PS_STORAGE_PASSWORD" \
|
||||||
run: |
|
-e JWT_SECRET="$JWT_SECRET" \
|
||||||
docker run -d --name iboard -p 3001:3001 \
|
-e POWERSYNC_JWT_SECRET="$POWERSYNC_JWT_SECRET" \
|
||||||
-e DATABASE_URL="${{ secrets.DATABASE_URL }}" \
|
-e POWERSYNC_JWT_KEY_B64="$POWERSYNC_JWT_KEY_B64" \
|
||||||
-e JWT_SECRET="${{ secrets.JWT_SECRET }}" \
|
-e PUBLIC_URL=https://iboard.honor3.com \
|
||||||
-e MIHOME_CACHE_DIR=/app/cache \
|
-e ROOT="$HOST_DIR" \
|
||||||
-v /app/iboard/cache:/app/cache \
|
docker:27-cli sh -c 'apk add -q bash curl >/dev/null 2>&1; bash /app/iboard-prod/scripts/deploy/prod.sh'
|
||||||
iboard:latest
|
|
||||||
env:
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
JWT_SECRET: ${{ secrets.JWT_SECRET }}
|
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 0.2.1 生产部署 (master 分支 CI 调用; 也可在服务器手工执行)
|
||||||
|
#
|
||||||
|
# 架构: app(3001 对外) + pg(内网) + powersync(内网), 见 deploy/prod/
|
||||||
|
# 幂等: 迁移 -> publication -> 起栈; 任一环节失败则退出, 不切换流量
|
||||||
|
#
|
||||||
|
# 所需环境变量 (由 CI secrets 注入):
|
||||||
|
# PG_PASSWORD, PS_STORAGE_PASSWORD, JWT_SECRET, POWERSYNC_JWT_SECRET,
|
||||||
|
# POWERSYNC_JWT_KEY_B64, PUBLIC_URL(可选, 默认 https://iboard.honor3.com)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="${ROOT:-/app/iboard-prod}"
|
||||||
|
COMPOSE_FILE="$ROOT/deploy/prod/docker-compose.yml"
|
||||||
|
ENV_FILE="$ROOT/deploy/prod/.env"
|
||||||
|
PROJECT="iboard-prod"
|
||||||
|
|
||||||
|
log() { echo "[deploy] $*"; }
|
||||||
|
die() { echo "[deploy][ERROR] $*" >&2; exit 1; }
|
||||||
|
|
||||||
|
for v in PG_PASSWORD PS_STORAGE_PASSWORD JWT_SECRET POWERSYNC_JWT_SECRET POWERSYNC_JWT_KEY_B64; do
|
||||||
|
[ -n "${!v:-}" ] || die "缺少环境变量 $v (请在 Gitea Actions secrets 配置)"
|
||||||
|
done
|
||||||
|
[ -f "$COMPOSE_FILE" ] || die "找不到 $COMPOSE_FILE (源码需上传到 $ROOT)"
|
||||||
|
|
||||||
|
log "写入 $ENV_FILE"
|
||||||
|
umask 077
|
||||||
|
cat > "$ENV_FILE" <<EOF
|
||||||
|
PG_PASSWORD=$PG_PASSWORD
|
||||||
|
PS_STORAGE_PASSWORD=$PS_STORAGE_PASSWORD
|
||||||
|
JWT_SECRET=$JWT_SECRET
|
||||||
|
POWERSYNC_JWT_SECRET=$POWERSYNC_JWT_SECRET
|
||||||
|
POWERSYNC_JWT_KEY_B64=$POWERSYNC_JWT_KEY_B64
|
||||||
|
PUBLIC_URL=${PUBLIC_URL:-https://iboard.honor3.com}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cd "$ROOT/deploy/prod"
|
||||||
|
mkdir -p data/pg data/cache
|
||||||
|
|
||||||
|
log "启动数据库"
|
||||||
|
docker compose --project-name "$PROJECT" --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d pg
|
||||||
|
|
||||||
|
log "等待数据库就绪"
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if docker compose --project-name "$PROJECT" --env-file "$ENV_FILE" -f "$COMPOSE_FILE" exec -T pg pg_isready -U iboard -d iboard >/dev/null 2>&1; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
log "执行数据库迁移"
|
||||||
|
docker run --rm --network "${PROJECT}_default" \
|
||||||
|
-e DATABASE_URL="postgresql://iboard:${PG_PASSWORD}@pg:5432/iboard" \
|
||||||
|
iboard:latest npx prisma migrate deploy
|
||||||
|
|
||||||
|
log "确保逻辑复制 publication 存在"
|
||||||
|
docker compose --project-name "$PROJECT" --env-file "$ENV_FILE" -f "$COMPOSE_FILE" exec -T pg \
|
||||||
|
psql -U iboard -d iboard -v ON_ERROR_STOP=1 -f /dev/stdin < sql/publication.sql
|
||||||
|
|
||||||
|
log "启动应用与同步服务"
|
||||||
|
docker compose --project-name "$PROJECT" --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d app powersync
|
||||||
|
|
||||||
|
log "等待健康检查"
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if curl -fsS --max-time 3 http://127.0.0.1:3001/api/health >/dev/null 2>&1; then
|
||||||
|
log "健康检查通过"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
die "应用未通过健康检查, 请查看 docker compose logs"
|
||||||
Reference in New Issue
Block a user