Files
creator-hub/docs/deployment.md
T

286 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CreatorHub 部署
本文档适用于当前阶段 A:在一台 Linux 主机上通过 Docker Compose 部署。控制面使用单用户 HTTP Basic Auth;当前不提供 RBAC 或多租户隔离。
## 部署内容
`compose.yaml` 会启动以下服务:
- `creator-hub`:Go 1.26 控制面,同时提供 React 19/Vite 8 构建的静态页面;
- `docker-gateway`:受限 Docker API 网关,是唯一挂载 `/var/run/docker.sock` 的服务;
- `postgres`:PostgreSQL 17,数据保存在 `creatorhub_postgres` 命名卷;
- 浏览器容器:由网关按需创建,镜像引用由平台「镜像版本」页配置(缺失时网关自动拉取),Profile 保存在 `creatorhub-profile-<别名>` 命名卷。
控制面发布到宿主机所有网卡,局域网内可直接访问;浏览器容器可访问外网。
`creator-hub` 会等待 `docker-gateway` 健康检查通过后再启动。
## 前置条件
- Linux 主机;
- Docker Engine 26 或兼容版本;
- Docker Compose v2;
- 当前用户可访问 Docker daemon;
- 可访问镜像仓库(如 `git.ipao.vip`),并已完成登录(如仓库要求认证);镜像也可不在宿主机预拉取,网关会在缺失时按引用自动拉取;
- `curl`,用于部署后检查。
在仓库根目录执行预检:
```bash
test -S /var/run/docker.sock
docker info >/dev/null
docker compose version
: "${CONTROL_PLANE_USERNAME:?set CONTROL_PLANE_USERNAME or fill .env}"
: "${CONTROL_PLANE_PASSWORD:?set CONTROL_PLANE_PASSWORD or fill .env}"
docker compose config --quiet
```
## 首次部署
以下命令应在同一个 shell、仓库根目录执行。`DOCKER_GID` 必须与宿主机 Docker socket 的组一致;`CREATORHUB_PORT` 控制控制面的宿主机端口。
```bash
export DOCKER_GID="$(stat -c '%g' /var/run/docker.sock)"
export CREATORHUB_PORT=8080
export GATEWAY_TOKEN="$(openssl rand -hex 24)" # 亦可在 .env 中设置
export CONTROL_PLANE_USERNAME=creatorhub
export CONTROL_PLANE_PASSWORD="$(openssl rand -hex 24)"
docker compose config --quiet
docker compose up --detach --build
```
控制面启动时会连接 PostgreSQL,并在事务和 advisory lock 保护下自动执行前向迁移。迁移失败时控制面会退出,由 Compose 按 `restart: unless-stopped` 重启;先检查日志,不要删除数据卷。
### 首次配置
服务起来后打开 <http://127.0.0.1:${CREATORHUB_PORT}>:
1. 「网关管理」页注册网关:名称如 `gw-main`,Endpoint `http://docker-gateway:8081`,令牌填 `GATEWAY_TOKEN` 的值(即 `openssl rand -hex 24` 生成的值)。
2. 「镜像版本」页添加可用镜像,如版本 `148.0.7778.215`、引用 `git.ipao.vip/rogee/fingerprint-chromium:148.0.7778.215`(或 `@sha256:` 摘要引用)。
3. 「运行环境」页创建环境:中文名 + 小写别名 + 指纹参数,容器名 `creatorhub-browser-<别名>`,Profile 卷 `creatorhub-profile-<别名>`。
## 部署验证
```bash
curl --fail --silent --show-error \
--retry 30 --retry-delay 2 --retry-connrefused \
--output /dev/null "http://127.0.0.1:${CREATORHUB_PORT}/healthz"
curl --fail --silent --show-error \
--retry 30 --retry-delay 2 --retry-connrefused \
--user "${CONTROL_PLANE_USERNAME}:${CONTROL_PLANE_PASSWORD}" \
"http://127.0.0.1:${CREATORHUB_PORT}/api/browsers" >/dev/null
docker compose exec -T postgres \
psql -U creatorhub -d creatorhub -tAc \
'SELECT 1 FROM schema_migration WHERE version = 12;' \
| grep -qx 1
docker compose ps
```
健康检查应成功,浏览器列表接口应返回 JSON,迁移查询当前应输出 `1`,三个 Compose 服务应为运行状态。然后访问 <http://127.0.0.1:8080>;修改过 `CREATORHUB_PORT` 时使用对应端口。
排障时读取结构化服务日志:
```bash
docker compose logs --tail=200 creator-hub docker-gateway postgres
```
## 配置
Compose 部署时通常只需设置以下宿主机变量:
| 变量 | 默认值 | 说明 |
| --- | --- | --- |
| `CREATORHUB_PORT` | `8080` | 控制面宿主机端口,局域网可访问 |
| `DOCKER_GID` | `999` | Docker socket 的宿主机组 ID;必须按实际值设置 |
| `GATEWAY_TOKEN` | `dev-creatorhub-gateway-token` | 网关与控制面共享的 Bearer 令牌;生产须改为随机值,并同步填入网关注册表单 |
| `CONTROL_PLANE_USERNAME` | 无(必填) | 控制面唯一用户;不能包含冒号 |
| `CONTROL_PLANE_PASSWORD` | 无(必填) | 控制面密码,至少 16 字节;使用随机值 |
服务本身支持并校验以下环境变量;`compose.yaml` 会在控制面凭据缺失或为空时拒绝渲染:
| 服务 | 变量 | 当前 Compose 值 |
| --- | --- | --- |
| `creator-hub` | `LISTEN_ADDR` | 默认 `:8080` |
| `creator-hub` | `WEB_DIR` | 镜像内固定为 `/app/web` |
| `creator-hub` | `DATABASE_URL` | `postgres://creatorhub@postgres/creatorhub?sslmode=disable` |
| `creator-hub` | `LOG_LEVEL` | 默认 `info` |
| `creator-hub` | `CONTROL_PLANE_USERNAME` | 必填;HTTP Basic Auth 用户名 |
| `creator-hub` | `CONTROL_PLANE_PASSWORD` | 必填且至少 16 字节;不会写入日志或响应 |
| `docker-gateway` | `LISTEN_ADDR` | 默认 `:8081` |
| `docker-gateway` | `DOCKER_SOCKET` | 默认值和 Compose 挂载均固定为 `/var/run/docker.sock`;不能只覆盖环境变量 |
| `docker-gateway` | `BROWSER_NETWORK` | `creatorhub_browser` |
| `docker-gateway` | `GATEWAY_TOKEN` | 与平台注册值一致,长度 ≥16;`/v1` 全部接口校验 Bearer 令牌 |
| `docker-gateway` | `LOG_LEVEL` | 默认 `info` |
不要把凭据写入仓库或 Compose 文件。
### P0-lite 停机通知
当前只使用 `creator-hub` 的专用 Logrus JSON logger 作为通知渠道;它固定输出警告,不继承业务 `LOG_LEVEL`。选择它是因为 Compose 已可靠收集服务日志,不需要新增外部账号、凭据、网络重试或通知依赖。仅 `policy_hold` 和 `needs_confirmation` 会产生 `operator attention required`,字段限定为 `event_type`、`reason_code`、账号/任务 ID;不会包含请求头、Secret 引用或凭据值。运维可用下列命令接入现有日志采集或人工查看:
```bash
docker compose logs creator-hub | grep 'operator attention required'
```
该渠道是单实例 P0-lite 能力,不保证外部送达、升级或确认回执;只有出现明确的多渠道/送达需求时才增加 webhook 或消息平台。
## 更新与回滚
更新前记录当前版本并备份数据库:
```bash
set -Eeuo pipefail
git rev-parse HEAD
umask 077
export BACKUP_FILE="$(pwd)/creatorhub-$(date +%Y%m%d-%H%M%S).dump"
docker compose exec -T postgres \
pg_dump -U creatorhub -d creatorhub --format=custom \
> "$BACKUP_FILE"
test -s "$BACKUP_FILE"
docker compose exec -T postgres pg_restore --list \
< "$BACKUP_FILE" >/dev/null
```
拉取已审核版本后,重新执行部署和验证:
```bash
set -Eeuo pipefail
git pull --ff-only
export DOCKER_GID="$(stat -c '%g' /var/run/docker.sock)"
export CREATORHUB_PORT=8080
docker compose config --quiet
docker compose up --detach --build
```
镜像版本升级在页面「运行环境 → 升级」完成:平台会停止并删除旧容器(保留 Profile 卷),用新镜像引用与原指纹参数重建后启动;失败时直接重试即可,无需回滚。
数据库迁移只支持安全前进,不提供自动破坏性回滚。需要同时恢复旧代码和更新前数据库时,修改下面两个变量后**整块执行一次**;不要逐行或拆块执行。预检、恢复演练、动态容器停止、停服、主库恢复、提交切换和启动都位于同一个 fail-fast subshell 中。
```bash
(
set -Eeuo pipefail
BACKUP_FILE=/absolute/path/to/creatorhub-YYYYmmdd-HHMMSS.dump
RESTORE_REV=PREVIOUS_REVIEWED_COMMIT_SHA
: "${BACKUP_FILE:?set BACKUP_FILE to the absolute archive path}"
: "${RESTORE_REV:?set RESTORE_REV to the previous reviewed commit SHA}"
test -r "$BACKUP_FILE"
test -s "$BACKUP_FILE"
git cat-file -e "${RESTORE_REV}^{commit}"
docker compose exec -T postgres pg_restore --list \
< "$BACKUP_FILE" >/dev/null
docker compose exec -T postgres \
dropdb --if-exists --force -U creatorhub creatorhub_restore_check
docker compose exec -T postgres \
createdb -U creatorhub creatorhub_restore_check
docker compose exec -T postgres \
pg_restore -U creatorhub -d creatorhub_restore_check \
--exit-on-error --no-owner --no-privileges \
< "$BACKUP_FILE"
docker compose exec -T postgres \
psql -U creatorhub -d creatorhub_restore_check -v ON_ERROR_STOP=1 -tAc \
'SELECT 1 FROM schema_migration WHERE version = 12;' \
| grep -qx 1
docker compose exec -T postgres \
dropdb --force -U creatorhub creatorhub_restore_check
list_running_browsers() {
docker ps --quiet \
--filter 'name=^creatorhub-browser-' \
--filter 'label=io.creatorhub.managed=true' \
--filter 'label=io.creatorhub.runtime-id'
}
browser_ids="$(list_running_browsers)" || exit 1
for browser_id in $browser_ids; do
if ! docker stop "$browser_id"; then
docker rm --force "$browser_id"
fi
done
browser_ids="$(list_running_browsers)" || exit 1
test -z "$browser_ids"
docker compose stop creator-hub docker-gateway
umask 077
PRE_ROLLBACK_BACKUP="$(pwd)/creatorhub-pre-rollback-$(date +%Y%m%d-%H%M%S).dump"
docker compose exec -T postgres \
pg_dump -U creatorhub -d creatorhub --format=custom \
> "$PRE_ROLLBACK_BACKUP"
test -s "$PRE_ROLLBACK_BACKUP"
docker compose exec -T postgres pg_restore --list \
< "$PRE_ROLLBACK_BACKUP" >/dev/null
test -r "$BACKUP_FILE"
test -s "$BACKUP_FILE"
git cat-file -e "${RESTORE_REV}^{commit}"
docker compose exec -T postgres pg_restore --list \
< "$BACKUP_FILE" >/dev/null
docker compose exec -T postgres \
dropdb --if-exists --force -U creatorhub creatorhub
docker compose exec -T postgres createdb -U creatorhub creatorhub
docker compose exec -T postgres \
pg_restore -U creatorhub -d creatorhub \
--exit-on-error --no-owner --no-privileges \
< "$BACKUP_FILE"
docker compose exec -T postgres \
psql -U creatorhub -d creatorhub -v ON_ERROR_STOP=1 -tAc \
'SELECT 1 FROM schema_migration WHERE version = 12;' \
| grep -qx 1
git switch --detach "$RESTORE_REV"
if ! docker compose up --detach --build; then
docker compose stop creator-hub docker-gateway || true
exit 1
fi
)
```
任何命令失败时 subshell 立即退出;若失败发生在主库 `dropdb` 之后,应用保持停止。`docker compose up` 自身失败时也会显式停回应用服务。成功后重新执行“部署验证”。不要直接删除数据卷或手工改写迁移记录。
## 停止与数据保留
`docker compose stop/down` 不管理网关动态创建的浏览器容器;直接执行会留下运行中的浏览器和活动会话。先严格按固定容器名前缀及两个管理标签筛选并停止;只有单个容器停止失败或超时时才强制删除。命令不带 `--volumes`,因此 Profile 卷仍会保留:
```bash
set -Eeuo pipefail
list_running_browsers() {
docker ps --quiet \
--filter 'name=^creatorhub-browser-' \
--filter 'label=io.creatorhub.managed=true' \
--filter 'label=io.creatorhub.runtime-id'
}
browser_ids="$(list_running_browsers)" || exit 1
for browser_id in $browser_ids; do
if ! docker stop "$browser_id"; then
docker rm --force "$browser_id"
fi
done
browser_ids="$(list_running_browsers)" || exit 1
test -z "$browser_ids"
docker compose stop
```
恢复服务使用 `docker compose up --detach`。需要删除服务容器和网络但保留数据时使用:
```bash
docker compose down
```
不要执行 `docker compose down --volumes`:它会删除 PostgreSQL 数据卷。浏览器 Profile 卷不属于 Compose 声明卷,删除浏览器容器或执行 `docker compose down` 时仍会保留;可用以下命令核对:
```bash
docker volume ls --filter name=creatorhub-profile-
```
`docker.sock` 即使以只读文件方式挂载,也仍允许 Docker API 写操作,等价于宿主机 root 权限。完整安全边界、API 契约和失败语义见[《浏览器容器控制面》](architecture/container-control.md)。