首页
/ Docker Compose `docker compose up` 命令完全指南:构建、创建、启动与重建的编排核心

Docker Compose `docker compose up` 命令完全指南:构建、创建、启动与重建的编排核心

2026-09-08 22:11:29作者:蔡丛锟

本文基于本仓库(Docker Compose)的官方命令参考文档 docs/reference/compose_up.md 编写,并结合 cmd/pkg/ 下的命令实现与测试用例展开源码级解析。

docker compose up 是 Docker Compose 中使用频率最高的单一入口命令:它负责构建镜像、拉取镜像、创建并启动服务容器,并在前台模式下汇总聚合各容器的日志输出。本指南将系统讲解该命令的完整行为模型、全部选项参数、重建/级联/等待策略以及 pre_start 生命周期钩子的故障排查流程,帮助你掌握"一条命令拉起整个应用栈"背后可精确控制的分阶段语义。

docker compose up 的职责与完整生命周期

官方文档对 docker compose up 的定义是:为服务构建、创建、启动并附着到容器(Builds, (re)creates, starts, and attaches to containers for a service)。如果相关联的服务尚未运行,它也会顺带启动这些关联服务(dependency),因此它天然具备"从零拉起整个应用"的能力。

从源码调用链看,命令的核心实现在 cmd/compose/up.go,其底层最终落到 pkg/compose/up.gocomposeService.Up

func (s *composeService) Up(ctx context.Context, project *types.Project, options api.UpOptions) error {
	err := Run(ctx, ..., func(ctx context.Context) error {
		err := s.create(ctx, project, options.Create)   // 阶段一:创建容器
		if err != nil {
			return err
		}
		if options.Start.Attach == nil {                 // 阶段二:后台模式直接启动
			return s.start(ctx, project.Name, options.Start, nil)
		}
		return nil
	}, "up", s.events)
    ...
	return s.runInteractiveUp(ctx, project, options)    // 前台模式:附着日志 + 交互
}

由此可以总结出 docker compose up 内部依次经历的阶段:

  1. 构建 / 拉取:若配置需要且策略允许,先执行镜像 build 或 pull;
  2. 创建(Create):创建各服务容器(此时并不启动,等价于 docker compose create);
  3. 启动(Start):启动已创建的容器及其依赖服务;
  4. 附着(Attach,前台模式):聚合各容器输出,行为类似 docker compose logs --follow;当命令退出时,所有容器被停止。

命令格式为:

docker compose up [OPTIONS] [SERVICE...]

不指定 SERVICE 时作用于 compose 文件中的全部服务;指定一个或多个服务名时,默认仍会连带其依赖服务(除非传入 --no-deps)。实现上通过 upOptions.apply 完成服务子集筛选(cmd/compose/up.go),若结合 --no-deps 则使用 types.IgnoreDependencies 忽略依赖。

全量选项速查表

下表完整收录自 docs/reference/compose_up.md,与 cmd/compose/up.go 中实际注册的 cobra flags 一一对应:

