Docker Compose 配置文件结构与卷挂载目录详解
Docker 应用已经成为很多人日常使用的重要工具,而 Docker Compose 也逐渐成为在 NAS 上部署应用时最常见的方式之一。对于刚接触 Docker 的用户来说,Compose 文件里的 services、ports、environment、volumes 这些字段往往最容易让人看花眼。
这篇文章就用尽量通俗的方式,简单说明 Docker Compose 配置文件的基本结构,以及 volumes 挂载目录到底应该怎么理解。
什么是 Docker Compose
Docker Compose 是一个用来定义和管理多容器应用的工具。你可以把一个应用所需的镜像、端口、环境变量、网络和数据目录等内容统一写在一个 YAML 文件里,然后通过 docker compose 命令完成创建和启动。
它特别适合部署“一个应用由多个容器组成”的场景,比如网站程序加数据库、下载服务加代理、面板程序加缓存服务等。
Compose 文件是什么
Compose 使用 YAML 文件描述应用配置,官方现在更推荐的文件名是 compose.yaml 或 compose.yml,同时也继续兼容旧写法 docker-compose.yaml 和 docker-compose.yml
很多旧教程会在文件开头写 version: '3' 或 version: '3.8',不过现在 Docker 官方已经使用统一的 Compose Specification,因此新手写 Compose 文件时通常不必再把 version 当成重点,很多情况下甚至可以省略这一行。
一个最基础的 Compose 示例
先看一个最基础的例子:
services:
web:
image: nginx:latest
ports:
- "90:80"
volumes:
- ./html:/usr/share/nginx/html
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydatabase
MYSQL_USER: user
MYSQL_PASSWORD: password
volumes:
- ./data:/var/lib/mysql
这个示例中定义了两个服务:一个是 web,使用 nginx 镜像;另一个是 db,使用 mysql 镜像。
web 服务把宿主机的 90 端口发布到容器的 80 端口,同时把当前项目目录下的 html 文件夹挂载到容器内的网站目录。
db 服务则通过环境变量初始化数据库信息,并把数据库数据保存到宿主机的 data 目录中,这样即使容器删除重建,数据通常也不会丢失。
Compose 文件里常见字段说明
在入门阶段,最常见的几个字段可以这样理解:
services:定义有哪些服务,也就是要启动哪些容器。image:指定这个服务使用哪个镜像。ports:把宿主机端口转发到容器端口。environment:为容器设置环境变量。volumes:把宿主机目录或 Docker 管理的存储挂载到容器中。
其中最容易让新手混淆的,通常就是 ports 和 volumes。
ports 该怎么理解
ports 最常见的写法可以理解为“宿主机端口:容器端口”。比如 90:80 表示外部访问 NAS 或服务器的 90 端口时,请求会被转发到容器内部的 80 端口。
更直接一点说,真正对外开放的是宿主机端口,而不是“容器通过 NAS_IP+端口访问宿主机”。这一点在很多入门文章里容易说反。
environment 是什么
environment 用于给容器传入环境变量。这些变量通常用来设置程序运行参数,例如数据库名、用户名、密码、时区等。
像 MySQL 这类镜像,在第一次启动时会读取相关环境变量,用来初始化数据库和账号。
volumes 到底是什么
很多新手第一次看到 volumes,会把它简单理解为“挂载目录”。这样理解没问题,但严格来说,Compose 里的存储方式不止一种。
常见的有两类:一种是绑定挂载,也就是把宿主机上真实存在的目录直接挂进容器;另一种是命名卷,也就是由 Docker 统一管理的持久化存储。
像下面这种写法:
volumes: - ./html:/usr/share/nginx/html
这更准确地说是“绑定挂载”。挂载路径通常按照以下格式表示:宿主机目录:容器目录
左边的 ./html 表示宿主机目录,右边的 /usr/share/nginx/html 表示容器目录。容器访问右边目录时,实际读写的就是宿主机左边这个目录里的内容。
相对路径怎么理解
如果写的是 ./config、./html 这种路径,前面的 ./ 表示当前 Compose 项目目录下的子目录。
在实际使用中,你可以把它简单理解为:Compose 文件放在哪个项目目录里,./config 通常就是路径这个目录下面的 config 文件夹。
这也是 NAS 场景中最常见的写法,因为结构清晰,后续备份和迁移也比较方便。
挂载之后会发生什么
当宿主机目录成功挂载到容器后,宿主机目录里的新增、修改、删除,通常会直接反映到容器里;容器内对这个目录的更改,也会同步到宿主机目录中。
这就是数据持久化最重要的意义之一:即使容器删了重建,只要宿主机目录还在,配置和数据通常就还在。
不过这里也要注意一点,绑定挂载默认通常是可写的,所以容器里的程序也可以直接修改宿主机上的文件。
另外,如果把宿主机目录挂载到容器里一个原本已有内容的位置,容器镜像中该目录原来的文件会被“遮住”,看起来像是原内容不见了。
再看一个更直观的 volumes 示例
如果你还是不太容易理解,可以单独看这一段:
services:
nginx:
image: nginx:latest
volumes:
- ./html:/usr/share/nginx/html
这段配置的意思就是:把 Compose 项目路径目录下的 html 文件夹,挂载到 nginx 容器内的 /usr/share/nginx/html 目录。
如果你在 NAS 的 html 文件夹里放一个网页文件,nginx 容器就能直接读取到它。反过来,如果容器对这个目录里的文件进行了修改,宿主机目录里的文件也会一起变化。
Lucky 安装示例
如果你是在飞牛 OS 或其他 NAS 环境中通过 Docker Compose 安装 Lucky,常见配置大致会像下面这样:
services:
lucky:
image: gdy666/lucky:latest
container_name: lucky
volumes:
- ./config:/goodluck
network_mode: host
restart: always
这段配置里最值得关注的是 volumes、network_mode 和 restart。
./config:/goodluck表示把项目目录下的 config 文件夹挂载到容器内的 /goodluck 目录,这样 Lucky 的配置文件就能保存在 NAS 本地。
network_mode: host 表示容器直接使用宿主机网络栈,这种模式下通常不需要再单独写 ports 端口映射,但要注意端口冲突问题。
restart: always 表示容器退出后会自动尝试重启,这类设置在 NAS 场景里很常见,有助于服务保持运行。
restart 常见可选值有 no、on-failure[:重试次数]、always、unless-stopped。其中 always 表示容器停止后持续尝试恢复,unless-stopped 则更适合希望手动停用后保持停机状态的场景。
network_mode: host 是什么
有些应用会要求使用 host 网络模式,这表示容器直接使用宿主机网络环境。它的优点是配置简单,某些依赖局域网广播、端口发现或特殊网络行为的应用更容易正常工作。
但缺点也很明显:端口冲突风险更高,网络隔离更弱,所以不是所有服务都适合这样配置。
restart: always 怎么理解
restart: always 表示容器退出后会自动尝试重启。
对于 NAS 用户来说,这通常意味着在异常退出或宿主机重启后,服务更容易自动恢复。不过它并不等于“任何情况下都无条件立即重启”,手动停止容器时的行为会有所不同。
写 Compose 文件时的几个建议
- 配置文件和数据目录尽量单独挂载出来,不要只放在容器内部。
- 刚开始可以优先使用相对路径,目录结构更直观,也更方便迁移。
- 如果你只是想把 NAS 上现有文件夹交给容器使用,那么你接触到的大多数 volumes 示例,本质上都是绑定挂载。
- 如果以后想让 Docker 统一管理持久化存储,再进一步了解命名卷即可。
结语
对于大多数 NAS 用户来说,学习 Docker Compose 不需要一开始就把所有语法都吃透,先理解 services、ports、environment 和 volumes 这几个最常见的字段,已经足够应对很多日常部署场景。
而在这些字段中,volumes 往往又是最重要的一项,因为它直接关系到配置是否保留、数据是否持久化、后续维护是否方便。
只要把“宿主机目录”和“容器目录”的对应关系想清楚,Compose 文件其实并没有想象中那么难。