首页
/ Moby Engine API v1.20 参考:Docker 守护进程的 REST 接口、端点体系与版本协商机制

Moby Engine API v1.20 参考:Docker 守护进程的 REST 接口、端点体系与版本协商机制

2026-09-06 23:06:10作者:管翌锬

本文以 Moby 仓库中 Engine API v1.20 官方文档 为核心,系统讲解 v1.20 版本的 Engine API 设计约定(Unix socket 监听、HTTP 劫持、版本前缀协商)及其完整的端点体系(容器、镜像、杂项三大类 30 余个端点),并结合当前仓库的 路由注册源码版本校验实现 说明这些端点在守护进程中的落地方式,帮助读者掌握如何直接以 HTTP 请求驱动 Docker 守护进程、以及如何判断 API 版本的可用性。

1. v1.20 API 的核心设计约定

api/docs/v1.20.md 在 “Brief introduction” 一节中给出了四条所有版本通用的基本原则,理解它们是编写任何 Engine API 客户端的前提:

  1. 默认监听 Unix socket。守护进程默认监听 unix:///var/run/docker.sock。文档同时指出可以将其绑定到其他 host/port 或 Unix socket(通过 dockerd 的绑定参数)。这意味着大多数场景下客户端不需要走 TCP,直接对 socket 发 HTTP 请求即可。
  2. 整体是 REST 风格,但存在“连接劫持”(hijacking)例外。对于 attachpull 这类复杂命令,HTTP 连接会被劫持,用于双向透传 stdoutstdinstderr,而不是按常规的“请求-响应-关闭”模式工作。
  3. POST 请求体必须携带 Content-Length。所有期望请求体的 POST 端点都要求该头存在,否则请求会被拒绝。
  4. 通过 URL 版本前缀锁定 API 版本。例如请求 /v1.18/info 即声明按 v1.18 语义与守护进程交互;若 URL 中不带版本号,则使用守护进程支持的最大版本。若指定的版本不被守护进程支持,会返回 HTTP 400 Bad Request

这四条约定在 v1.20 文档 的第 1 节中逐字给出,是整个参考手册的行为契约。

1.1 v1.20 在当前仓库中的支持状态:重要的适用前提

需要特别强调一个适用前提:当前 Moby 主分支的守护进程已不再支持 v1.20daemon/config/config.go 中定义了:

  • MaxAPIVersion = "1.56"(守护进程支持的最高 REST API 版本);
  • MinAPIVersion = "1.24"(可配置下限,低于该值的配置会直接报错);
  • defaultMinAPIVersion = "1.40"(实际生效的最低支持版本,介于两者之间的 1.24~1.39 属于已弃用区间)。

daemon/config/config.go 中的 ValidateMinAPIVersion 会拒绝小于 MinAPIVersion 或大于 MaxAPIVersion 的配置。也就是说,一个按本文档以 /v1.20/... 前缀发起请求的客户端,会被当前守护进程判定为“API version too old”并收到 400 响应。这一点在 daemon/server/server.go 中有明确的代码体现:当 URL 中的版本低于 1.24 时,服务端故意以纯文本而非 JSON 返回错误,以避免旧客户端无法解析 JSON 错误体:

// While we no longer support API versions older than 1.24 [config.DefaultMinAPIVersion],
// a client may try to connect using an older version and expect a plain-text error
// instead of a JSON error. ...
if v := vars["version"]; v != "" && versions.LessThan(v, "1.24") {
    http.Error(w, err.Error(), statusCode)
} else {
    _ = httputils.WriteJSON(w, statusCode, &common.ErrorResponse{Message: err.Error()})
}

因此,本文的价值在于:v1.20 是理解 Engine API 历史语义(尤其是 v1.24 之后各版本 diff 的基线)的重要参考文档,其端点命名、参数风格与错误约定与新版 API 一脉相承;但实际对接现网守护进程时,应以 /v1.40 及以上版本前缀为准

2. 端点总览:v1.20 的三大类端点

api/docs/v1.20.md 的 “Endpoints” 章节按资源划分为三组,全部端点清单如下,可用作接口速查表:

分组 端点 方法 + 路径
2.1 容器 List containers GET /containers/json
2.1 容器 Create a container POST /containers/create
2.1 容器 Inspect a container GET /containers/{id}/json
2.1 容器 List processes (top) GET /containers/{id}/top
2.1 容器 Get container logs GET /containers/{id}/logs
2.1 容器 Filesystem changes GET /containers/{id}/changes
2.1 容器 Export a container GET /containers/{id}/export
2.1 容器 Get container stats GET /containers/{id}/stats
2.1 容器 Resize a container TTY POST /containers/{id}/resize
2.1 容器 Start / Stop / Restart / Kill POST /containers/{id}/start|stop|restart|kill
2.1 容器 Rename / Pause / Unpause POST /containers/{id}/rename|pause|unpause
2.1 容器 Attach to a container POST /containers/{id}/attach(另有 WebSocket 变体)
2.1 容器 Wait a container POST /containers/{id}/wait
2.1 容器 Remove a container DELETE /containers/{id}
2.1 容器 Copy files from a container GET /containers/{id}/archive(HEAD 变体获取文件元信息)
2.1 容器 Get an archive of a filesystem resource GET /containers/{id}/archive
2.1 容器 Extract an archive to a container PUT /containers/{id}/archive
2.2 镜像 List Images GET /images/json
2.2 镜像 Build image from a Dockerfile POST /build
2.2 镜像 Create an image POST /images/create
2.2 镜像 Inspect an image GET /images/{name}/json
2.2 镜像 Get the history of an image GET /images/{name}/history
2.2 镜像 Push an image POST /images/{name}/push
2.2 镜像 Tag an image POST /images/{name}/tag
2.2 镜像 Remove an image DELETE /images/{name}
2.2 镜像 Search images GET /images/search
2.3 杂项 Check auth configuration POST /auth
2.3 杂项 Display system-wide information GET /info
2.3 杂项 Show the docker version information GET /version
2.3 杂项 Ping the docker server GET /_ping
2.3 杂项 Create an image from a container's changes POST /commit
2.3 杂项 Monitor Docker's events GET /events
2.3 杂项 Get a tarball containing all images in a repository GET /images/{name}/get
2.3 杂项 Get a tarball containing all images GET /images/get
2.3 杂项 Load a tarball with images and tags POST /images/load
2.3 杂项 Exec Create / Start / Resize / Inspect POST /containers/{id}/execPOST /exec/{id}/startPOST /exec/{id}/resizeGET /exec/{id}/json

从当前仓库源码看,这些路径定义与文档高度一致。daemon/server/router/container/container.go 中的 initRoutes 注册了容器类全部路由:GET /containers/jsonPOST /containers/createGET/POST 各类动作路由,以及 PUT /containers/{name}/archive 等;唯一超出 v1.20 文档的新增路由(如 POST /containers/prune)通过 router.WithMinimumAPIVersion("1.25") 标注了最低 API 版本——这正是“每个版本文档对应一个端点集合”这一设计思想在源码中的直接体现。镜像类路由则注册在 daemon/server/router/image/image.go,系统/构建类路由在 daemon/server/router/system/system.godaemon/server/router/build/build.go 中。

3. 容器端点详解(2.1 Containers)

3.1 列出容器:GET /containers/json

v1.20 文档给出的标准请求与响应:

GET /v1.20/containers/json?all=1&before=8dfafdbc3a40&size=1 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[
     {
             "Id": "8dfafdbc3a40",
             "Names":["/boring_feynman"],
             "Image": "ubuntu:latest",
             "Command": "echo 1",
             "Created": 1367854155,
             "Status": "Exit 0",
             "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}],
             "Labels": {
                     "com.example.vendor": "Acme",
                     "com.example.license": "GPL",
                     "com.example.version": "1.0"
             },
             "SizeRw": 12288,
             "SizeRootFs": 0
     },
     ...
]

注意示例响应中 SizeRw/SizeRootFs 字段只有在 size=1 时才有实际数值。查询参数共六个,语义如下:

