首页
/ Moby Engine API:基于 Swagger 驱动的 Docker Engine HTTP API 设计、文档生成与开发流程

Moby Engine API:基于 Swagger 驱动的 Docker Engine HTTP API 设计、文档生成与开发流程

2026-09-03 16:19:17作者:仰钰奇

本文以 api/README.md 为核心,系统讲解 Moby 项目中 Engine API 的组成结构、swagger.yaml 定义文件的组织方式、API 文档的更新与验证流程,以及如何通过 Makefile 目标完成文档预览、类型生成与一致性校验。读完后,你将能够独立完成 Engine API 定义文件的编辑、验证与文档预览,并理解 Go 客户端与服务端共享类型的生成机制。

一、Engine API 是什么:一个由 Swagger 定义的 HTTP API

Engine API 是 Docker 守护进程(daemon)对外提供的 HTTP API,命令行客户端通过它与 daemon 通信,第三方软件同样可以基于它控制 daemon。api/README.md 指出,该 API 由仓库中的多个组件共同构成:

组件 路径 职责
Swagger 定义文件 api/swagger.yaml Engine API 的完整 Swagger(OpenAPI 2.0)定义,是 API 的唯一事实来源
共享类型 api/types/ 客户端与服务端共用的 Go 类型,表示各类对象、选项和响应。大部分为手写,一部分由 Swagger 定义自动生成
Go 客户端 client/ 命令行客户端使用的 Go 客户端库,第三方 Go 程序也可直接引用
守护进程 daemon/ 提供服务端实现,负责实际执行 API 请求

这一“定义文件 → 生成类型 → 客户端/服务端实现”的三层结构,是理解整个 Engine API 开发流程的关键。

二、swagger.yaml:API 的单一事实来源

api/README.md 明确说明,Swagger 定义文件有三个用途:

  1. 自动生成 API 文档;
  2. 自动生成 Go 服务端与客户端代码(官方注明这仍是进行中的工作,即“Work-in-progress”);
  3. 提供机器可读的 API 描述,便于内省、为其他语言自动生成客户端等。

打开 api/swagger.yaml 可以看到文件头部的关键元信息:

swagger: "2.0"
schemes:
  - "http"
  - "https"
produces:
  - "application/json"
  - "text/plain"
consumes:
  - "application/json"
  - "text/plain"
basePath: "/v1.56"
info:
  title: "Docker Engine API"
  version: "1.56"

其中 basePath: "/v1.56" 表明当前仓库中 API 的版本为 v1.56。文件头部的风格注释还给出了若干编辑约定:

  • 该文件由 ReDoc 渲染,描述字段支持 GitHub Flavored Markdown;
  • 不限制行宽,以便编辑和生成整洁的 diff;
  • operationId 采用“NounVerb”命名格式,且名词使用单数形式(例如 ContainerListImageGet 这类模式)。

2.1 两大核心章节:definitions 与 paths

api/README.mdswagger.yaml 划分为两个主要章节,这也是编辑该文件时的基本定位方法:

  • definitions:定义请求与响应中可复用的对象;
  • paths:定义 API 端点,以及少数不需要复用的内联对象。

编辑流程是:先在 paths 中找到要修改的端点,再处理其中通过 $ref 引用的可复用对象——这些引用指向 definitions 章节中的定义。以 definitions 中的实际片段为例,可以清楚看到字段的类型、必填约束与 Go 侧的映射控制:

definitions:
  PortSummary:
    type: "object"
    description: |
      Describes a port-mapping between the container and the host.
    required: [PrivatePort, Type]
    properties:
      IP:
        type: "string"
        format: "ip-address"
        x-go-type:
          type: Addr
          import:
            package: net/netip
      PrivatePort:
        type: "integer"
        format: "uint16"
        x-nullable: false

注意 x-go-typex-nullable 等扩展字段:它们控制着自动生成 Go 类型时的映射细节,这正体现了“Swagger 定义驱动代码生成”的设计。

2.2 tags:同时定义 ReDoc 文档的导航菜单

api/swagger.yaml 中有一段专门关于 tags 的注释,说明了它们同时承担 API 分组与文档导航的职责:

  • tags 必须是单数形式;
  • tag 数量不宜过多,否则菜单难以使用——例如应将端点归入 "System" 而不是新建只有一个路径的 tag;
  • tags 列表中的顺序即文档菜单的顺序。

当前文件中定义的 tag 覆盖 Container、Image、Network、Volume、Exec、Swarm、Node、Service、Task、Secret、Config、Plugin、System 等分组,基本对应 Docker 客户端的全部核心命令面。

三、API 的版本化、错误与鉴权约定

swagger.yaml 头部的 info.description 以 Markdown 形式内嵌了 API 使用规范,这部分内容是任何 Engine API 客户端(无论是否用 Go 编写)都必须遵守的契约:

版本化。由于每个版本都会修改 API,所有调用都通过 URL 前缀锁定版本,例如调用 /v1.30/info 即使用 v1.30 版本的 /info 端点。若 URL 中指定的版本不被 daemon 支持,将返回 HTTP 400 Bad Request。省略版本前缀时会使用当前版本(等价于 /v1.56/info),但官方明确说明无版本前缀的方式已被弃用,并将在未来版本移除。

开放模式(open schema model)。服务端可以在响应中新增额外属性,客户端编写时必须忽略未知属性,以免与更新版本的 daemon 通信时出错;服务端同样会忽略多余的查询参数和请求体字段。

错误格式。API 使用标准 HTTP 状态码表示成功或失败,响应体为如下 JSON:

{
  "message": "page not found"
}

镜像仓库鉴权。对注册表的鉴权在客户端侧完成:客户端需要把凭据以 X-Registry-Auth 请求头发送给需要与注册表通信的端点(如 POST /images/(name)/push),其值是一个 base64url 编码的 JSON 字符串:

{
  "username": "string",
  "password": "string",
  "serveraddress": "string"
}

serveraddress 是不带协议的域名或 IP,且结构中的双引号是必需的。若已通过 /auth 端点获取了 identity token,也可以只传 {"identitytoken": "..."}

四、更新 API 文档的标准流程

api/README.md 给出的操作指引可归纳为四步:

  1. 修改 api/swagger.yaml。任何 API 变更都必须先编辑该文件以反映文档变化,因为 API 文档完全由它生成。修改时优先在 paths 中定位端点,通过 $ref 关联 definitions;文件内有足够的示例可以参照复制相似的字段或端点模式。
  2. 验证定义文件。README 提到 swagger.yamlhack/validate/swagger 校验。从当前仓库结构看,该校验逻辑实际落在 api 模块内:api/Makefilevalidate-swagger 目标执行 api/scripts/validate-swagger.sh,脚本先运行 yamllint -f parsable -c validate/yamllint.yaml swagger.yaml 检查 YAML 风格,再运行 swagger validate swagger.yaml 校验定义合法性。在编辑过程中随时运行该目标可以快速确认修改是否符合规范。
  3. 同步生成类型(若改动影响了生成的 Go 类型,见下节)。
  4. 预览生成的文档确认渲染效果(见第六节)。

4.1 版本化文档与 CHANGELOG

每个 API 版本的文档存放在 api/docs/ 目录:v1.24 及更早版本为 Markdown 格式(如 api/docs/v1.24.md),v1.25 起为 OpenAPI 2.0 规范文件(如 api/docs/v1.55.yaml)。api/docs/README.md 说明:

  • 对旧 API 版本的支持属于“best-effort”,建议使用最新版本,仅为兼容旧客户端时才依赖旧版本;
  • 较新版本通常向后兼容旧版本,但有弃用特性的例外;
  • 仓库根部的 swagger.yaml 是最新版本,可能包含尚未发布的变更(当前为 v1.56,而 api/docs/ 中最新已发布规范是 v1.55,印证了这一点);
  • 官方会尽力使这些规范文件与实际实现保持一致,但由于 OpenAPI 2.0 表达能力有限,仍可能存在偏差,欢迎社区通过 issue 或 PR 修正。

api/docs/CHANGELOG.md 记录了每个版本的变更明细,例如 v1.56 中 GET /containers/json 新增了 annotation 过滤器;v1.55 新增了 GET /images/{name}/attestations 端点、POST /containers/{id}/update 开始支持 per-device blkio 资源字段。维护 API 时,对照 CHANGELOG 了解各版本差异是必要步骤。

五、类型生成与一致性校验的完整工作流

api/README.md 提到 api/types/ 中的类型“大部分手写,一部分由 Swagger 自动生成”。这一机制的完整工作流可以从 api 模块的脚本与配置中看清:

5.1 生成脚本:generate-swagger-api.sh

api/scripts/generate-swagger-api.sh 定义了哪些 Swagger 对象需要生成 Go 类型,以及生成到哪个 Go 包。脚本按模型包分块调用 swagger generate model,每一块的模型名要求按字母序排列以降低合并冲突概率,例如:

generate_model types/container <<- 'EOT'
	ChangeType
	ContainerCreateResponse
	ContainerTopResponse
	ContainerUpdateResponse
	ContainerWaitExitError
	ContainerWaitResponse
	ContainersDiskUsage
	FilesystemChange
	PortSummary
EOT

生成覆盖的类型包包括 types/buildtypes/commontypes/containertypes/imagetypes/networktypes/plugintypes/registrytypes/storagetypes/swarmtypes/volume。脚本中 --config-file 指向 api/swagger-gen.yaml,该配置声明了生成布局:模型输出到对应包路径、文件名按 pascalize → snakize 命名,服务端操作代码(operations handler)单独声明——但当前实际启用的只有模型生成,服务端/客户端代码自动生成为进行中的工作。--template-dir 指向 api/templates/,其中的 api/templates/schema.gotmplapi/templates/structfield.gotmplapi/templates/server/operation.gotmpl 用于覆盖 go-swagger 的默认渲染模板,以适配 Moby 的代码风格。