名称 类型 默认值 说明
--abort-on-container-exit bool 任一容器停止时停止所有容器,与 -d 不兼容
--abort-on-container-failure bool 任一容器以失败退出时停止所有容器,与 -d 不兼容
--always-recreate-deps bool 重建依赖容器,与 --no-recreate 不兼容
--attach stringArray 仅附着到指定服务,与 --attach-dependencies 不兼容
--attach-dependencies bool 同时附着到依赖服务的日志输出
--build bool 启动容器前先构建镜像
-d, --detach bool 分离模式:后台运行容器
--dry-run bool 以演练(dry run)模式执行命令
--exit-code-from string 返回指定服务容器的退出码,隐含 --abort-on-container-exit
--force-recreate bool 即使配置与镜像未变化也重建容器
--menu bool 前台附着时启用交互快捷键,与 --detach 不兼容;也可由环境变量 COMPOSE_MENU 控制
--no-attach stringArray 不附着(不流式输出日志)到指定服务
--no-build bool 即使策略允许也不构建镜像
--no-color bool 单色输出
--no-deps bool 不启动关联服务
--no-log-prefix bool 日志中不打印前缀
--no-recreate bool 容器已存在则不重建,与 --force-recreate 不兼容
--no-start bool 只创建不启动服务
--pull string policy 运行前拉取镜像("always"|"missing"|"never"
--quiet-build bool 抑制构建输出
--quiet-pull bool 拉取时不打印进度信息
--remove-orphans bool 移除不在 compose 文件中定义的服务容器
-V, --renew-anon-volumes bool 重建匿名卷,而非从旧容器继承数据
--scale stringArray 将 SERVICE 扩缩到 NUM 个实例,覆盖 compose 文件中的 scale 设置
-t, --timeout int 0 附着或容器已运行时用于关停容器的超时秒数
--timestamps bool 显示时间戳
--wait bool 等待服务处于 running/healthy,隐含分离模式
--wait-timeout int 0 等待项目达到 running/healthy 的最大秒数
-w, --watch bool 监听源码,文件更新时重建/刷新容器
-y, --yes bool 对所有提示默认回答 yes,非交互式运行

标志间冲突校验:不可组合的选项

这些"不兼容"并非口头约定,而是在 PreRunE 阶段由 cmd/compose/up.govalidateFlags 强校验的。部分典型约束包括:

  • --detach 不能与 --abort-on-container-exit--abort-on-container-failure--attach--attach-dependencies--watch 组合;
  • --wait自动隐含分离模式up.Detach = true),因此同样不能再与上述附着类选项组合;
  • --force-recreate--no-recreate--always-recreate-deps--no-recreate--no-recreate--renew-anon-volumes--build--no-build--no-build--watch 两两互斥;
  • --exit-code-from--abort-on-container-failure 可叠加;--abort-on-container-exit--abort-on-container-failure 不可同时使用;
  • --wait-timeout 必须是非负整数。

前台 vs 后台:attach / detach 的输出控制模型

官方文档明确了三种常见运行形态:

$ docker compose up               # 前台:聚合日志,Ctrl+C 退出后停止全部容器
$ docker compose up --detach      # 后台:容器持续运行,命令立即返回
$ docker compose up --no-start    # 只创建不启动(等价 create 阶段)

前台的"附着输出"默认包含所有被启动的服务(含依赖),因此默认输出形态等同于 docker compose logs --follow。当某些服务日志过于冗长时,可用三组标志精细裁剪:

  • --attach <service>:只附着指定服务(可重复),此时无法再附着依赖,故与 --attach-dependencies 互斥;
  • --attach-dependencies:连依赖服务的日志一起附着;
  • --no-attach <service>:从附着集合中剔除指定服务,保留其余服务的输出。

实现细节(cmd/compose/up.go):--attach 给出的服务名必须是被启动项目的一部分,否则直接报错 cannot attach to services not included in up--no-attach 则作为过滤器在运行时从集合中 RemoveAll。另外,compose YAML 中服务若声明 attach: false,该服务默认就不会被自动附着(除非显式 --attach)。--no-log-prefix 关闭每行日志的 <service> | 前缀,--timestamps 追加时间戳,--no-color 关闭 ANSI 彩色输出,这三者共同决定日志渲染外观(对应 pkg/compose 的日志消费者构建处)。

重建策略:diverged / force / never 三种模式的取舍

docker compose up已有旧容器时,默认会根据"服务的配置或镜像自容器创建以来是否发生变化"来决定是否重建。变化的容器会被停止并重建,且保留已挂载的卷(mounted volumes);未变化的容器则保持原样。

从源码看,三种策略被建模为常量(pkg/api/api.go):

  • RecreateDiverged = "diverged":默认策略——仅当容器配置与 compose 模型出现分歧(diverges)时才重建;
  • RecreateForce = "force":无条件重建;
  • RecreateNever = "never":绝不重建。

CLI 层将用户标志翻译为这些策略(cmd/compose/create.go):

func (opts createOptions) recreateStrategy() string {
	if opts.noRecreate {
		return api.RecreateNever
	}
	if opts.forceRecreate {
		return api.RecreateForce
	}
	if opts.noInherit { // -V / --renew-anon-volumes
		return api.RecreateForce
	}
	return api.RecreateDiverged
}

func (opts createOptions) dependenciesRecreateStrategy() string {
	if opts.noRecreate {
		return api.RecreateNever
	}
	if opts.recreateDeps {
		return api.RecreateForce // --always-recreate-deps
	}
	return api.RecreateDiverged
}

日常典型用法:

$ docker compose up                      # 只在配置/镜像变化时重建
$ docker compose up --no-recreate        # 已存在容器一律不重建(例如只是想补启动缺失的服务)
$ docker compose up --force-recreate     # 强制重建全部容器(如想应用运行时的环境变更)
$ docker compose up --always-recreate-deps   # 每次重建依赖容器(常用于 CI 确保依赖最新)

