

WARN The "XXX" variable is not setNo 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 unpausestop 子命令用于终止容器执行,但它不会破坏与容器关联的任何数据:
docker-compose stop如果要删除与此容器化环境关联的容器、网络和卷,可以使用 down 子命令:
docker-compose down注意:down 命令不会删除 Docker Compose 用于启动你的环境的基础镜像(示例中为 nginx:alpine)。因此,当你再次执行 docker-compose up 启动环境时,启动过程会比第一次要快得多,因为镜像已经在你的系统上。
如果你还想从系统中删除基础镜像,那么可以使用下面命令:
docker image rm nginx:alpine
一、先给你结论(一定要先看)
Docker Compose 的一切“诡异行为”,都源于两个识别规则:
① Compose 文件是“怎么找的”
②.env是“从哪加载的”
只要你理解这两条,
变量为空
No services to build
启动时各种 WARN都会自动消失。
二、第一个核心问题:文件名一定要叫 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 -dDocker 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% 不是写错,而是“放错位置”。