| name | docker-best-practices |
| description | Use when containerizing or deploying a frontend, backend, or full-stack project for local testing, an internal registry, production, or offline delivery. Triggers include "docker化", "容器化", "写Dockerfile", "build镜像", "推送镜像", "部署到服务器", "docker-compose", Docker images, Compose, multi-stage or multi-arch buildx, registry delivery, tar-offline delivery, embedded MariaDB, dev/prod container environments, and image build/push/run scripts. |
Docker Best Practices
核心约定:三区结构
所有 Docker 工程化产物都收拢在项目根 docker/ 下,分三个职责清晰的子目录:
docker/
README.md ← 部署手册(不叫 DEPLOY.md)
images/ ← 镜像制作区
Dockerfile.base / .code / .ui ...
entrypoint.sh
nginx.conf
.env / .env.example ← 镜像 tag 的唯一来源
containers/ ← 容器运行区
docker-compose.yml 本地开发裸放在 containers/ 根
data/ 本地开发挂载(脚本自动建)
<env-name>/ 其他环境(生产 / 区域)
docker-compose.yml
scripts/ ← 脚本区
build-images.sh [target ...]
push-images.sh [target ...]
run-local.sh [target ...]
stop-local.sh [-v]
.registry.env / .registry.env.example
为什么这样分:
- images/ = "怎么造镜像"(Dockerfile 和构建期资源)
- containers/ = "怎么跑容器"(compose 编排 + 运行时挂载)
- scripts/ = "怎么操作"(build / push / run 工作流)
- 三个区互不交叉——改 Dockerfile 不动 compose、改 compose 不动脚本、改脚本不动镜像。
核心设计点:
- 本地开发的 compose 直接放在
containers/ 根(不放 containers/dev/),因为 dev 是默认场景,少一层目录就少一层心智负担。
- 生产 / 区域环境放子目录(
containers/syzh/、containers/prod/),跟 dev 平级共存。
docker/images/.env 是镜像 tag 的唯一来源——build / push / 本地 compose 都从这里读,运维生产环境另写一份 .env。
- 三个脚本统一参数协议——不传参 = 处理全部镜像,传参 = 只处理指定的子集。
参考实现:
阶段一:初始化(Init)
Step 1:自动扫描项目类型
| 检测条件 | 判断结果 |
|---|
同时有 frontend/ 和 backend/ | 全栈 |
只有 backend/(含 pyproject.toml 或 pom.xml) | 纯后端 |
只有 frontend/(含 package.json) | 纯前端 |
Step 2:收集必要信息(按顺序逐一询问)
Q1:项目名(用于镜像名前缀和 compose project name)
Q2:版本号(写入 .env.example 的初始值)
Q3:对外暴露端口
- 全栈默认:
80(Nginx 统一入口)
- 纯后端默认:
8000
- 纯前端默认:
80
Q4(全栈 / 纯后端):数据库策略
- A — SQLite(嵌入,零配置)
- B — 嵌入式 MariaDB(
USE_EMBEDDED_DB=true/false 切换)
- C — 纯外部数据库(compose env 配连接)
Q5:镜像结构(默认走多镜像,单镜像只在以下三个条件全满足时考虑):
- 项目最终镜像 < 1GB
- 部署只走 registry,不需要 tar 离线
- 团队就 1-2 个人,不在乎工程化复杂度
多镜像的层划分按项目实际:
- Java 后端(如 waveflow):
base / code / ui
- Python + ML(如 sage):
base / venv / models / code
- 任意项目:层名按内容定,
base 始终是系统运行时,其他层用 code / ui / venv / models / deploy / data 这种语义化名字。
Q6(仅多镜像):部署通道是 registry 还是 tar 离线?
- Registry:data-only 镜像可
FROM scratch(buildkit 直接 push)
- Tar + docker load:data-only 镜像必须
FROM busybox:musl(init 需要 sh + cp)
Step 3:生成 docker/ 三区目录
docker/
├── README.md ← 按项目模板生成(见 references/templates.md)
├── images/
│ ├── Dockerfile.base
│ ├── Dockerfile.code ← 多镜像;单镜像直接叫 Dockerfile
│ ├── Dockerfile.ui ← 仅多镜像 + 全栈
│ ├── entrypoint.sh
│ ├── nginx.conf ← 全栈 / 纯前端
│ ├── .env ← 跟随项目复制
│ └── .env.example
├── containers/
│ ├── docker-compose.yml ← 本地开发(含 build profiles + ports)
│ └── <env>/docker-compose.yml ← 生产 / 区域(image-only,无 build)
└── scripts/
├── build-images.sh
├── push-images.sh
├── run-local.sh
├── stop-local.sh
├── .registry.env
└── .registry.env.example
项目根目录同步(首次创建 docker 项目就把这两个 ignore 写好,避免运行时数据被误 commit 或拖进 build context,详见 references/templates.md):
.dockerignore —— 排除 docker/containers/*/data/、packages/、**/target/、凭据 .env 等
.gitignore —— 同样排除 docker/containers/*/data/、docker/images/.env、docker/scripts/.registry.env
阶段二:开发指导(Guide)
子节 1:本地开发(一行命令)
./docker/scripts/run-local.sh
./docker/scripts/run-local.sh code
./docker/scripts/run-local.sh code ui
run-local.sh 的标准动作:
- 缺
.env 就从 .env.example 复制
mkdir -p 运行时挂载目录
- 调
build-images.sh 透传参数
docker compose down --remove-orphans(保留 volume)
docker compose up -d --remove-orphans
- 等主容器健康(最多 90s)
- 打印访问入口 banner
关键:compose down + up 让 init 容器重新跑,结合 dev compose 里去掉 .version skip 逻辑(每次全量 cp),代码改动一定生效。生产 compose 保留 .version skip,避免每次 restart 重 cp。
子节 2:推送到内网仓库
首次配置:
cp docker/scripts/.registry.env.example docker/scripts/.registry.env
vim docker/scripts/.registry.env
./docker/scripts/push-images.sh
./docker/scripts/push-images.sh code
./docker/scripts/push-images.sh code ui
关键设计:
- 不自动创建 buildx builder——尊重用户当前激活的(特别是配过 HTTP registry 的)
- 登录走
docker login,凭据放 .registry.env(gitignored)
- 多架构 venv build 必须
--build-arg BASE_IMAGE={registry}/{ns}/{project}-base,让 buildx 从 registry 拉对应架构
子节 3:生产部署(运维视角)
运维在服务器上维护两个文件,放在同一目录(docker compose 自动加载同级 .env):
/apps/{project}/
docker-compose.yml ← 取自 docker/containers/<env>/docker-compose.yml
.env ← N 行镜像 tag,每次发版随包提供
Registry 通道:
cd /apps/{project}
docker login {registry}
docker compose pull
docker compose up -d
Tar 离线通道(生产机不能访问 registry):
中转机(能访问 registry):拉 → retag 成短名 → save tar
生产机:load 所有 tar → docker compose up -d
详见 references/structure.md#tar-离线。
升级(只换 code,最常见):
cd /apps/{project}
sed -i 's/^.*_CODE_TAG=.*/{PROJECT_UPPER}_CODE_TAG=2.1.1/' .env
docker compose pull
docker compose up -d
.version skip 让 base/ui 的 init 跳过;只有 code 重新 cp。
阶段三:代码审查(Review)
三区结构
镜像质量
多镜像拆分
Compose 设计
脚本质量
安全
网络(全栈项目)