注意 --renew-anon-volumes-V)会强制重建并从策略上丢弃旧匿名卷数据,因其与"保留数据"的继承语义冲突,故与 --no-recreate 互斥。--timeout-t)则作用于关停容器时的宽限期(秒),仅当用户在命令行显式指定时才会覆盖默认值(GetTimeout 依据 timeChanged 判断)。

Build 与 Pull 的精细控制

docker compose up 的拉取默认策略是 policy,即由镜像的 pull_policy 决定是否/何时拉取(注册默认值 "pull""policy")。若显式传入 --pull,则只接受三个取值之一:alwaysmissingnever,且会把所选策略应用到项目全部服务(cmd/compose/create.goApply 遍历服务覆写 PullPolicy)。无效取值会报 invalid --pull option

镜像构建相关的标志分三档:

  • --build:强制在启动前构建所有带 build 上下文的服务(实现上等效于把这些服务的 pull_policy 置为 build,见 Apply);
  • --no-build:关闭构建——即使某个服务按策略需要本地构建(如 pull_policy: build)也跳过;该标志与 --watch 互斥;
  • --quiet-build / --quiet-pull:分别抑制构建进度与拉取进度条输出。

实际构建以 api.BuildOptions 形式合并进 api.CreateOptions,且会覆盖"显式指定的服务 + 其依赖"这一完整集合(cmd/compose/up.go),保证了依赖镜像缺位时 up 仍能自举构建。

退出码、信号处理与级联停止

官方文档对退出语义给出明确的契约:

  • 命令执行过程中遇到错误,退出码为 1
  • 前台运行中被 SIGINT(Ctrl+C)或 SIGTERM 中断时,所有容器被停止,退出码为 0

升级版的级联(cascade)行为由三个标志提供,其中 --exit-code-from <service> 特别适合"启动完就跑"的任务型编排——它返回所选服务容器的退出码,并隐含启用 --abort-on-container-exit,即任何容器退出都会停止整栈:

func (opts upOptions) OnExit() api.Cascade {
	switch {
	case opts.cascadeStop:
		return api.CascadeStop       // --abort-on-container-exit
	case opts.cascadeFail:
		return api.CascadeFail       // --abort-on-container-failure
	default:
		return api.CascadeIgnore
	}
}

(见 cmd/compose/up.go--exit-code-from 会把 cascadeStop 置真,见 validateFlags。)

典型场景示例——构建测试矩阵后按被测服务退出码判定 CI 成败:

$ docker compose up --exit-code-from tests --abort-on-container-failure
$ echo $?   # 拿到 tests 服务容器的真实退出码

同时,级联停止与"前台附着输出"天然绑定,因此它们全部与 -d/--wait 互斥。

等待就绪:--wait / --wait-timeout

--waitdocker compose up 在容器启动后继续等待,直到项目内服务达到 running/healthy 状态(结合服务 healthcheck 与依赖条件判定),隐含分离模式,适合自动化脚本在 up 之后立即消费服务。等待时长上限由 --wait-timeout(秒)控制,超过则报错;两个参数在源码中分别落到 api.StartOptions.WaitWaitTimeoutcmd/compose/up.go)。仓库中的端到端样例 pkg/e2e/testdata/TestUpWait/compose.yaml 展示了配合 depends_on: condition: service_completed_successfully 使用一次性任务的典型形态。

源码热更新:-w / --watch

-w, --watchup 转为开发模式:附着输出的同时监听项目源码目录,文件变更即触发对应服务的镜像重建或容器刷新(refresh)。实现上由 pkg/compose/up.go 中创建的 Watcher 驱动,并可与交互菜单联动(见下文)。注意 watch 的语义要求可构建,因此与 --no-build 互斥;更多细节可参考仓库中的 compose_watch.mdpkg/watch/ 目录下的 watcher 实现。

扩缩容与孤儿容器清理

  • --scale SERVICE=NUM:命令行级扩缩容,覆盖 compose 文件中的 scale/deploy.replicas;格式错误(缺少 = 或非数字)会由 applyScaleOpts 直接报错(cmd/compose/create.go);
  • --remove-orphans:清理"属于当前项目但未在 compose 文件中定义"的孤儿容器。

