# Docker 构建指南

## 前提条件

- Docker 20.10+
- Cargo.lock 已存在（`cargo generate-lockfile`）
- 网络能够访问 crates.io

## 快速开始

```bash
# 构建全部镜像（默认 registry=myapp, tag=latest）
./docker/build.sh

# 构建指定镜像
./docker/build.sh app
./docker/build.sh gitserver email-worker

# 指定 registry 和 tag
REGISTRY=myregistry TAG=v1.0.0 ./docker/build.sh
```

## 镜像列表

| 镜像 | Dockerfile | 二进制 | 实例类型 | 说明 |
|---|---|---|---|---|
| `myapp/app:latest` | `app.Dockerfile` | `app` | 多实例 | 主 Web 服务（API + WS） |
| `myapp/gitserver:latest` | `gitserver.Dockerfile` | `gitserver` | 单实例 | Git HTTP + SSH 服务 |
| `myapp/email-worker:latest` | `email-worker.Dockerfile` | `email-worker` | 单实例 | 邮件发送 Worker |
| `myapp/git-hook:latest` | `git-hook.Dockerfile` | `git-hook` | 单实例 | Git Hook 事件处理 |
| `myapp/migrate:latest` | `migrate.Dockerfile` | `migrate` | Job/InitContainer | 数据库迁移 CLI |

## 部署架构

```
                    ┌─ NATS ─┐
                    │        │
┌─────────┐    ┌──────────────┐    ┌─────────────────┐
│  LB/    │───▶│ app (×N)    │    │ git-hook        │
│  nginx  │    │ (stateless) │    │ (单实例)        │
└─────────┘    └──────────────┘    └─────────────────┘
               ┌──────────────┐
               │ gitserver   │
               │ (单实例)    │    ┌─────────────────┐
               │ HTTP :8022  │───▶│ email-worker    │
               │ SSH  :2222  │    │ (单实例)        │
               └──────────────┘    └─────────────────┘
```

## 环境变量

所有配置通过环境变量注入，无需修改镜像：

| 变量 | 示例 | 说明 |
|---|---|---|
| `APP_DATABASE_URL` | `postgres://user:pass@host:5432/db` | 数据库连接 |
| `APP_REDIS_URLS` | `redis://host:6379` | Redis（多实例用逗号分隔） |
| `APP_SMTP_HOST` | `smtp.example.com` | SMTP 服务器 |
| `APP_SMTP_USERNAME` | `noreply@example.com` | SMTP 用户名 |
| `APP_SMTP_PASSWORD` | `xxx` | SMTP 密码 |
| `APP_SMTP_FROM` | `noreply@example.com` | 发件人地址 |
| `APP_AI_BASIC_URL` | `https://api.openai.com/v1` | AI API 地址 |
| `APP_AI_API_KEY` | `sk-xxx` | AI API Key |
| `APP_DOMAIN_URL` | `https://example.com` | 主域名 |
| `APP_LOG_LEVEL` | `info` | 日志级别: trace/debug/info/warn/error |
| `APP_SSH_DOMAIN` | `git.example.com` | Git SSH 域名 |
| `APP_REPOS_ROOT` | `/data/repos` | Git 仓库存储路径 |
| `NATS_URL` | `nats://localhost:4222` | NATS 服务器地址 |

## 数据库迁移

镜像启动前先运行迁移：

```bash
# 方式一：直接运行
docker run --rm \
  --env-file .env \
  myapp/migrate:latest up

# 方式二：Kubernetes InitContainer
# 见下方 K8s 示例
```

## Kubernetes 部署示例

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  replicas: 3
  template:
    spec:
      containers:
        - name: app
          image: myapp/app:latest
          envFrom:
            - secretRef:
                name: app-secrets
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gitserver
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: gitserver
          image: myapp/gitserver:latest
          ports:
            - containerPort: 8022  # HTTP
            - containerPort: 2222  # SSH
          envFrom:
            - secretRef:
                name: app-secrets
          volumeMounts:
            - name: repos
              mountPath: /data/repos
      volumes:
        - name: repos
          persistentVolumeClaim:
            claimName: git-repos
---
apiVersion: batch/v1
kind: Job
metadata:
  name: migrate
spec:
  template:
    spec:
      containers:
        - name: migrate
          image: myapp/migrate:latest
          envFrom:
            - secretRef:
                name: app-secrets
          args: ["up"]
      restartPolicy: Never
```

## 构建缓存

使用 Docker BuildKit 的构建缓存：
- `--mount=type=cache,target=/usr/local/cargo/registry` — crates.io 依赖
- `--mount=type=cache,target=/usr/local/cargo/git` — git 依赖
- `--mount=type=cache,target=target` — 编译产物

建议挂载持久化缓存卷以加速增量构建：

```bash
docker buildx create --use
docker buildx build \
  --cache-from=type=local,src=/tmp/cargo-cache \
  --cache-to=type=local,dest=/tmp/cargo-cache \
  -f docker/app.Dockerfile -t myapp/app .
```

## 跨平台构建

默认构建 x86_64 Linux 可执行文件。构建其他平台：

```bash
# ARM64
BUILD_TARGET=aarch64-unknown-linux-gnu ./docker/build.sh

# 需先安装对应 target：
rustup target add aarch64-unknown-linux-gnu
```