参数 取值 说明
all 1/True/true0/False/false 显示所有容器;默认只显示运行中的(默认 false)
limit 整数 只返回最近创建的 limit 个容器,含非运行态
since 容器 ID 只返回该 ID 之后创建的容器,含非运行态
before 容器 ID 只返回该 ID 之前创建的容器,含非运行态
size 1/True/true0/False/false 返回每个容器的 SizeRw/SizeRootFs 大小
filters JSON 编码的 map[string][]string 支持的过滤器:exited=<int>(退出码)、status=created|restarting|running|paused|exited)、label=keylabel="key=value"

状态码:200 无错误、400 参数错误、500 服务端错误。

该端点在守护进程侧由 daemon/server/router/container/container.goGET /containers/json 路由处理,handler 为 getContainersJSON,最终委托给 daemon 的容器列表逻辑。

3.2 创建容器:POST /containers/create

这是 v1.20 中参数面最宽的端点之一。请求体为 JSON,要求 Content-Type: application/jsonContent-Length 头(见第 1 节约定)。文档给出的代表性请求体结构(节选核心字段):

POST /v1.20/containers/create HTTP/1.1
Content-Type: application/json
Content-Length: 12345

{
       "Hostname": "",
       "Domainname": "",
       "User": "",
       "AttachStdin": false,
       "AttachStdout": true,
       "AttachStderr": true,
       "Tty": false,
       "OpenStdin": false,
       "StdinOnce": false,
       "Env": ["FOO=bar", "BAZ=quux"],
       "Cmd": ["date"],
       "Entrypoint": null,
       "Image": "ubuntu",
       "Labels": {
               "com.example.vendor": "Acme",
               "com.example.license": "GPL",
               "com.example.version": "1.0"
       },
       "Volumes": { "/volumes/data": {} },
       "WorkingDir": "",
       "NetworkDisabled": false,
       "MacAddress": "12:34:56:78:9a:bc",
       "ExposedPorts": { "22/tcp": {} },
       "HostConfig": {
         "Binds": ["/tmp:/tmp"],
         "Links": ["redis3:redis"],
         "LxcConf": {"lxc.utsname":"docker"},
         "Memory": 0,
         "MemorySwap": 0,
         "CpuShares": 512,
         "CpuPeriod": 100000,
         "CpuQuota": 50000,
         "CpusetCpus": "0,1",
         "CpusetMems": "0,1",
         "BlkioWeight": 300,
         "MemorySwappiness": 60,
         "OomKillDisable": false,
         "PidMode": "",
         "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
         "PublishAllPorts": false,
         "Privileged": false,
         "ReadonlyRootfs": false,
         "Dns": ["8.8.8.8"],
         "DnsSearch": [""],
         "ExtraHosts": null,
         "VolumesFrom": ["parent", "other:ro"],
         "CapAdd": ["NET_ADMIN"],
         "CapDrop": ["MKNOD"],
         ...
       }
}

从请求体结构可以看出 v1.20 的设计取向:配置被显式拆分为“容器配置”(顶层字段:镜像、命令、环境变量、端口声明、卷声明等)与“主机配置”(HostConfig:资源限制、网络绑定、设备、能力集等)Memory/MemorySwapCpuShares/CpuPeriod/CpuQuotaCpusetCpus/CpusetMems 对应 cgroup 限制,PortBindingsExposedPorts 分别描述“实际绑定”和“镜像级端口声明”。

创建成功时返回 201,响应体含 IdWarnings。在 api/docs/v1.20.md 的 “3.1 Inside docker run” 一节中,文档进一步解释了 docker run 在内部会依次调用 create、start、attach 等端点——也就是说,理解 create 请求体结构等价于理解了 docker run 大半的参数空间。

3.3 生命周期动作端点

v1.20 为容器提供了一组语义单一的动作端点,全部为 POST,以 {id} 作为路径参数,多数支持 204(动作成功)或 304(资源未改变)语义:

  • StartPOST /containers/{id}/start):查询参数 container 为实际启动对象;响应常见 204,容器已运行时为 304
  • StopPOST /containers/{id}/stop):查询参数 t 指定优雅停机等待秒数。
  • RestartPOST /containers/{id}/restart):同样支持 t 参数。
  • KillPOST /containers/{id}/kill):查询参数 signal 指定信号(如 SIGKILL9),未指定时默认发送 SIGKILL
  • Pause / UnpausePOST /containers/{id}/pause.../unpause):基于 cgroup freezer 暂停/恢复容器内所有进程。
  • RenamePOST /containers/{id}/rename):查询参数 name 为新名称。
  • Resize TTYPOST /containers/{id}/resize):查询参数 hw 分别为终端高宽。
  • WaitPOST /containers/{id}/wait):阻塞直到容器停止,返回 {"StatusCode": <int>},若容器未运行则返回 500
  • RemoveDELETE /containers/{id}):查询参数 v(同时删除关联匿名卷)、force(强制停止并删除)、link(删除与容器的链接)。返回 204 成功,304 容器不存在,409 冲突(正在运行),404 未找到。

