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

Docker Compose stop 和 down 有什么区别?

docker compose stop 只停止并保留容器,down 还会删除容器和项目网络;两者都不删除命名卷,只有 down --volumes 会删除 Compose 文件中声明的卷和数据库数据。

简短回答

docker compose stop 会停止容器,但保留磁盘上的容器。docker compose down 会停止容器,然后删除容器以及 Compose 为项目创建的网络。这两个命令都不会影响命名卷。只有添加 -v(如 docker compose down -v)时,数据库才会被删除;该选项会删除 Compose 文件 volumes 部分中声明的命名卷。

以上一段话概括了两者的全部区别。本指南其余部分将通过一个 Postgres 卷进行验证:观察该卷在执行 down 后仍然存在,并在执行 down -v 后消失;同时说明需要使用 --force-recreate 的两种情况。

docker compose stop:容器仍然存在

stop 会向每个容器中的主进程发送 SIGTERM,等待一段时间;如果进程仍在运行,则发送 SIGKILL。默认等待时间为 10 秒,-t 可修改该时间。不会删除任何内容。容器会保留其 ID、可写层、IP 保留信息和日志。

docker compose stop
docker compose ps -a

docker compose ps 单独使用时只显示正在运行的容器,因此执行 stop 后会显示空表,导致人们以为容器已被删除。ps -a 会包含已停止的容器,此时可以在每个服务旁看到 Exited (0)。使用 docker compose start 可重新启动它们,该命令会重新使用完全相同的容器。

由于容器仍然存在,写入容器内部且不在 volume 中的内容也会保留。其中包括使用 docker compose exec 手动安装的软件包,以及在容器内编辑过的配置文件。这也是调试时更适合使用 stop 的实际原因:您可以在相同状态下重新启动容器。

docker compose down:删除容器和网络

down会停止容器,然后删除这些容器,以及 Compose 为项目创建的默认网络。Docker 文档将其描述为停止容器,并删除由 up 创建的容器、网络、卷和镜像;但只有在使用 -v--rmi 请求时,才会删除卷和镜像。

docker compose down
docker compose ps -a
docker network ls

执行 down 后,ps -a 不会为该项目输出任何内容,<project>_default 网络也会被删除。除非在 Compose 文件中设置 name: 或传入 -p,否则项目名称取自目录名称。你在容器可写层中所做的所有更改现在都无法恢复。因此,应将 down 视为会删除容器、但保留卷中数据的命令。

如果在错误的目录中运行该命令,会得到 no configuration file provided: not found。Compose 无法确定你指的是哪个项目,因此会拒绝执行。不在项目目录中时,请使用 docker compose -f /srv/myapp/compose.yaml down

执行 docker compose down 会删除我的卷吗?

不会。顶层 volumes 键下声明的命名卷不会随 down 删除,也不会因所附加的容器被删除而消失。这是使用该命令时最常见的担忧,而在 Compose v2 中,答案始终如此。

先创建一个可用于测试的堆栈。在名为 voltest 的空目录中,将以下内容写入 compose.yaml

services:
  db:
    image: postgres:16.4
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

启动堆栈,并写入一行稍后可以识别的数据。

docker compose up -d
sleep 10
docker compose exec -T db psql -U postgres -c "create table marker (note text);"
docker compose exec -T db psql -U postgres -c "insert into marker values ('survived');"

现在删除容器,然后检查卷。

docker compose down
docker volume ls

输出中仍会列出 voltest_pgdata。容器已删除,但数据仍在。重新启动堆栈并读取该行。

docker compose up -d
sleep 10
docker compose exec -T db psql -U postgres -c "select * from marker;"

你会得到包含 survived 的一行。新容器与原容器不同,并且具有不同的 ID,但它附加到了同一个卷。如果需要了解更完整的内容,请参阅Compose 基础指南,其中介绍了命名卷与绑定挂载的区别,以及每种卷在主机上的实际位置。

down -v 会精确删除什么

-v(长选项形式为 --volumes)会删除 Compose 文件 volumes 部分中声明的命名卷,以及附加到容器的匿名卷。请对同一组服务执行此命令。

docker compose down -v
docker volume ls

voltest_pgdata 不再列出。重新启动这组服务后,Postgres entrypoint 会发现数据目录为空,因此初始化一个新的集群。容器日志会明确说明这一点。

The files belonging to this database system will be owned by user "postgres".
PostgreSQL init process complete; ready for start up.

如果这段日志出现在已经运行数月的服务组中,说明卷已被删除。您的 marker 表也已丢失,唯一的恢复方式是使用备份。

-v 永远不会删除某些存储。bind mount 指向主机路径,因此 Docker 只会卸载它,文件仍保留在原位置。标记为 external: true 的卷声明属于该项目之外的对象,Compose 不会删除它。在运行 down -v 前从 Compose 文件中删除的命名卷已不再声明,因此 Compose 不知道要删除它,会将其作为孤立卷保留,直到执行 docker volume prune

最后一种情况常见于重构期间。从文件中删除服务及其卷,运行 down -v 后,该卷仍会保留,因为文件中已不再提及它。请在编辑文件前运行 down -v,不要在编辑后运行。

何时确实需要使用 --force-recreate

