# Docker 与容器

## 多阶段示例

```dockerfile
FROM denoland/deno:alpine AS build
WORKDIR /app
# 先复制 manifest 与 lockfile 安装依赖，源码变化不使依赖层失效
COPY deno.json deno.lock ./
RUN deno ci
COPY . .
RUN deno install --entrypoint main.ts

FROM denoland/deno:distroless
WORKDIR /app
COPY --from=build /app /app
# 依赖缓存在 DENO_DIR（/deno-dir），不随 /app 复制，必须显式带过来
COPY --from=build /deno-dir /deno-dir
USER deno
EXPOSE 8000
CMD ["run", "--cached-only", "--allow-net", "--allow-env=PORT", "main.ts"]
```

<Callout type="warn" title="多阶段构建必须复制 DENO_DIR">
`deno install` 缓存的是全局 `DENO_DIR`（官方镜像中为 `/deno-dir`），而不是项目目录。第二阶段漏掉这一步再叠加 `--cached-only`，容器启动时会因缓存缺失直接报错，而不是重新下载依赖。
</Callout>

根据依赖选择 `debian`、`alpine` 或 `distroless`。需要 shell、CA、字体或系统库时，不要只为镜像更小而使用缺少调试能力的变体。

## 生产检查

- 固定 Deno 镜像标签或 digest，不用漂移的 `latest` 发布。
- `.dockerignore` 排除 `.git`、密钥、覆盖率与本地缓存。
- 使用非 root 用户并保持只读根文件系统；只挂载需要写入的目录。
- `0.0.0.0` 监听和 `PORT` 行为由应用明确实现。
- 让平台发送 SIGTERM，测量优雅退出时长。
- 如果运行时禁止联网解析依赖，构建阶段预缓存并用 `--cached-only` 验证。

官方参考：[Deno and Docker](https://docs.deno.com/runtime/reference/docker/)。