3.4 输出与状态读取端点

  • Get container logsGET /containers/{id}/logs):查询参数 stdoutstderr(必须至少选其一)、stdintimestamps(每条消息带 RFC3339Nano 时间戳)、since(Unix 秒,只看其后的日志)、follow(持续推送)、tailall 或行数)。注意:对于 TTY 容器(Tty=true),stdout 与 stderr 会被混流,stdout/stderr 参数须同时设置且值相同,否则返回 400
  • List processesGET /containers/{id}/top):查询参数 ps_args 透传给 ps 命令;响应包含 Titles(ps 列标题)与 Processes(二维数组)。
  • Inspect changes on a container's filesystemGET /containers/{id}/changes):返回文件系统变更数组,每项形如 {"Path": "/tmp", "Kind": 1}Kind 为 0(未变更)、1(修改)、2(添加)、3(删除)。
  • Export a containerGET /containers/{id}/export):以流式 tar 返回容器文件系统,响应头带 Content-Type: application/x-tar
  • Get container statsGET /containers/{id}/stats):查询参数 stream 控制是否持续推送;响应为 JSON 对象流,核心字段包括 cpu_statsprecpu_statsmemory_statsnetworks 等。

3.5 文件传输:archive 三端点

v1.20 提供了基于 tar 的容器文件访问能力:

  1. Retrieving information about files/foldersHEAD /containers/{id}/archive?path=...,响应头 X-Docker-Container-Path-Stat 为 base64 编码的 JSON,含 NameSizeModeModifiedTime 等字段,用于在传输前探测路径。
  2. Get an archive of a filesystem resourceGET /containers/{id}/archive?path=...,以 application/x-tar 流返回文件或目录归档;404 表示路径不存在。
  3. Extract an archive to a directory in a containerPUT /containers/{id}/archive?path=...,请求体为 tar 流,配合查询参数 noOverwriteDirMode 等控制解包行为;400(参数非法)、404(路径不存在)、500(写失败)。

这套端点正是 docker cp 命令的底层实现。

3.6 Attach 与 WebSocket 变体

  • AttachPOST /containers/{id}/attach):查询参数 stream(合并并流式返回 stdout/stderr)、logs(是否先回放历史日志)。如第 1 节所述,该端点会劫持 HTTP 连接建立多路复用流。
  • Attach (websocket)GET /containers/{id}/attach/ws):通过 WebSocket 提供等价的 attach 能力,适合浏览器类客户端。这是 v1.20 引入的能力之一。

4. 镜像端点详解(2.2 Images)

4.1 构建镜像:POST /build

构建端点的输入是一个 tar 构建上下文Content-Type: application/x-tar),文档给出的示例:

POST /v1.20/build HTTP/1.1
Content-Type: application/x-tar

{{ TAR STREAM }}

响应是 JSON 消息流,逐条输出构建进度与错误:

HTTP/1.1 200 OK
Content-Type: application/json

