Go 项目使用docker compose的正确方式

我第一次接手一个"成熟"的 Go 项目时,光是让它在本地跑起来就花了一整个下午。docker compose up 之后,终端疯狂报错,数据库连接被拒绝、Redis 连不上、Kafka 还没就绪。翻了一圈文档,发现前人留下的"解决方案"是:在启动脚本里加了个 sleep 10

后来同事告诉我,这个 sleep2 秒一直加到 10 秒,因为"有时候跑得起来,有时候跑不起来"。更糟的是,这个 compose.yml 文件已经膨胀到快 300 行,里面有五六个服务、一堆硬编码的环境变量,还有三个被注释掉的配置块------没人敢删。

这不是个别现象,是我见过的绝大多数 Go 项目的真实写照。

如果你也有类似的经历,下面这六个模式能帮你在不跟 Docker Compose 较劲的前提下,让本地开发环境稳定、测试可靠、构建高效。

模式一:健康检查比"等几秒"靠谱一万倍

depends_on 的语义是"等容器启动",不是"等服务就绪"。Postgres 容器起来了,但数据库引擎可能还在初始化,你的 Go 程序一启动就执行 db.Ping(),结果只能是崩溃。

正确的做法是告诉 Compose:"等到这个服务真正能干活了,再启动我的应用。"

yaml 复制代码
services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypass
      POSTGRES_DB: mydb
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myuser -d mydb"]
      interval: 5s
      timeout: 5s
      retries: 5
      start_period: 10s

  app:
    build: .
    depends_on:
      postgres:
        condition: service_healthy

这样,应用会一直等到 Postgres 真正可以接受连接才启动。同样的方法适用于任何支持健康检查的服务:Redis、MySQL、Kafka------全都通用。

模式二:别把所有服务塞进一个文件

一个 compose.yml 管所有,意味着每次启动都要拉起整个架构。新人想改一行代码,结果启动了数据库、缓存、消息队列、监控面板、Worker 进程------这些东西他一个都不需要。

分层配置是更好的做法:

复制代码
compose.yaml          # 基础设施:Postgres、Redis
compose.dev.yaml      # 开发专用:挂载源码、热加载、调试端口
compose.test.yaml     # 测试专用:临时数据库、独立端口
compose.override.yaml # 个人配置,不提交
bash 复制代码
# docker-compose.dev.yml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    volumes:
      - .:/app
    ports:
      - "8080:8080"
      - "2345:2345"   # delve debugger
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?sslmode=disable
      REDIS_URL: redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy

这样,新人跑 docker compose -f compose.yaml -f compose.dev.yaml up 就能开工,不会被多余的组件干扰。

模式三:多阶段构建让镜像从 1GB 缩到 20MB

很多项目的 Dockerfile 直接从 golang:1.23 开始,把整个编译工具链塞进最终镜像。结果就是 1.2GB 的镜像,CI 推一次等三分钟。

合理的 Go Dockerfile 应该分层:

dockerfile 复制代码
# ---- 依赖缓存 ----
FROM golang:1.23-alpine AS deps
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

# ---- 构建 ----
FROM deps AS builder
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /server ./cmd/server

# ---- 运行 ----
FROM scratch
COPY --from=builder /server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/server"]

这样做的效果:依赖缓存不会因为改了一行业务代码就失效;最终镜像只包含一个静态二进制文件,大多数 Go 服务的镜像能压缩到 20MB 以内。

模式四:用 .env 管配置,别往 YAML 里写密码

POSTGRES_PASSWORD: admin123 这种写法,迟早会出事。密码泄露只是时间问题。

Docker Compose 原生支持 .env 文件,你只需要把配置写进去:

复制代码
# .env(本地开发,不提交)
POSTGRES_USER=dev
POSTGRES_PASSWORD=devpass
POSTGRES_DB=devdb

提交一个 .env.example 作为模板就够了。新人复制、改名、填空,就能跑起来。

模式五:测试数据库跟开发数据库分开

集成测试直接跑在开发数据库上,是在玩火。一个清空表的测试用例就能让你一整个下午的调试数据灰飞烟灭。

测试环境应该独立,而且最好用内存存储:

yaml 复制代码
# compose.test.yaml
services:
  test_db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: testuser
      POSTGRES_PASSWORD: testpass
      POSTGRES_DB: testdb
    ports:
      - "5433:5432"
    tmpfs:
      - /var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U testuser"]
      interval: 2s
      timeout: 2s
      retries: 10

tmpfs 让数据跑在内存里,测试结束数据自动消失,速度比磁盘快一个量级。

总结

这些模式的核心思路只有一条:把不确定性变成确定性

健康检查让启动顺序可靠,分层配置让环境可维护,多阶段构建让镜像高效,环境变量让配置安全,隔离测试让数据安全,Makefile 让操作简单。

一个合格的 Go 项目目录,看起来应该是这样的:

复制代码
.
├── cmd/server/main.go
├── compose.yaml
├── compose.dev.yaml
├── compose.test.yaml
├── Dockerfile
├── .env.example
└── scripts/test.sh

这些东西不花哨,但它能保证:三个月后,你或者你的同事,不用再对着 200 行的 compose.yml 发愁。

相关推荐
OPEN-F5 小时前
C++进阶教程:继承与多态
开发语言·c++
luj_17687 小时前
大律师考核应重能力与科技素养
c语言·开发语言·c++·经验分享·算法
浮生望7 小时前
Docker 入门实战:容器化思想、nginx 反向代理与容器生命周期管理
docker
leonkay8 小时前
C# 特性(Attribute)——【1】基础讲解
开发语言·青少年编程·面试·c#·.net·个人开发
harmful_sheep8 小时前
java group by常见用法
java·开发语言·python
SKH.8 小时前
Linux软件编程(6)线程间通信
java·开发语言·数据库
whcyhhh8 小时前
头歌实践教学平台:数据科学与大数据技术导论(十六)
大数据·开发语言·python
萌动的小火苗8 小时前
数据结构面试题【无答案】
c语言·开发语言·数据结构·链表
宸津-代码粉碎机9 小时前
AI工程化高阶实战|从Demo到生产落地核心架构、全套源码与避坑指南
java·大数据·开发语言·人工智能·python·架构
XR12345678810 小时前
办公网自主创新建设怎么选?信创办公场景的选型逻辑
开发语言·php