Files
adcloud-server/docs/docker-deployment.md
T
codex-bot 789ab64013
Docker test deployment / test-build-deploy (push) Successful in 4m5s
Add Docker test deployment on Gitea Actions
2026-09-16 01:27:57 +08:00

106 lines
5.9 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.
# Docker / Gitea Actions 测试部署
## 运行方式
工作流 `.gitea/workflows/docker-deploy.yml` 使用现有 `ubuntu-latest` runner 标签,在推送 main 或手动 dispatch 时运行:
1. 验证作业可以访问 Docker daemon。
2. 使用 Gitea 自动签发的短期作业 token 下载精确提交的源码,不将认证信息放入 URL、命令行或日志。
3. 用 uv 和 uv.lock 构建 test 镜像,执行 Ruff 与 pytest。外部数据库测试未配置环境时跳过。
4. 构建不含开发依赖的非 root runtime 镜像,包含 PostgreSQL / Cassandra Python 驱动,允许以后配置存储;不运行数据库服务。
5. 在一次性 candidate 容器上验证真实 HTTP 流程。
6. 替换测试容器,持久化数据和密钥,映射宿主机端口,再从 Docker daemon 的 host 网络验证请求。
7. 如提供公网 URL,再探测公网 `/health`。后续可从外部执行匿名和埋点测试。
Docker 镜像直接保存在该 daemon 上,本版不依赖镜像仓库登录。
## 公网端口
```text
http://CI_SERVER_PUBLIC_IP:18080
↓ Docker published port
容器 :8000
↓
/v1/identity/*
/v1/events
/v1/users/*
/v1/ads/*
```
默认 `0.0.0.0:18080:8000`。Docker 的 published port 映射到 **daemon 所在服务器**,不是任务容器自己的 localhost。
服务器公网 IP、路由、云安全组和防火墙也必须允许 18080/TCP,映射本身不能修改云端安全组。
这是用于合成测试数据的 HTTP 环境,`COOKIE_SECURE=false`;正式使用需要 HTTPS 和 Secure Cookie,已有 Nginx 443 模板可接入。
`/health`、`/docs`、`/openapi.json` 可用于测试;画像查询、Stitch 和历史查询保持服务端凭据鉴权。
CORS 默认允许 localhost:3000、5173、5174;接入控制台域名时设置 `DEPLOY_CORS_ORIGINS`。
## Runner 要求
runner v0.6.1 的 `container.docker_host` 默认空字符串,会自动查找 daemon 并将 socket 提供给 job。
若显式配置为 `-`,作业不会获得 Docker host,第一步会失败。直接使用宿主机 socket 的配置示例:
```yaml
container:
docker_host: unix:///var/run/docker.sock
```
如果 runner 本身在 Docker 中,runner 容器需要挂载宿主机 `/var/run/docker.sock`。
本工作流不额外申请 privileged 或用户自定义 host bind mount;使用 runner 提供的 daemon。
如果使用 Docker-in-Docker,18080 会发布在 DinD daemon 的命名空间中,未必是公网宿主机。
需要切换为宿主机 daemon,或由服务器管理员额外转发 DinD 端口。看到 runner 的 Idle 状态不能证明公网部署已配置好。
Docker socket 具有管理 daemon 的能力,因此部署工作流仅对 main 的 push/dispatch 执行,不接收不可信 PR。
## 手动运行 / 配置
手动 dispatch 可提供:
- `deploy_port`:宿主机公开端口,默认 18080,允许 1024–65535。
- `public_base_url`:例如 `http://SERVER_IP:18080`;用于公网探测和访问地址报告。
也可由仓库管理员设置 `ADCLOUD_DEPLOY_PORT`、`ADCLOUD_PUBLIC_BASE_URL` 两个 Actions 变量;手动输入优先。
执行部署的 bot 只需仓库写入权限;修改 runner 配置和 Actions 变量需要对应管理权限。
在有 Docker 的目标服务器手动部署:
```sh
docker build --target runtime --tag adcloud-server:test .
DEPLOY_IMAGE=adcloud-server:test bash scripts/deploy_docker.sh
```
当前固定测试部署配置为 SQLite / relational。未来连接数据库时需给容器传入 DATABASE_URL 等配置,并按需要启动画像 worker;本工作流不创建 PostgreSQL 或 Cassandra。
## 持久化、权限和回滚
- `adcloud-server-test-data`:SQLite 数据,挂到 `/data`。
- `adcloud-server-test-config`:运行密钥,挂到 `/config`。
- 首次启动生成随机 IDENTITY_SECRET、SERVICE_TOKEN,原子写入 mode 0600 的配置文件;后续重建复用它们,不输出到流水线日志。
- runtime 使用 UID/GID 10001,根文件系统只读,去除 capabilities,启用 no-new-privileges,并限制 CPU、内存和进程数。
- 正式测试容器使用 `restart=unless-stopped`,Actions 作业结束后继续运行。
- 只替换具有本项目 managed/repository 标签的容器和 volume,不删除其他服务或数据卷。
- named lock 防止多个部署同时操作测试容器。取消任务可能遗留 lock;先确认无部署仍在运行,再由服务器管理员检查并清理 `adcloud-server-test-deploy-lock`。
- 新容器健康检查或 host-port HTTP 验证失败时,删除失败的新容器并尽可能恢复旧容器。端口替换期间有短暂停机;不保证数据库 schema 迁移可以回滚。
- 本版不自动删除旧 Docker 镜像,避免影响其他构建;后续需按保留策略清理本项目镜像。
## HTTP 验证
`smoke_api.py` 检查系统/模块路由、匿名 Cookie、埋点、未授权拒绝、可信 Stitch、画像继承和历史事件回溯。
使用合成邮箱与独立匿名身份,会向测试数据库写入少量演示数据。
验证宿主机端口时,临时探测容器挂载配置卷为只读,读取凭据在进程内发送,不将凭据放到命令参数或日志中。
公网健康检查:
```sh
curl --fail http://SERVER_IP:18080/health
```
外部匿名和事件检查(不需要服务端凭据):
```sh
uv run python scripts/smoke_api.py --base-url http://SERVER_IP:18080 --public-only
```
不要将 SERVICE_TOKEN 放入浏览器或 SDK。需要管理接口测试时,在服务器的受控环境读取部署配置,或配置你自己的受保护测试凭据。
参考:[Docker 端口映射](https://docs.docker.com/engine/network/port-publishing/)、[runner v0.6.1 配置](https://gitea.com/gitea/act_runner/src/tag/v0.6.1/internal/pkg/config/config.example.yaml)、[uv Docker 集成](https://docs.astral.sh/uv/guides/integration/docker/)。