# 管理机部署

Zot（容器仓库）、Garage（对象存储）、Gitea（代码 + Actions Runner）、Caddy（HTTPS 反代 + 业务入口），全部在同一台 center 机器上以 Docker Compose 运行。业务服务部署在另一台 k01 机器上，公网流量经由 center 的 Caddy 反代到 k01 上的 envoy-gateway NodePort。

部署机参考：center（Vultr High Frequency / 1 vCPU / 1 GB RAM / 32 GB NVMe）。

## 前置条件

- Docker Engine 与 compose v2
- `apache2-utils`（提供 `htpasswd` 命令，用于给 Zot 生成 bcrypt 密码）
- DNS：`git` / `registry` / `s3` / `juwan` 四条 A 记录全部指向 66.135.5.101，灰云直连
- 防火墙入站规则允许 TCP 80、443、UDP 443

## 首次部署

```bash
cd deploy/center

# 生成所有随机密码与 token，渲染 garage.toml / zot.htpasswd / .env
bash init.sh

# 启动 Caddy + Zot + Garage + Gitea
docker compose up -d caddy zot garage gitea

# 创建 Gitea 管理员
docker compose exec -u git gitea gitea admin user create \
  --username admin \
  --email admin@juwan.xhttp.zip \
  --password "$(cat secrets/gitea-admin-password)" \
  --admin --must-change-password=false

# 在浏览器打开 https://git.juwan.xhttp.zip
# → Site Administration → Actions → Runners → 生成 runner token
# → 把 token 写入 .env 的 RUNNER_TOKEN
# → 回到终端执行：
docker compose up -d runner

# 初始化 Garage：创建 layout、两个 bucket、生成 access key
bash garage/bootstrap.sh
```

`bootstrap.sh` 最后会打印 S3 连接信息，其中 `S3_ACCESS_KEY` / `S3_SECRET_KEY` 留给 k01 的 `objectstory-rpc` 和 CNPG backup 配置。

## 访问入口

| 子域                       | 内容                                              |
| -------------------------- | ------------------------------------------------- |
| `git.juwan.xhttp.zip`      | Gitea 代码仓库                                    |
| `registry.juwan.xhttp.zip` | Zot 镜像仓库 + 内置 zui 浏览器                    |
| `s3.juwan.xhttp.zip`       | Garage S3 API                                     |
| `juwan.xhttp.zip`          | 业务前端，Caddy 反代至 k01 envoy-gateway NodePort |

## 凭据与认证

`init.sh` 会把所有密码写入 `secrets/` 目录（权限 600，`.gitignore` 已排除）。`garage/garage.toml` 和 `zot/htpasswd` 由模板渲染生成，同样不在仓库中跟踪。

### Zot

匿名用户可浏览 zui、`docker pull` 镜像。推送或删除需要登录：

```bash
docker login registry.juwan.xhttp.zip -u admin -p "$(cat secrets/zot-admin-password)"
```

### Gitea

注册链接默认关闭。管理员登录后通过以下方式创建新用户：

```bash
docker compose exec -u git gitea gitea admin user create \
  --username NAME --email MAIL --password PASS
```

## Runner

通过宿主 `/var/run/docker.sock` 启动 job 容器。Workflow 里写 `runs-on: ubuntu-latest` 时，runner 会拉取 `gitea/runner-images:ubuntu-latest-slim` 作为临时工作环境。`docker build` 命令在此容器内调用宿主的 dockerd，生成的镜像可直接推送到本机 Zot。

## 日常维护

```bash
docker compose restart           # 全部重启
docker compose logs -f caddy     # 查看 Caddy 日志（含 ACME 信息）
docker compose logs -f runner    # 查看 Runner 日志（含 job 输出）

# 彻底重置：删除所有 Compose 卷与 init.sh 生成的本地文件
docker compose down -v
rm -rf secrets garage/garage.toml zot/htpasswd
```

持久化数据所在的 Docker 卷：

| 卷                   | 内容                     |
| -------------------- | ------------------------ |
| `juwan-caddy-data`   | ACME 证书                |
| `juwan-caddy-config` | Caddy 自动配置           |
| `juwan-zot-data`     | 容器镜像层               |
| `juwan-garage-meta`  | Garage 元数据            |
| `juwan-garage-data`  | S3 对象数据              |
| `juwan-gitea-data`   | Git 仓库与 SQLite 数据库 |
| `juwan-runner-data`  | Runner 注册信息          |
