SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-28

Docker Compose 真实服务器常用命令速查表

按生命周期、变更、日志、Shell、网络、卷和清理整理 Compose V2 命令,说明 compose.yaml 目录要求、down 与 stop 的区别及安全清理方法。

实际最常用的 Compose 命令

Docker Compose 提供了 40 多个子命令。服务器上的日常工作通常只会用到其中约 12 个。本页按任务对这些命令分组,为每个命令说明一个直接原因,并在命令存在隐藏风险时提供深入说明的入口。

本页所有内容都使用 Compose V2:docker compose,两者之间有一个空格,而不是旧版的 docker-compose 脚本。V2 是随 Docker Engine 一起安装的 Go 插件。当前软件包已不再提供 V1,因此截至 2026 年 7 月,在全新的 Ubuntu 主机上看到 docker-compose: command not found 是正常现象,并不表示出现故障。使用 docker compose version 检查。如果没有任何输出,请安装 docker-compose-plugin 软件包。

下面的每条命令都应在包含 compose.yaml 的目录中运行,因为 Compose 会从该目录获取项目名称,并相对于该目录查找文件。如果在上一级目录中运行相同的命令,Compose 会因 no configuration file provided: not found 而停止。如果你还不熟悉该文件格式,请先阅读VPS 上的第一个 Compose 文件,然后返回这里查看这些命令。

生命周期:您会使用的4个命令,以及会删除容器的那个命令

docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose down

up -d 创建网络、创建容器、启动容器,然后返回。容器一经创建,该命令就会返回。因此,部署脚本如果随后使用 curl 探测,首次执行通常会失败。up -d --wait 会阻塞,直到所有声明了 healthcheck 的服务都报告 healthy;如果某个服务始终未达到该状态,命令将以非零状态退出。该标志的可靠性取决于其背后的检查,因此在将它用于自动化之前,应先编写 Compose 可以信任的 healthcheck

stop 会停止容器但保留容器,因此 start 会使用相同的可写层重新启动相同的容器。down 会停止容器,然后删除容器和项目网络。容器内写入的、且不属于卷的数据都会随容器一起删除。这是 Compose 中代价最高的误解;down 和 stop 的完整区别介绍了它会在哪些情况下造成影响。

restart 不是重新加载。它会使用现有配置停止并重新启动同一个容器,因此修改后的环境变量、新的镜像标签或编辑后的端口映射完全不会生效。要应用文件变更,您需要再次运行 up -d。Compose 会将每个服务与其正在运行的容器进行比较,只重新创建配置发生变化的服务。

应用变更:重新创建、拉取或重新构建

docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build web

在没有任何变更时,单独运行 up -d 不会执行任何操作,因此可以安全地重复运行。--force-recreate 会跳过比较,直接替换每个容器,即使配置完全相同。因此,它是清理容器内部异常状态最快的方法。

更新镜像需要执行两个命令,因为这两个命令的作用不同。pull 会下载文件中列出的每个标签对应的最新镜像。随后,up -d 发现服务的镜像 ID 已与正在运行的容器不匹配,于是重新创建容器。跳过 pull 后,up -d 会继续运行上个月的 latest,且不会报错。在多服务堆栈中则存在相反的风险:一次为所有服务拉取 latest,可能会让十秒前还正常运行的应用中断。因此,自托管的 AFFiNE 工作区 会为其 4 个镜像标签分别固定版本。固定版本还会将升级变成一次有意的标签编辑,之后再执行相同的 pull 和重新创建操作。对于启动时会迁移数据库的堆栈,应在执行任一命令前准备好转储文件;自托管的 Chatwoot 支持服务台 会在每次版本升级时遵循这一流程。

build 适用于声明 build: 部分而不是 image: 的服务。up -d --build 会在一个步骤中完成构建和启动,这是修改代码时通常采用的循环。只有在明确确认缓存层已过时时,才使用 --no-cache,因为它会从头重新构建每一层。当堆栈不是从镜像仓库获取镜像,而是从已检出的 git 标签部署时,同一构建循环也会成为更新路径。自托管 openGym 健身追踪器就是通过这种方式从一个固定版本更新到下一个版本的。

