compose 文件写三年,我总结的 12 条实践

Docker · 7 分钟阅读· 11 次阅读

我的 Home Lab 里有 9 个 compose 项目,最老的跑了四年。这些年改下来,形成了一套固定写法。

不是「最佳实践」这种大词,就是我自己觉得省事的东西。

1. 一个项目一个目录,一个 .env

~/stacks/gitea/
  ├─ compose.yaml
  ├─ .env
  └─ data/

.env 里放所有可变的东西:端口、路径、密码、镜像版本。这样换机器时只改 .env。

2. 镜像必须固定版本,不能用 latest

image: gitea/gitea:1.22.3   # 不是 :latest

用 latest 的代价:某天自动拉了个新版本,数据库迁移了,回不去了。

升级应该是显式动作:改版本号 → docker compose pull → up -d → 看日志 → 有问题改回来。

3. restart: unless-stopped

restart: unless-stopped

不用 always:always 在 docker stop 之后重启策略仍然生效(手动停了会被拉起来),而 unless-stopped 尊重你的手动停止。

on-failure 也不错,但如果程序启动就崩,会无限重启刷日志。配合 restart: unless-stopped + 健康检查更好。

4. 端口映射只绑内网地址

ports:
  - "127.0.0.1:3000:3000"   # 只本机可访问,前面用反代
  # 不要写 "3000:3000"     # 等于 0.0.0.0:3000,公网直接扫得到

这一条能挡掉大量「我的服务被扫到了」的问题。公网访问统一走反向代理。

5. 数据用相对路径的绑定挂载

volumes:
  - ./data:/data

不用绝对路径,这样整个目录可以打包搬走。命名卷也好,但备份时要多一步 docker run --rm -v vol:/data alpine tar,绑定挂载直接 rsync 就行。

6. 显式声明时区和用户

environment:
  - TZ=Asia/Shanghai
user: "1000:1000"

第二行看情况,有些镜像不支持非 root,会报权限错。但凡是支持 PUID/PGID 的镜像(linuxserver 系),一定要设。

7. 健康检查,不要只看「容器在跑」

healthcheck:
  test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"]
  interval: 30s
  timeout: 5s
  retries: 3
  start_period: 40s

start_period 很重要——不加的话,启动慢的服务会被判定为不健康然后被反复重启。

8. 日志必须限制大小

logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

不加这个,一个话多的容器几个月能把磁盘写满。我有一次就是 nginx 容器的 access log 写了 40G。

9. 用 depends_on 加健康条件,不要只写名字

depends_on:
  db:
    condition: service_healthy

只写 depends_on: [db] 只能保证启动顺序,不保证 db 已经能接受连接。加了 condition 才是真的等。

10. 网络显式命名,别用默认 bridge

networks:
  backend:
    name: stack_backend

services:
  web:
    networks: [backend]
    ports: ["127.0.0.1:3000:3000"]
  db:
    networks: [backend]

好处:容器名可以当 DNS 用;不同项目的网络隔离;排查时 docker network inspect 清楚。

11. 敏感信息不要写进 compose

environment:
  - DB_PASSWORD=${DB_PASSWORD}   # 从 .env 读

.env 加进 .gitignore,仓库里只放 .env.example。

更进一步用 secrets,但家庭场景 .env + 文件权限 600 已经够了。

12. 保留一份 compose.yaml.bak 的习惯

改之前先 cp compose.yaml compose.yaml.bak。

Docker 的坑在于:写错一个缩进,up -d 会把原来的容器重建掉。有备份就能立刻回滚。

真正该做的是 git,但我发现自己在小改动时经常懒得 commit,所以物理备份更实际。

一份模板

把我常用的骨架整理成一个:

services:
  app:
    image: vendor/app:1.2.3
    container_name: app
    restart: unless-stopped
    user: "1000:1000"
    environment:
      - TZ=Asia/Shanghai
      - DB_PASSWORD=${DB_PASSWORD}
    volumes:
      - ./data:/app/data
    ports:
      - "127.0.0.1:8080:8080"
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 30s
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
    networks: [backend]

  db:
    image: postgres:16.4
    restart: unless-stopped
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - TZ=Asia/Shanghai
    volumes:
      - ./db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks: [backend]

networks:
  backend:

一条没做到的

我至今没有把 9 个项目全部纳入 CI 做配置校验。理想情况下应该有个 docker compose config 的 pre-commit 检查,防止缩进写错。

这条先记着,等哪天真的被缩进坑一次大的,大概就会做了。

评论 (0)

还没有评论,来说两句吧~

发表评论

验证码

提交后需站长审核,通过后才会显示。