docker compose up -d不会每次都重建所有容器。Compose 会将每个服务的已解析配置哈希值作为标签存储在容器上。如果哈希值和镜像 ID 都匹配,容器会保持不变,您会得到 Container voltest-db-1 Running,而不是 Recreated。这通常正是您需要的行为,因为这样可以安全地重复运行 up -d

这也是某些编辑看起来没有生效的原因。Compose 对已解析的服务定义进行哈希,而不是对该定义所指向的文件内容进行哈希。挂载到容器中、并在启动时只读取一次的配置文件,修改后不会触发容器重建,因为挂载路径没有变化。服务会继续运行,并继续使用启动时读取的值。

docker compose up -d --force-recreate

该命令会停止并删除每个容器,然后根据相同的定义创建新容器。修改了已挂载的配置文件后,或者容器进入了无法解释的状态时,可以使用它。卷不会受到影响,因此数据库数据会在强制重建后保留。要在相同标签下获取更新后的镜像,还需要同时执行拉取操作。

docker compose pull
docker compose up -d

pull会获取新的镜像 ID,随后 up -d会发现运行中容器的镜像 ID 已发生变化,并自行重建容器。在没有 pull 的情况下添加 --force-recreate,只会使用相同的旧镜像创建新容器。因此,“我执行了强制重建,但版本仍然是旧的”会成为常见问题。

docker compose restart不会执行上述任何操作。它只会重启现有容器,完全不会重新读取 Compose 文件,因此修改后的环境变量或端口映射不会生效。如果您编辑了该文件,请使用 up -d

需要牢记的思维模型

容器可以替换。容器由一个进程和一个薄的可写层组成,Compose 大约可以在 1 秒内根据文件重新构建出相同的容器。卷不能替换,因为其中保存着唯一一份状态数据,仓库中的任何文件都无法重新生成这些数据。

每个 Compose 命令都对应这种区分。stopstart 会保留容器。downup 会替换容器,但保留卷。down -v 是唯一会删除状态数据的常规命令,因此需要显式标志。在任何真实环境中执行它之前,请确认您有备份,并且至少成功恢复过一次。

同样的逻辑也适用于密钥。通过 POSTGRES_PASSWORD 设置的密码只会在数据库首次初始化时读取,因此,您在环境文件中修改密码后运行 up -d,得到的仍然是 password authentication failed for user "postgres"。容器是新的,卷是旧的,而旧卷仍然保存着旧密码。Compose 如何解析环境文件和密钥说明了同一个变量被设置两次时,哪一层配置优先。

故障模式及你将看到的字符串

no configuration file provided: not found 表示 Compose 在一个既没有 compose.yaml 也没有 docker-compose.yml 的目录中运行。使用完整路径传入 -f

down 上的 network voltest_default has active endpoints 表示项目外部的容器已连接到项目网络。通常,这是使用 docker run --network 手动启动的容器。删除该容器,然后再次运行 down

重命名或删除服务后会出现 Found orphan containers ([voltest-old-1]) for this project。旧容器仍带有项目标签。docker compose down --remove-orphans 会清理这些容器,在运行正常的堆栈上执行此命令是安全的。

手动执行 docker volume rm 时出现 Error response from daemon: remove voltest_pgdata: volume is in use,表示仍有容器引用该卷,包括已停止的容器。先运行 docker compose down,然后删除该卷;或者直接使用 down -v。对于较大的项目,请参阅多服务 Compose 堆栈,了解单个项目可能累积多少个卷。

FAQ

docker compose down 会删除我的数据库吗?

不会,前提是数据库位于命名卷或绑定挂载中。down 会删除容器和项目网络,但卷仍保留在磁盘上,数据也保持完整。下次运行 docker compose up -d 时,新容器会挂载同一个卷,数据仍然存在。只有 docker compose down -v 会删除命名卷,而且只会删除 Compose 文件中 volumes 部分声明的命名卷。

对于需要稍后恢复的容器,stop 和 down 有什么区别?

stop 会保留容器,因此 docker compose start 会将您恢复到同一个容器,并保留相同的可写层。您在容器内手动安装或修改的内容仍然存在。down 会删除容器,因此下次运行 up -d 时,会根据镜像创建一个全新的容器,这些手动修改也会丢失。调试期间,请使用 stop

如何删除 Compose 项目创建的所有内容?

docker compose down -v --rmi all --remove-orphans 会删除容器、项目网络、文件中声明的命名卷、服务使用的镜像,以及所有仍带有项目名称标签的容器。它不会处理绑定挂载或标记为 external: true 的卷。运行前使用 docker volume ls 检查即将删除的内容。

为什么容器没有应用我对挂载配置文件所做的修改?

Compose 通过比较解析后的服务定义哈希来决定是否重新创建容器,但该哈希不包含挂载文件的内容。文件路径没有变化,因此 Compose 会让容器继续运行,并继续使用容器启动时读取的值。运行 docker compose up -d --force-recreate,创建一个会重新读取该文件的新容器。

为什么我修改后的新 POSTGRES_PASSWORD 没有生效?

Postgres 镜像只会在初始化空数据目录时读取 POSTGRES_PASSWORD。您的卷中已经存在初始化完成的集群,因此该变量会被忽略,旧密码仍然有效。您会看到 password authentication failed for user "postgres"。请在运行中的数据库内使用 ALTER USER 修改密码;或者接受数据丢失,并使用 docker compose down -v 重新开始。