查看正在运行的内容

docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose ls

ps仅列出正在运行的容器。启动过程中崩溃的服务不会显示在其中,除非添加 -a。因此,容器未出现在 ps 中,而 ps -a 将其显示为 Exited (1),这是启动失败的常见表现。先读取退出码,再查看日志。

logs -f同时跟踪所有服务,并在每行前添加服务名称。当服务相互通信且事件顺序很重要时,应使用此视图。指定服务名称可缩小范围。对于已运行一个月的容器,--tail=100 很重要,因为默认情况下会输出完整历史记录,导致终端被大量内容占满。--since 15m 可以回答通常需要确认的问题:刚才执行的重启期间发生了什么。

top列出每个容器内的进程,用于区分“容器正在运行”和“容器内的进程正在运行”。ls 会离开当前目录,列出主机上的所有 Compose 项目及其状态,因此可以找到三个月前启动的服务栈。

在服务内部获取 Shell

docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web sh

exec 在已经运行的容器中执行命令。run 根据同一服务定义启动一个新容器。当服务无法持续运行足够长时间、无法使用 exec 进入时,应使用此命令。始终将 run--rm 配合使用,否则每次调用都会留下一个已停止的容器。这些容器会不断累积,直到 docker compose ps -a 无法读取。

先尝试 sh,再尝试 bash。基于 Alpine 的镜像不包含 bash,因此失败时会显示 exec: "bash": executable file not found in $PATH。将 --no-deps 添加到 run 可跳过服务的依赖项,避免快速检查配置时启动整个数据库。

run --rm web env 是查看服务实际获得的环境的最快方法。此时所有 .env 文件、environment: 块和 Shell 变量都已合并。如果某个值不正确,通常是合并顺序导致的。Compose 如何解析 env 文件和密钥说明了哪个来源具有更高优先级。

网络、端口和名称解析

docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networks

Compose 会将所有服务连接到同一个项目网络,并将每个服务名称作为该网络中的 DNS 名称。在 web 中运行 getent hosts db 时,如果名称解析成功,就会输出容器 IP;如果解析失败,则不输出任何内容。因此,2 秒内即可判断“这些容器能否相互访问”。如果名称可以解析,但连接被拒绝,说明 db 中的进程绑定到了 127.0.0.1,而不是 0.0.0.0,因此不会接受来自其他容器的数据包。相同的网络边界也解释了为什么在项目外启动的容器(无论由 docker run 启动,还是作为独立堆栈运行)完全无法解析 jellyfin 这样的名称。当 用于 Jellyfin 媒体库的 Halcyon 前端无法连接到其配置的服务器时,这是首先需要检查的问题。有关该模型的其余内容,请参阅Compose 网络和服务 DNS 的工作方式

port web 80 会输出容器端口发布到的主机地址和端口。映射由变量提供时,这可以避免猜测。发布端口还会写入由 Docker 自行管理的防火墙规则。该规则优先于您配置的规则,因此原本认为是私有的服务可能会对互联网开放。为什么已发布的 Docker 端口会绕过 ufw介绍了这种情况。更安全的做法是不发布这些端口,而是在项目网络中放置一个负责身份验证的代理,并让它位于各服务前面。将 Authentik 作为单点登录层运行采用的就是这种结构。

卷和数据

docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -v

config --volumes 每行输出项目声明的一个命名卷。这些卷就是需要备份的对象。如果卷中存储着无法替代的数据,准确的备份命令与卷列表同样重要。因此,PhotoPrism 与 Immich 的对比详细列出了每个照片服务器所需的转储和复制命令。cp 无需打开 shell,即可将文件复制到容器或从容器复制出来;容器所在的一侧使用 service:path 形式。

down -v 会连同容器一起删除这些命名卷。拆除测试堆栈时应使用此命令;对于包含重要数据的堆栈则不应使用,因为它不会要求确认,也无法撤销。绑定挂载不受影响,因为它们位于主机文件系统中。这种影响范围的差异,也是应在 绑定挂载和命名卷之间谨慎选择的原因之一。

