Docker Compose export 命令详解:将服务容器文件系统导出为 tar 归档
docker compose export 用于把 Compose 项目中某个服务容器的文件系统打包导出为 tar 归档,其能力等价于对单个容器执行引擎 API 的 ContainerExport,但在 Compose 视角下以"服务名 + 副本索引"定位目标容器。本文基于 compose 仓库的命令参考文档与源码实现,完整解析该命令的参数、导出行为约束(终端输出限制、原子写入、dry-run)以及容器定位与调用链细节,帮助你在数据抢救、环境备份等场景中正确使用它,并理解底层实现。
一、命令概览:导出服务容器的文件系统
命令参考文档 compose_export.md 对该命令的定义是:
Export a service container's filesystem as a tar archive(将服务容器的文件系统导出为 tar 归档)
用法格式为:
docker compose export [OPTIONS] SERVICE
其中 SERVICE 为必填位置参数(命令定义 中 Args: cobra.MinimumNArgs(1) 强制要求至少一个参数),且支持通过 ValidArgsFunction 对服务名做 Shell 自动补全。
选项一览
完整继承参考文档的选项表如下:
| Name | Type | Default | Description |
|---|---|---|---|
--dry-run |
bool |
Execute command in dry run mode | |
--index |
int |
0 |
index of the container if service has multiple replicas. |
-o, --output |
string |
Write to a file, instead of STDOUT |
几个值得注意的点:
--dry-run是全局继承选项,并非 export 专属。在机器可读的命令定义 docker_compose_export.yaml 中,index和output列在options段,而dry-run位于inherited_options段(默认值false)。--index默认值为0,仅在服务的容器有多个副本时才有意义。-o是--output的短选项,用于把归档写入文件而非 STDOUT。
二、导出行为的关键约束
阅读 实现代码 pkg/compose/export.go 可以发现若干条文档未明说、但对实操影响很大的约束。
1. 输出到终端必须显式指定 -o
if options.Output == "" {
if s.stdout().IsTerminal() {
return fmt.Errorf("output option is required when exporting to terminal")
}
} else if err := command.ValidateOutputPath(options.Output); err != nil {
return fmt.Errorf("failed to export container: %w", err)
}
当 stdout 是交互式终端且未指定 -o 时,命令直接报错退出——避免二进制 tar 流打乱终端显示。也就是说:
docker compose export -o backup.tar app:写入文件;docker compose export app > backup.tar:重定向到管道/文件是允许的(stdout 此时不是终端);docker compose export app(在终端中直接运行):报错。
2. 文件写入采用原子写且权限为 0600
当指定了 -o 时,归档通过 atomicwriter 写入:
writer, err := atomicwriter.New(options.Output, 0o600)
这带来两个行为:目标文件以 0600 权限创建(仅属主可读写);写入以原子方式完成,中途失败不会留下半截文件。
3. --dry-run 只走流程、不落盘
if !s.dryRun {
if options.Output == "" {
_, err := io.Copy(s.stdout(), responseBody)
...
} else {
...
_, err = io.Copy(writer, responseBody)
...
}
}
在 dry-run 模式下,引擎侧的 ContainerExport 调用仍然会发生(响应体被创建并关闭),但 io.Copy 写入步骤被整体跳过,即不产生归档文件。整个过程的事件状态(exporting → exported)仍会正常上报。
4. 执行过程的事件上报
导出开始与完成分别通过 s.events.On(...) 上报 StatusExporting(Working)与 StatusExported(Done)两类事件,资源 ID 为规范化容器名。这使 compose 的进度展示与 --dry-run 状态汇总能够覆盖 export 操作。
三、容器定位:服务名、--index 与 one-off 容器
export 不像 docker 原生命令那样直接接收容器 ID,而是通过 getSpecifiedContainer 按 Compose 语义定位目标容器:
container, err := s.getSpecifiedContainer(ctx, projectName, oneOffInclude, false, options.Service, options.Index)
该函数(pkg/compose/containers.go)的行为决定了几条重要规则:
- 只定位运行中的容器。调用参数
all=false,即ContainerList不带All过滤,已停止的容器不会被选中——若服务没有运行中容器,报错service "xxx" is not running; - 支持 one-off 容器。传入的
oneOff参数为oneOffInclude,意味着docker compose run创建的 one-off 容器同样可以被 export(exec、attach、commit等命令也复用同一oneOffInclude语义); --index通过容器编号标签过滤。当--index > 0时,追加label=com.docker.compose.container-number=<index>过滤条件;若指定副本不存在,报错service "xxx" is not running container #N;- 默认取编号最小的容器。结果按
com.docker.compose.container-number标签升序排列,one-off 容器被排到末尾,最终取列表首项。
另外项目名在入口处会先做 strings.ToLower 归一化(pkg/compose/export.go),与 Compose 项目名统一小写的约定一致。
四、完整调用链:从 Cobra 命令到 Docker Engine API
整条链路如下,每一环都能在仓库中找到对应文件:
cmd/compose/export.go cobra 命令解析,构建 api.ExportOptions
│
▼
pkg/api/api.go Compose 接口定义:Export(ctx, projectName, ExportOptions)
│
▼
pkg/compose/export.go composeService.Export → export()
│ ① getSpecifiedContainer 定位运行中的目标容器
│ ② 校验输出目标(终端 / -o 路径)
│ ③ apiClient().ContainerExport 发起引擎 API
│ ④ io.Copy 写 stdout 或 atomicwriter 落盘
▼
Docker Engine POST /containers/{id}/export
- 命令入口 cmd/compose/export.go:解析
SERVICE位置参数与--index、-o两个标志,组装api.ExportOptions后调用backend.Export(ctx, projectName, exportOptions); - API 层选项结构(pkg/api/api.go):
// ExportOptions group options of the Export API
type ExportOptions struct {
Service string
Index int
Output string
}
- 服务层入口带统一的执行包装
Run(...)与事件总线(pkg/compose/export.go),操作名上报为"export"; - 真正干活的是引擎客户端
ContainerExport,其 mock 与 dry-run 客户端分别在 mocks/mock_docker_api.go 与 pkg/dryrun/dryrunclient.go 中有对应实现,后者保证--dry-run无需真实引擎也能走通全流程。
五、典型用法示例
以一个多副本服务为例:
# 导出 app 服务首个副本(编号最小)的容器文件系统
docker compose export -o app-fs.tar app
# 导出 app 服务的第 2 个副本
docker compose export --index 2 -o app-fs-2.tar app
# 直接通过管道处理(stdout 非终端,允许不指定 -o)
docker compose export app | tar -tvf - | head
# dry-run:走完整流程但不写入文件
docker compose export --dry-run -o /tmp/x.tar app
几点适用前提与限制:
- 目标服务必须正在运行(停止的容器无法被选中);
- 导出结果是容器当前文件系统快照(含运行期写入、未提交到镜像的变化),等价于
docker export的语义,不包含镜像元数据;如需生成可复用镜像,应使用语义相近但方向不同的docker compose commit(二者共用同一套容器定位逻辑,见 pkg/compose/commit.go); - 指定
-o生成的文件权限为0600,属主之外不可读,注意后续分发时的权限处理。
六、测试与机器可读定义
- 端到端测试见 pkg/e2e/export_test.go,覆盖
TestExport(单副本)与TestExportWithReplicas(多副本 +--index)两个场景,对应 fixture 位于 pkg/e2e/testdata/TestExport/compose.yaml 与 pkg/e2e/testdata/TestExportWithReplicas/compose.yaml; - 机器可读的命令元数据见 docker_compose_export.yaml,其中
usage、short/long与人类可读文档保持一致,可作为 CLI 文档生成的数据源; - API 层的
Export接口契约定义在 pkg/api/api.go,可供上层工具(如 IDE 插件、CI 脚本)直接调用。
综合来看,docker compose export 把"按 Compose 语义找到容器"与"引擎级文件系统打包"组合成了一条命令:它以服务名为入口、以 --index 精确到副本、以 -o 安全落盘,是容器运行态数据抢救与备份时值得记住的工具。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00