{"stream": "Step 1/5..."}
{"stream": "..."}
{"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}}

文档明确了约束与行为:

  • 输入 tar 支持 identity(不压缩)、gzipbzip2xz 四种压缩;
  • 归档内必须包含构建指令文件(通常位于根目录、名为 Dockerfile),可用 dockerfile 参数指定其他路径;
  • 归档中的其他文件构成构建上下文(对应 Dockerfile 中 ADD/COPY 可引用的文件);
  • 守护进程在开始前对 Dockerfile 做预校验,语法错误直接报错;之后逐条执行指令直至输出新镜像 ID;
  • 客户端断开连接即取消构建(quit 或被 kill)。

查询参数全集(v1.20 版):

参数 说明
dockerfile 构建上下文中 Dockerfile 的路径;若指定 remote 且其指向外部 Dockerfile,则被忽略
t 镜像 name:tag 命名;省略 tag 时默认 latest
remote Git 仓库 URI 或 HTTP(S) 上下文 URI;指向单个文本文件时其内容作为 Dockerfile;指向 tarball 时由守护进程下载并用作构建上下文
q 抑制冗长构建输出
nocache 构建时不使用缓存
pull 即使本地存在旧镜像也尝试拉取
rm 构建成功后删除中间容器(默认行为)
forcerm 始终删除中间容器(包含 rm 的语义)
memory / memswap 构建内存限制;memswap-1 表示不限交换
cpushares CPU 相对权重
cpusetcpus 允许执行的 CPU(如 0-30,1
cpuperiod CPU 周期长度(微秒)
cpuquota 每个 CPU 周期内可获得的微秒数

请求头中除 Content-Type 外,还有一个重要头 X-Registry-Config:base64-url-safe 编码的注册表鉴权配置 JSON,将注册表主机名映射到 username/password 对。文档特别指出:由于历史原因,官方 Docker 托管注册表必须以 https://index.docker.io/v1/ 的形式指定,尽管 Docker 会优先使用 v2 注册表 API。状态码:200 无错误、500 服务端错误。

该端点在当前守护进程中由 daemon/server/router/build/build.go 注册,POST /build 路由对应的后端已演进为 BuildKit 驱动的构建,但请求/响应协议(tar 上下文 + JSON 消息流)与本文档描述保持兼容。

4.2 其余镜像端点

  • List ImagesGET /images/json):查询参数 filters(JSON 编码过滤器,支持 dangling=truebeforereference 等);返回含 IdRepoTagsParentIdSizeVirtualSizeSharedSizeCreatedContainers 等字段的数组。
  • Create an imagePOST /images/create):查询参数 fromImage(从已有镜像创建,可与 repo/tag 组合打标签)、fromSrc(从指定 URL 的 tarball 导入);fromImagefromSrc 二选一必选;响应为 JSON 消息流,私有仓库拉取需要鉴权头。
  • Inspect an imageGET /images/{name}/json):返回完整镜像元数据(架构、配置、层信息、大小等)。
  • Get the history of an imageGET /images/{name}/history):按时间倒序返回每层的创建指令(CreatedBy)、创建时间、大小与评论。
  • Push an imagePOST /images/{name}/push):查询参数 tag 指定推送的 tag,请求头携带 X-Registry-Auth(base64 编码的鉴权 JSON);200 成功,404 镜像/仓库不存在,500 服务端错误。
  • Tag an imagePOST /images/{name}/tag):查询参数 repotag201 打标签成功,404 源镜像不存在,409 标签冲突。
  • Remove an imageDELETE /images/{name}):查询参数 force(强制删除,包括被引用的镜像)、noPrune(不删除父层);200 返回 {"Untagged": ...}{"Deleted": ...}404 未找到,409 冲突。
  • Search imagesGET /images/search):查询参数 term 必填,另可选 no-trunc(不截断描述)、filters;返回注册表搜索结果(namedescriptionstar_countis_officialis_automated 等字段)。