5.2 一致性校验:validate-swagger-gen.sh

api/scripts/validate-swagger-gen.sh 保证“定义文件已改、生成代码也同步更新”:

  1. 通过 grep -rl "// Code generated"api/types/ 中所有带生成标记的文件与手写文件分离;
  2. 将生成文件连同 swagger.yamlswagger-gen.yamltemplates/ 复制进临时目录,在临时目录中重新运行生成脚本;
  3. 对每个生成文件执行 diff,任何差异都会打印 unified diff 并提示运行 ./scripts/generate-swagger-api.sh 后提交更新的文件,否则校验失败。

5.3 Makefile 入口

api/Makefile 提供四个核心目标,全部通过容器化环境执行(构建一个 docker-api-dev 镜像,挂载当前目录,保证工具链版本一致):

目标 作用
swagger-gen 执行 scripts/generate-swagger-api.sh,重新生成 Swagger API 类型
swagger-docs 预览 API 文档(见下节)
validate-swagger 校验 swagger.yaml 是合法的 Swagger 定义
validate-swagger-gen 校验已提交的生成类型与定义文件保持同步

根目录 Makefile 中的 swagger-genswagger-docs 目标只是转发到 $(MAKE) -C api,因此在仓库任意位置执行 make swagger-docs 均可生效。

六、预览与发布 API 文档

api/README.md 建议:编辑 swagger.yaml 后运行 make swagger-docs,在 http://localhost:9000 检查生成文档的渲染效果(样式可能有小瑕疵,但足以确认文档内容正确)。

api/Makefile 可以看到该目标的实现:将 api 目录挂载到容器内的 /usr/share/nginx/html/swagger/,设置 REDOC_OPTIONS=hide-hostname="true" lazy-renderingSPEC_URL="swagger/swagger.yaml",用 redocly/redoc:v2.5.1 镜像起一个 Redoc 服务,端口由 SWAGGER_DOCS_PORT 控制(默认 9000)。

正式文档的发布路径则是:将 swagger.yaml 以 vendor 方式引入官方的 docker/docs 仓库进行生成。而仓库内的 api/docs/ 目录则承担“每个历史版本一份规范文件”的归档职能,并配合 api/docs/CHANGELOG.md 提供版本变更总览。

七、与 Go 客户端的衔接:一个可直接运行的示例

swagger.yaml 描述的行为最终由 client/ 中的 Go 客户端封装。client/client.go 的包注释中给出了官方使用示例,等价于 docker ps 的实现:

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/moby/moby/client"
)

func main() {
	// 创建客户端:处理 DOCKER_HOST、DOCKER_API_VERSION 等环境变量,
	// 并做 API 版本协商(negotiation),以便连接旧版本 daemon 时自动降级。
	apiClient, err := client.New(client.FromEnv)
	if err != nil {
		log.Fatal(err)
	}

	// 列出所有容器(等价于 docker ps -a)。
	result, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{
		All: true,
	})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s  %-22s  %s\n", "ID", "STATUS", "IMAGE")
	for _, ctr := range result.Items {
		fmt.Printf("%s  %-22s  %s\n", ctr.ID, ctr.Status, ctr.Image)
	}
}

示例中 client.FromEnv 选项体现的正是一节中提到的版本协商机制——它读取环境变量、自动探测并降级 API 版本,使同一份客户端代码可以同时面向新旧 daemon。客户端方法(如 ContainerList 对应 GET /containers/json)与 api/swagger.yamlpaths 的 operationId 一一对应,这正是“Swagger 定义驱动一切”在客户端侧的落点。

八、小结:Engine API 的开发闭环

结合 api/README.md 与仓库实现,Engine API 的完整开发闭环如下:

  1. 编辑 api/swagger.yamlpaths 定位端点,definitions 维护可复用对象,遵守 operationId 与 tag 规范);
  2. 校验make validate-swagger(yamllint + swagger validate);
  3. 生成:若涉及生成类型,运行 make swagger-gen 更新 api/types/ 下带 // Code generated 标记的文件;
  4. 一致性检查make validate-swagger-gen 确保生成代码与定义文件零差异;
  5. 预览make swagger-docshttp://localhost:9000 用 Redoc 检查渲染结果;
  6. 归档:版本规范沉淀于 api/docs/(v1.24 为 Markdown,之后为 OpenAPI 2.0 YAML),变更记入 api/docs/CHANGELOG.md

掌握这条链路后,无论是要为 API 新增端点、新增请求字段,还是排查“文档与实现不一致”的问题,都能在 Moby 仓库内找到明确的操作入口与验证手段。

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

项目优选

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