Administrator
Published on 2025-12-25 / 2 Visits
0
0

你以为 Docker Compose “没起服务、没读变量”? 真相只有两个规则,但 90% 的人都踩过

WARN The "XXX" variable is not set
No services to build

明明 .env 写好了,
明明 compose 文件也在,
为什么 Docker Compose 就是“不认”?

如果你也被这两个问题反复折磨过——
文件名一定要叫 docker-compose.yml 吗?
.env 到底是怎么被 Compose 识别的?

这篇文章,把两个问题合并讲清楚,你看完只需要记住 两条规则,以后再也不踩坑。


Docker Compose 是 Docker 官方开源的容器编排(Orchestration)项目之一,用于快速部署分布式应用。本文将介绍 Docker Compose 的基本概念、安装流程及使用方法。

简介

Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。从功能上看,Docker Compose 和 OpenStack 中的 Heat 十分类似。

我们知道,使用 Dockerfile 模板文件可以让用户很方便的定义一个单独的应用容器。然而,在实践过程中,我们经常会遇到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。Compose 就是为了满足这样的需求而出现的。

Docker Compose 允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。这里有两个重要的概念 —— 服务和项目。

服务(service):是指一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。

项目(project):是指由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

其中,项目是 Compose 默认的管理对象,可通过子命令对项目中的一组容器进行生命周期管理。

Compose 项目最早由 Python 编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 Compose 来进行编排管理。

后来 Docker 官方用 Go 语言重写了 Docker Compose,称为 Compose V2。并将其作为了 docker cli 的子命令,所以 V1 和 V2 版本的命令有一些区别(你需要将 docker-compose 命令替换为 docker compose)。

如果你想暂停环境执行,但不更改容器的当前状态,那么可以使用 pause 子命令:

docker-compose pause

如果想要在暂停后恢复执行,可以使用 unpause 子命令:

docker-compose unpause

stop 子命令用于终止容器执行,但它不会破坏与容器关联的任何数据:

docker-compose stop

如果要删除与此容器化环境关联的容器、网络和卷,可以使用 down 子命令:

docker-compose down

注意:down 命令不会删除 Docker Compose 用于启动你的环境的基础镜像(示例中为 nginx:alpine)。因此,当你再次执行 docker-compose up 启动环境时,启动过程会比第一次要快得多,因为镜像已经在你的系统上。

如果你还想从系统中删除基础镜像,那么可以使用下面命令:

docker image rm nginx:alpine

Docker Compose - GeeksforGeeks

一、先给你结论(一定要先看)

Docker Compose 的一切“诡异行为”,都源于两个识别规则:

① Compose 文件是“怎么找的”
.env 是“从哪加载的”

只要你理解这两条,

  • 变量为空

  • No services to build

  • 启动时各种 WARN都会自动消失。


Image

二、第一个核心问题:文件名一定要叫 docker-compose.yml 吗?

✅ 答案:不一定,但要看你怎么用


场景一:你什么参数都不写(默认模式)

docker compose up -d

这时 Docker Compose 只做一件事

👉 在“当前目录”查找固定文件名

只认这两个名字:

docker-compose.yml
docker-compose.yaml

📌 结论:

  • 不叫这个名字 → 直接当不存在

  • 这时文件名 必须固定


场景二:你显式指定文件(推荐做法)

docker compose -f zabbix-7.0.yml up -d

这时规则立刻变成:

👉 你说哪个文件,它就用哪个

zabbix.yml
compose-prod.yml
my-stack.yaml
随便叫什么都行

📌 结论:

  • 只要用了 -f

  • 文件名 完全自由

  • 这是生产环境推荐方式


三、第二个核心问题:.env 到底是怎么被 Compose 识别的?

这一步,是 90% WARN 的真正根因


默认规则(不写 --env-file 时)

.env 只会在「compose 文件所在目录」被加载

举个你一定踩过的坑:

docker compose -f /data/zbx7/compose/zabbix.yml up -d

Docker Compose 会去找:

/data/zbx7/compose/.env

不会找你当前目录的 .env
不会全盘搜索

如果这里没有 .env,结果就是:

WARN The "XXX" variable is not set. Defaulting to a blank string.

📌 重点一句话:

.env 不在对的目录,等于没写


四、.env 还有 3 条“铁律”,错一条都不生效

❌ 错误写法(很多人中招)

export TZ=Asia/Shanghai
TZ = Asia/Shanghai
TZ: Asia/Shanghai

✅ 正确写法(唯一)

TZ=Asia/Shanghai

规则只有三条:

  • 必须是 KEY=VALUE

  • 等号两边 不能有空格

  • 不能写 export


五、为什么你会看到这条看似“吓人”的警告?

WARN No services to build

这不是错误。

它只说明一件事:

👉 你执行了 docker compose build
👉 但你的 compose 文件里 只有 image:,没有 build:

Docker 只是告诉你:
“兄弟,这里没啥需要编译的”

📌 正确启动姿势永远是:

docker compose up -d

六、把两个问题合在一起的“真相公式”

Compose 文件 ≠ 随便找
.env ≠ 自动全局加载

真正的识别逻辑只有这一句:

Compose 用 -f 决定用哪个 yml,
.env 只在这个 yml 的目录生效。


七、给你一套“永不踩坑”的生产级用法

目录规范

/data/zbx7/compose/
├── zabbix-7.0.yml
└── .env

启动命令(固定用这一条)

docker compose --env-file /data/zbx7/compose/.env -f /data/zbx7/compose/zabbix-7.0.yml up -d

📌 这套写法的好处:

  • 文件名随你改

  • 目录随你放

  • .env 永远生效

  • 新机器 / 新人接手 0 成本


八、一个“自检神命令”,建议你记住

当你怀疑 .env 没生效时,直接跑:

docker compose --env-file .env -f zabbix-7.0.yml config

如果你看到的是:

TZ: Asia/Shanghai

👉 说明变量已经正确展开
👉 不是 env 的问题,就别再怀疑它


九、最后一句话

Docker Compose 从来不“智能猜测”,
它只严格遵守规则。

一切变量问题,90% 不是写错,而是“放错位置”。



Comment