清理磁盘空间且不丢失数据

docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune

--remove-orphans 会删除属于该项目、但已不再出现在文件中的容器。重命名服务后通常就会出现这种情况。不执行此命令时,这些容器会继续运行,但 docker compose ps 不会显示它们。

docker system df 会在删除任何内容前显示磁盘空间的占用情况,并分别列出镜像、容器、本地卷和构建缓存,以及每类内容可回收的空间。image prune -a 会删除没有任何标签指向的镜像。对于拉取过多个大型镜像版本的服务器,这通常能释放最多空间。builder prune 会清理构建缓存。任何自行构建镜像的服务器都会逐渐积累这类缓存。

这些命令都不会处理命名卷。只有 docker volume prunedocker compose down -v 会处理命名卷。

在出现问题前检查文件

docker compose config --quiet
docker compose config --services
docker compose --dry-run up -d

config --quiet 会在验证成功时不输出任何内容,因此适合放在部署前步骤或 git hook 中。普通的 config 会输出完整合并并插值后的文件。通过它可以确认变量是否已解析,以及覆盖文件是否按预期叠加。未设置的变量会显示为空值,并伴随警告 The "X" variable is not set. Defaulting to a blank string.

--dry-run 是全局选项,而不是子命令选项,因此应放在 up 之前。它会输出 Compose 将执行的每个操作,但不会进行任何更改。在重要的堆栈上执行 down 之前,花费三十秒进行检查很值得。

跨文件、配置文件和项目协作

docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -d

多个 -f 标志按顺序合并,后面的文件会逐项覆盖前面的文件。这是保留一个基础文件并使用小型生产环境覆盖文件的标准方法。不过,列表和映射的合并规则不同,因此在排查意外结果前,请先阅读Compose 如何合并多个文件

--profile 会启动标记了该配置文件的服务,并同时启动未标记的服务,从而使调试工具不会出现在普通的 up 中。-p 会设置项目名称,因此同一堆栈的两个副本可以并行运行,并使用独立的网络和卷名称。重启后恢复堆栈并不是需要手动输入的命令,而是由一个自动执行该操作的单元完成,具体说明请参阅在系统启动时启动 Compose 堆栈

FAQ

什么替代了带连字符的 docker-compose

Compose V2,使用带空格的 docker compose 调用。它是 Docker Engine 随附的插件,当前软件包不再安装 V1 Python 工具。如果带空格的形式没有输出,请为您的发行版安装 docker-compose-plugin 软件包。更新旧脚本时应改用带空格的形式,而不是添加别名,因为 V2 支持 V1 没有的选项。

为什么 docker compose restart 没有应用我的配置更改?

restart 会使用容器创建时的配置停止并启动现有容器,而且不会重新读取 compose.yaml。环境变量、端口、卷或镜像标签发生任何更改时,都需要使用 docker compose up -d。该命令会将每个服务与其运行中的容器进行比较,并重新创建配置不同的容器。如果希望即使文件没有变化也执行替换,请添加 --force-recreate

如何将服务更新到较新的镜像?

运行 docker compose pull,然后运行 docker compose up -d。pull 操作会为文件中的每个标签获取当前镜像,up -d 会重新创建镜像 ID 与容器不再匹配的服务。单独运行 up -d 会复用磁盘上已有的镜像。因此,固定到 latest 的堆栈可能持续使用数月前的构建版本,且不会输出任何错误。

哪些清理命令可安全地在运行中的服务器上执行?

docker system dfdocker image prune -adocker builder prune 只会删除镜像和缓存,因此运行中的服务会继续工作,命名卷也不会受到影响。危险的是 docker compose down -vdocker volume prune,它们会直接删除命名卷而不提示。先运行 docker compose config --volumes,确认可能受到影响的内容。

可以只运行一个命令而不启动整个堆栈吗?

可以。docker compose run --rm --no-deps web sh 会根据 web 服务定义启动单个容器,跳过其依赖项,并在退出时删除该容器。如果容器已经在运行,请改用 exec,因为 exec 会加入正在运行的进程,并显示服务实际所处的状态。