5. 杂项端点(2.3 Misc)

  • Check auth configurationPOST /auth):请求体为 JSON 的鉴权信息(usernamepasswordemailserveraddress),用于验证而非存储;200 验证通过,500 注册表无法访问。
  • Display system-wide informationGET /info):返回守护进程运行环境信息,字段包括 IDContainersImagesDriverMemoryLimitSwarm 等,是运维排障的常用入口。
  • Show the docker version informationGET /version):返回 VersionApiVersion(守护进程支持的最高 API 版本)、GoVersionGitCommitOs/Arch 等字段。这是客户端做版本协商的实际信息来源。
  • Ping the docker serverGET /_ping):返回 200 OKOK 体;若以 HEAD 请求(HTTP/1.0)访问,仅返回 200。这是最轻量的连通性/健康检查端点。
  • Create a new image from a container's changesPOST /commit):查询参数 container(必填)、repo/tagmessage(提交注释)、author(作者);请求体可携带与 create 类似的配置覆盖;201 成功并返回 {"Id": "..."}
  • Monitor Docker's eventsGET /events):长连接流式推送,查询参数 since/until(时间窗)、filters(按 eventcontainerimage 等过滤);事件对象含 TypeActionActortime 字段。与 attach/pull 类似,它依赖劫持连接保持流式输出。
  • Get a tarball containing all images in a repositoryGET /images/{name}/get)与 Get a tarball containing all imagesGET /images/get):以 tar 流导出镜像(后者可配 ?images= 列表),是 docker save 的底层。
  • Load a tarballPOST /images/load):上传 tar 流加载镜像与标签,是 docker load 的底层。文档附有 “Image tarball format” 小节说明 tar 内部结构(每个镜像目录含 manifest.jsonrepositories 与层文件)。
  • Exec 系列
    • Exec CreatePOST /containers/{id}/exec):请求体描述执行环境(AttachStdout/AttachStderrTtyCmdEnvWorkingDir 等),返回 201{"Id": "exec-id"}
    • Exec StartPOST /exec/{id}/start):请求体为 Detach/Tty 两字段;注意 v1.20 文档中该端点使用 {"Detach": bool, "Tty": bool} 结构,且若 exec 创建时已 attach 输出流,start 请求会劫持连接200 表示进程退出、304 表示容器未运行(HTTP/1.0 客户端场景);
    • Exec ResizePOST /exec/{id}/resize):查询参数 hw 调整终端尺寸,201 成功;
    • Exec InspectGET /exec/{id}/json):返回 exec 实例的完整状态(ExitCodeRunningOpenStdin 等)。

6. 深入理解(Going further)

v1.20 文档第 3 章给出了三个进阶主题,是理解 Engine API 行为的关键:

6.1 docker run 的内部调用链

“Inside docker run” 一节说明:docker run 并非单一 API 调用,而是守护进程侧组合了 create(解析配置并创建容器对象)、start(启动容器进程)、attach(可选,透传 I/O)等端点的效果。理解了这一点,就能解释为什么 docker run 的超时、日志、退出码行为需要分别对照 start/attach/wait 三个端点的语义。

6.2 Hijacking(连接劫持)

“Hijacking” 小节解释:对于 attachpullbuildevents 等端点,响应完成后连接不会关闭,而是转为双向多路复用通道,承载 stdout/stderr/stdin 流。客户端 SDK 必须实现对应的帧协议(例如 docker/cli 中 stdcopy 的 8 字节帧头格式)才能正确解码。仓库内 api/pkg/stdcopy 即实现了这一流解码逻辑,可作为协议细节的参考实现。

6.3 CORS 请求

“CORS Requests” 小节说明:Engine API 允许来自任意来源的跨域请求(守护进程默认信任本地 socket 上的调用方),因此暴露到 TCP 时必须依赖 TLS 或防火墙做访问控制,这也是文档反复强调的安全边界。

7. 实践要点小结

  1. 版本前缀是硬契约:客户端应显式使用 /v1.NN/... 前缀锁定语义;从 daemon/config/config.go 看,当前守护进程支持范围为 1.24~1.56(实际默认下限 1.40),v1.20 请求会被 400 拒绝daemon/server/server.go 还专门为低于 1.24 的版本返回纯文本错误以照顾旧客户端。
  2. 写请求必须带 Content-Length,且 POST /containers/create 等端点要求 JSON 请求体;构建端点要求 application/x-tar
  3. 流式端点(attach、build、events、stats、logs)依赖连接劫持,客户端需要处理“无 Content-Length 的长响应 + 帧协议解码”;api/pkg/stdcopy 提供了 stdcopy 解码参考。
  4. 端点与源码一一对应:容器路由见 daemon/server/router/container/container.go,镜像路由见 daemon/server/router/image/image.gorouter.WithMinimumAPIVersion("1.25") 这类注解展示了 Moby 如何按 API 版本增量开放新端点——这也解释了为什么仓库会为 v1.20 这样的历史版本保留完整参考文档:它是理解各版本端点差异与参数演进的基线。
登录后查看全文
热门项目推荐
相关项目推荐