值得一提的是这些行为同样受到环境变量的影响(定义见 cmd/compose/compose.go):

  • COMPOSE_REMOVE_ORPHANS:当命令行未显式指定 --remove-orphans 时,取其布尔值作为默认行为(up.go 的 PreRunE);
  • COMPOSE_IGNORE_ORPHANS:从项目环境读取,若与 --remove-orphans 同时为真会直接报错冲突(up.go)。

交互式导航菜单:--menu 与 COMPOSE_MENU

前台附着模式下可启用交互式快捷键菜单(--menu)。其默认开启逻辑较为讲究(resolveNavigationMenucmd/compose/up.go):

  1. 输出非 TTY(例如被管道化)时强制关闭;
  2. 未显式传 --menu 时读取环境变量 COMPOSE_MENU(取值 true/false);
  3. 两者都未提供时默认 true

最终菜单是否真正生效还要求当前 display 模式非 plain 且 stdin 为终端(见 cmd/compose/up.go 的组合条件)。由于它服务于前台附着,与 --detach 不兼容。启用后可通过快捷键在附着日志中执行暂停、终止、切换时间戳等操作(菜单与 watcher、detach 能力的接线在 pkg/compose/up.go)。

pre_start 生命周期钩子:失败时的保留与排查

Compose 支持通过 compose 文件中的 pre_start 钩子在服务容器真正启动前运行一次性任务容器。官方文档明确了失败语义:当某个 pre_start 钩子以非零码退出时,Compose 会中止该服务的启动,并保留(retain)这个钩子容器以便排查。参考 e2e 样例 pkg/e2e/testdata/TestPreStartHookSuccess/compose.yaml

services:
  sample:
    image: alpine
    command: sh -c 'cat /shared/init.txt && sleep 5'
    volumes:
      - data:/shared
    pre_start:
      - image: alpine
        command: sh -c 'echo "initialized" > /shared/init.txt'
volumes:
  data:

失败后的三条排查命令

钩子容器带有 com.docker.compose.hook=pre_start 标签,因此可精确过滤定位:

$ docker ps -a --filter label=com.docker.compose.hook=pre_start
$ docker logs <container-id>

钩子容器的自动清理机制

源码中的钩子实现位于 pkg/compose/pre_start.go

  • 每次 runPreStart 开始时(pre_start.go),会先校验钩子配置(当前不支持 per_replica: true,会直接报错并不触发任何 I/O),随后按声明的顺序顺序执行各钩子,任一失败即中断并向外抛错门控服务启动;
  • 每个钩子以临时容器形式运行,通过 VolumesFrom 共享服务容器的卷、接入同一网络;数据写入请使用命名卷或 bind mount(匿名卷与 tmpfs 按副本隔离,不会共享给钩子);
  • 执行前会自动 removeOrphanPreStartContainers:把上一次失败遗留的同项目同服务 HookLabel=pre_start 钩子容器清理掉,避免累积。因此下一次 docker compose up 前会自动清掉旧钩子残留
  • docker compose down 同样负责清理——pkg/compose/down.goremovePreStartHookContainers 会按项目名 + 服务名 + 钩子标签强制删除保留容器,对应测试 TestDownRemovesRetainedPreStartHookContainerspkg/compose/down_test.go)。

总结:一次 docker compose up 的决策路径

把以上要素串起来,一次不带参数的前台 docker compose up 大致走完这样一条决策链:

  1. 解析 compose 文件与选择的服务集合(校验 --exit-code-from 服务存在性、--no-deps 依赖裁剪、空集合时报 no service selected,见 up.go);
  2. --pull / --build / --no-build 决定拉取与构建动作;
  3. 进入 create 阶段:依据 --no-recreate / --force-recreate / --always-recreate-deps / --renew-anon-volumes 决定每类容器的重建策略;
  4. 进入 start 阶段(除非 --no-start),前台则构造日志消费者并按 --attach / --no-attach / --attach-dependencies / attach: false 决定附着集合;
  5. 若任一服务的 pre_start 钩子失败,中止启动并保留钩子容器供排查;
  6. 依据 --abort-on-container-exit / --abort-on-container-failure / --exit-code-from 设定级联退出语义,配合 --wait/--wait-timeout 决定命令何时返回及以何退出码返回。

理解这条路径后,无论是日常本地开发(up --watch)、后台常驻(up -d)、CI 就绪等待(up --wait --wait-timeout 60)还是任务退出码透传(up --exit-code-from job),都能准确选对参数组合并预判行为。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391