Compose 编排 vs 生产镜像部署:环境变量怎么注入
总结
两种常见形态:
- Compose 全栈:同一台机(或同一 Docker 网络)里一起起 Postgres / Redis / Backend,网络与连接信息多半由编排写死或同源注入。
- 只跑 Backend 镜像:CI 打出应用镜像;生产只拉这个镜像跑,库和缓存在外部,靠部署时注入 env 告诉进程远程地址。
核心不是「有没有 .env 文件」,而是:进程最终读到的环境变量从哪来、值对不对得上它所在的网络位置。
先分清三层
| 层 | 是什么 | 典型内容 |
|---|---|---|
| 服务本身 | Postgres / Redis 容器怎么初始化 | POSTGRES_USER / PASSWORD / DB |
| 客户端连接 | Backend 怎么连库、连缓存 | DB_HOST、POSTGRES_PORT、REDIS_HOST… |
| 配置来源 | 这些值谁填进进程 | .env、Compose environment、K8s Secret、docker run -e |
Backend 不会自动读 docker-compose.yml。进程侧常见优先级是:
已存在的环境变量(容器 / 系统已注入,优先)
→ godotenv 等只补缺、默认不覆盖已有 env
→ 代码里的 default fallback
镜像里通常只有二进制,不含你本机的 .env。
flowchart LR
subgraph Compose全栈
A[app] -->|DB_HOST=postgres| P[(postgres)]
A -->|REDIS_HOST=redis| R[(redis)]
end
subgraph 只跑Backend镜像
B[backend] -->|远程地址+密钥| P2[(外部 DB)]
B --> R2[(外部 Redis)]
end
方案 A:Compose 编排整套服务
在做什么
docker compose up
├── postgres (官方镜像 + 初始化 env)
├── redis
└── app (backend 镜像/build,同一 Docker 网络)
同一网络内用服务名做 DNS,例如 postgres、redis。
连接关系
app 容器内:
DB_HOST=postgres ← 服务名,不是 localhost
REDIS_HOST=redis
POSTGRES_PORT=5432 ← 容器内端口(一般固定)
坑: 在 app 容器里写 DB_HOST=localhost 会连到 app 自己,而不是数据库。
env 怎么注入
| 变量类型 | 谁写 | 说明 |
|---|---|---|
POSTGRES_USER/PASSWORD/DB | Compose 给 postgres 服务 + app 服务(常 ${VAR:-default} 同源) | 初始化账号与客户端账号要对齐 |
DB_HOST / REDIS_HOST / POSTGRES_PORT 等 | Compose 写死进 app(postgres / redis) | 应用客户端配置名;Postgres 官方镜像不认 DB_HOST/POSTGRES_PORT,它们只给 backend 用 |
日志 ENV / LOG_LEVEL 等 | 可选,从 .env 插值进 app | 运维向参数 |
Compose 读项目根目录 .env 的方式是:
磁盘 .env
→ 替换 YAML 里的 ${POSTGRES_PASSWORD} 等
→ 变成容器的 environment
默认不会把整个 .env 文件挂进容器;容器里进程看到的是已经算好的环境变量。
开发变体:Compose 只起依赖
compose 只起 postgres + redis(端口映射到宿主机)
本机 go run ./cmd/server
这时 backend 在宿主机:
DB_HOST=localhost
REDIS_HOST=localhost
端口 = 映射出来的 5432 / 6379
代码默认常常就是这样,本地可以不写 .env。
宿主端口映射(5432:5432)属于开发便利,不必全部做成可配项。
何时 host/port「没什么可配的」
若生产也用 Compose 在同一网络起全套 app + 中间件:
DB_HOST/POSTGRES_PORT对人几乎不用调——编排已经定死拓扑- 变量仍存在:Compose 注入它们,app 才能连上
- 仍要管的是 密码、库名、日志级别 等
方案 B:只部署 Backend 镜像(更接近常见生产)
在做什么
CI:测试 → build 镜像 → push GHCR(等)
生产:只 pull backend 镜像运行
Postgres / Redis 在别处(托管库、另一台机、K8s 另一套服务)
Compose 可以仍用于本地/预发,但不是生产唯一形态。