首页
/ Moby Remote API v1.15 全解:容器、镜像、Exec 端点与 Hijack 流协议详解

Moby Remote API v1.15 全解:容器、镜像、Exec 端点与 Hijack 流协议详解

2026-09-06 11:43:09作者:邬祺芯Juliet

本文基于 Moby 仓库中的 Remote API v1.15 规范文档,系统梳理该版本 Engine Remote API 的完整端点体系:容器生命周期管理、镜像拉取/推送/导出、构建、事件监听与 Exec 执行,以及 attach 场景下基于 8 字节头帧的 stdout/stderr 多路复用流协议。读完本文,你能够直接使用 curl 或自研客户端对接 Docker Engine 的 v1.15 HTTP API,理解每个端点的请求参数、响应格式与状态码,并掌握底层调用链(如 docker run 背后的 API 组合)。

1. 总览:v1.15 时代 Remote API 的设计基调

v1.15 文档开篇明确了 Remote API 的三条基本设定,这也是理解该版本一切端点行为的前提:

  • Remote API 已取代旧的 rcli 客户端协议:所有与 Engine 的交互统一走 HTTP,不再依赖私有 RPC 协议;
  • 默认监听 Unix Socket:daemon 默认监听 unix:///var/run/docker.sock,也可以通过绑定参数把 Docker 挂到另一个 host/port 或另一个 Unix socket 上(即后来 dockerd -H 参数所表达的能力);
  • REST 为主,hijack 为辅:API 大体遵循 REST 风格,但 attachpull 等需要双向流式传输的命令会劫持(hijack)HTTP 连接,把 STDINSTDOUTSTDERR 直接跑在同一条连接上。

这一设计区分对客户端实现影响很大:普通端点可以按标准 REST 方式解析 JSON 响应;而流式端点的响应体是自定义二进制帧格式(见第 5 节),必须按协议解析。Moby 仓库中的 api/pkg/stdcopy 即为这类多路复用流的 Go 侧实现支撑,与文档中描述的帧格式相对应。

适用前提说明:本文所有端点行为、状态码与字段均以 api/docs/v1.15.md 的记载为准,属于历史版本(v1.15 期)的 API 语义;当前仓库主线已演进到 v1.49 等更新版本,字段结构(如日志的 JSON 流、inspect 输出)有变化。若对接现代 daemon,请以对应版本的 API 文档为准。

2. 容器端点(Containers)

容器是 v1.15 API 的绝对主体,覆盖“列表 → 创建 → 检视 → 生命周期 → 流式接入 → 删除”的完整闭环。

2.1 列出容器:GET /containers/json

示例请求(通过 allbeforesize 组合过滤并附带体积信息):

GET /containers/json?all=1&before=8dfafdbc3a40&size=1 HTTP/1.1

响应为 JSON 数组,每个元素的关键字段:

字段 含义
Id 容器短 ID(如 8dfafdbc3a40
Names 名称列表(带 / 前缀,如 ["/boring_feynman"]
Image 镜像引用,如 ubuntu:latest
Command 命令行的简短描述
Created 创建时间(Unix 秒)
Status 状态描述,如 Exit 0
Ports 端口映射,元素形如 {"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}
SizeRw / SizeRootFs 读写层 / 根文件系统大小(仅在 size=1 时填充)

查询参数:

  • all1/True/true0/False/false,是否显示全部容器。默认只显示运行中的容器(默认 false);
  • limit – 只显示最近创建的 limit 个容器(包含非运行态);
  • since – 只显示该 Id 之后创建的容器(包含非运行态);
  • before – 只显示该 Id 之前创建的容器(包含非运行态);
  • size – 是否在结果中携带容器大小;
  • filters – JSON 编码的过滤器(map[string][]string)。v1.15 支持的过滤器:
    • exited=<int>:退出码为 <int> 的容器;
    • status=(restarting|running|paused|exited):按状态过滤。

状态码:200 无错误;400 参数非法;500 服务器错误。

2.2 创建容器:POST /containers/create

这是 v1.15 中参数最重的端点,请求体同时携带容器配置HostConfig(主机侧配置)。文档给出的完整示例:

POST /containers/create HTTP/1.1
Content-Type: application/json

{
     "Hostname": "",
     "Domainname": "",
     "User": "",
     "Memory": 0,
     "MemorySwap": 0,
     "CpuShares": 512,
     "Cpuset": "0,1",
     "AttachStdin": false,
     "AttachStdout": true,
     "AttachStderr": true,
     "Tty": false,
     "OpenStdin": false,
     "StdinOnce": false,
     "Env": [
             "FOO=bar",
             "BAZ=quux"
     ],
     "Cmd": [
             "date"
     ],
     "Entrypoint": "",
     "Image": "ubuntu",
     "Volumes": {
             "/tmp": {}
     },
     "WorkingDir": "",
     "NetworkDisabled": false,
     "MacAddress": "12:34:56:78:9a:bc",
     "ExposedPorts": {
             "22/tcp": {}
     },
     "SecurityOpt": [],
     "HostConfig": {
       "Binds": ["/tmp:/tmp"],
       "Links": ["redis3:redis"],
       "LxcConf": {"lxc.utsname":"docker"},
       "PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
       "PublishAllPorts": false,
       "Privileged": false,
       "Dns": ["8.8.8.8"],
       "DnsSearch": [""],
       "ExtraHosts": null,
       "VolumesFrom": ["parent", "other:ro"],
       "CapAdd": ["NET_ADMIN"],
       "CapDrop": ["MKNOD"],
       "RestartPolicy": { "Name": "", "MaximumRetryCount": 0 },
       "NetworkMode": "bridge",
       "Devices": []
    }
}

成功响应(注意 201 Created 返回的是完整容器 Id 与告警列表):

HTTP/1.1 201 Created
Content-Type: application/json

{
     "Id": "f91ddc4b01e079c4481a8340bbbeca4dbd33d6e4a10662e499f8eacbb5bf252b"
     "Warnings": []
}

JSON 参数逐项说明(容器配置部分):

  • Hostname – 容器主机名;
  • Domainname – 容器域名;
  • User – 容器内运行用户;
  • Memory – 内存限制(字节);
  • MemorySwap – 内存 + swap 总限制,-1 表示 swap 无限;
  • CpuShares – 相对 CPU 权重(与其他容器相比的相对权重);
  • CpuSet – 使用的 cgroups cpuset;
  • AttachStdin / AttachStdout / AttachStderr – 是否附着到对应标准流;
  • Tty – 是否把标准流挂到 tty(含未关闭的 stdin);
  • OpenStdin – 是否打开 stdin;
  • StdinOnce – 第一个附着客户端断开后关闭 stdin;
  • Env["VAR=value", "VAR2=value2"] 形式的环境变量列表;
  • Cmd – 要执行的命令(字符串或字符串数组);
  • Entrypoint – 容器入口点(字符串或数组);
  • Image – 所用镜像名;
  • Volumes – 挂载点路径到空对象的映射;
  • WorkingDir – 工作目录;
  • NetworkDisabledtrue 时禁用容器网络;
  • MacAddress – 指定 MAC 地址;
  • ExposedPorts – 端口到空对象的映射,形如 "22/tcp": {}
  • SecurityOpt – 为 MLS(如 SELinux)自定义标签的字符串列表。

HostConfig 子参数(决定容器与宿主机的关系):

  • Binds – 卷绑定列表,元素格式为 container_path(新建卷)、host_path:container_path(绑定挂载)或 host_path:container_path:ro(容器内只读);
  • Links – 链接列表,元素形如 container_name:alias
  • LxcConf – LXC 专属配置,仅在使用 lxc 执行驱动时生效;
  • PortBindings – 容器暴露端口到宿主端口的映射,形如 { "<port>/<protocol>": [{ "HostPort": "<port>" }] }注意 port 是字符串而非整数
  • PublishAllPorts – 为所有暴露端口随机分配宿主端口;
  • Privileged – 给予容器对宿主机的完全访问;
  • Dns / DnsSearch – DNS 服务器 / 搜索域列表;
  • ExtraHosts – 追加到容器 /etc/hosts["hostname:IP"] 映射;
  • VolumesFrom – 从其他容器继承卷,形如 <container name>[:<ro|rw>]
  • CapAdd / CapDrop – 增删内核 capabilities;
  • RestartPolicy – 退出后的重启策略:Name"always"(总是重启)或 "on-failure"(退出码非零才重启);用 on-failure 时由 MaximumRetryCount 控制重试次数;默认不重启。为防止重启风暴,每次重启前会加入倍增延迟(从 100ms 起步、逐次翻倍);
  • NetworkMode – 网络模式,支持 bridgehostnonecontainer:<name|id>
  • Devices – 设备列表,元素形如 { "PathOnHost": "/dev/deviceName", "PathInContainer": "/dev/deviceName", "CgroupPermissions": "mrw"}

查询参数:

  • name – 给容器指定名称,须匹配 /?[a-zA-Z0-9_-]+

状态码:201 无错误;404 无此容器;406 无法 attach(容器未运行);500 服务器错误。

2.3 检视容器:GET /containers/(id or name)/json

返回容器的低层信息,包括 Config(创建时配置)、State(运行态)、Image(完整镜像 Id)、NetworkSettingsHostConfig 等。v1.15 响应示例(节选):

{
     "Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2",
     "Created": "2013-05-07T14:51:42.041847+02:00",
     "Path": "date",
     "Args": [],
     "Config": {
             "Hostname": "4fa6e0f0c678",
             "User": "",
             "Memory": 0,
             "MemorySwap": 0,
             "AttachStdin": false,
             "AttachStdout": true,
             "AttachStderr": true,
             "Tty": false,
             "OpenStdin": false,
             "StdinOnce": false,
             "Env": null,
             "Cmd": ["date"],
             "Image": "ubuntu",
             "Volumes": {},
             "WorkingDir": ""
     },
     "State": {
             "Running": false,
             "Pid": 0,
             "ExitCode": 0,
             "StartedAt": "2013-05-07T14:51:42.087658+02:01360",
             "Ghost": false
     },
     "Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
     "NetworkSettings": {
             "IpAddress": "",
             "IpPrefixLen": 0,
             "Gateway": "",
             "Bridge": "",
             "PortMapping": null
     },
     "HostConfig": {
         "Privileged": false,
         "PortBindings": {
            "80/tcp": [{ "HostIp": "0.0.0.0", "HostPort": "49153" }]
         },
         "Links": ["/name:alias"],
         "PublishAllPorts": false,
         "CapAdd": ["NET_ADMIN"],
         "CapDrop": ["MKNOD"]
     }
}

可以看到该版本的 inspect 输出里还保留着 Ghost 这类早期字段——这是研究 API 演化(对照 CHANGELOG)的典型样本。状态码:200 / 404 / 500

2.4 容器内进程、日志与文件系统

列出进程 GET /containers/(id or name)/top:在 Unix 系统上通过执行 ps 实现,Windows 不支持。查询参数 ps_args 指定 ps 参数(如 aux),默认 -ef。响应为 Titles(表头)+ Processes(行数组)结构:

GET /containers/4fa6e0f0c678/top?ps_args=aux HTTP/1.1
{
  "Titles" : ["USER","PID","%CPU","%MEM","VSZ","RSS","TTY","STAT","START","TIME","COMMAND"],
  "Processes" : [
    ["root","13642","0.0","0.1","18172","3184","pts/0","Ss","17:03","0:00","/bin/bash"],
    ["root","13895","0.0","0.0","4348","692","pts/0","S+","17:15","0:00","sleep 10"]
  ]
}

获取日志 GET /containers/(id or name)/logs,响应 Content-Type 为 application/vnd.docker.raw-stream

GET /containers/4fa6e0f0c678/logs?stderr=1&stdout=1&timestamps=1&follow=1&tail=10 HTTP/1.1

查询参数:follow(是否流式返回,默认 false)、stdout / stderr(分别显示对应流,默认 false)、timestamps(每行打印时间戳,默认 false)、tail(输出末尾 all<number> 行,默认 all)。状态码:200 / 404 / 500

检视文件系统变更 GET /containers/(id or name)/changes:返回 Path + Kind 数组,Kind 为数字枚举(0/1 分别表示不同类型变更):

[
    { "Path": "/dev", "Kind": 0 },
    { "Path": "/dev/kmsg", "Kind": 1 },
    { "Path": "/test", "Kind": 1 }
]

导出容器 GET /containers/(id or name)/export:以 application/octet-stream 返回容器的 tar 流

调整 TTY 尺寸 GET /containers/(id or name)/resize?h=<height>&w=<width>:如 ?h=40&w=80,成功返回 200 且 Content-Length 为 0;500 表示坏文件描述符。

2.5 生命周期操作

以下端点都是“动作型”端点,成功后统一返回 204 No Content

端点 作用 关键查询参数 特有状态码
POST /containers/(id)/start 启动容器 无(v1.15 允许在 body 携带与创建时相同的 HostConfig 字段做启动期修订) 304 已在运行
POST /containers/(id)/stop 停止容器 t – 强制 kill 前等待的秒数 304 已停止
POST /containers/(id)/restart 重启容器 t – kill 前等待秒数
POST /containers/(id)/kill 杀死容器 signal – 发送的信号(整数或 "SIGINT" 等);不设置时按 SIGKILL 处理并等待容器退出
POST /containers/(id)/pause 暂停容器
POST /containers/(id)/unpause 恢复容器
POST /containers/(id)/wait 阻塞至容器停止并返回退出码 见下

wait 的响应是一个 JSON 对象 {"StatusCode": 0},这是脚本化场景里拿退出码的标准方式。所有端点均共享 404(无此容器)与 500(服务器错误);start 端点文档还列出:在启动时 body 中可携带 BindsLinksPortBindingsPrivilegedDnsVolumesFromCapAddCapDropRestartPolicyNetworkModeDevices 等字段(语义与创建时 HostConfig 一致),用于在启动阶段再修订一次主机侧配置。

2.6 等待与删除

删除容器 DELETE /containers/(id or name),查询参数:

  • v – 是否同时删除关联卷(默认 false);
  • force – 先 kill 再删除(默认 false)。

状态码:204 无错误、400 参数非法、404 无此容器、500 服务器错误。

从容器拷贝文件 POST /containers/(id or name)/copy,请求体指定资源路径,响应为 tar 流:

POST /containers/4fa6e0f0c678/copy HTTP/1.1
Content-Type: application/json

{
     "Resource": "test.txt"
}
HTTP/1.1 200 OK
Content-Type: application/x-tar

{{ TAR STREAM }}

3. 流式接入:attach 与多路复用协议(重点)

attach 是 v1.15 中最需要客户端认真实现的端点。

3.1 POST /containers/(id or name)/attach

POST /containers/16253994b7c4/attach?logs=1&stream=0&stdout=1 HTTP/1.1

查询参数(均为 1/True/true0/False/false,默认 false):

  • logs – 是否返回历史日志;
  • stream – 是否返回实时流;
  • stdinstream=true 时是否接入 stdin;
  • stdout / stderrlogs=true 时返回对应日志;stream=true 时接入对应流。

状态码:200 / 400(参数非法)/ 404 / 500

3.2 帧格式:Header + Payload

文档对流的二进制格式有精确定义,这是客户端实现的关键:

  • 若创建容器时启用了 Tty:流是进程 PTY 与客户端 stdin 的原始数据,无帧结构,直接读即可;
  • 未启用 Tty:stdout 与 stderr 被多路复用到同一条流上,每一帧由 Header + Payload 组成。

Header 共 8 字节,Go 伪码表示为:

header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
  • 第 1 字节 STREAM_TYPE0 = stdin(写往 stdout 侧)、1 = stdout、2 = stderr;
  • 第 2–4 字节固定为 0;
  • 最后 4 字节 SIZE1..SIZE4 为**大端(big endian)**编码的 uint32 帧载荷长度;
  • Payload 紧随其后,为原始流数据。

文档给出的最简实现步骤:

  1. 读 8 字节头;
  2. 按第 1 字节选择输出到 stdout 或 stderr;
  3. 从最后 4 字节取出帧大小;
  4. 读取该大小的数据并输出到正确的一路;
  5. 回到第 1 步循环。

在 Moby 仓库中,这一帧协议的 Go 侧读写实现集中在 api/pkg/stdcopy(从源码结构看,stdcopy 包即围绕这种“带 8 字节头的 stdio 多路复用”提供读写工具),自研客户端可直接参考其语义。

3.3 WebSocket 变体:GET /containers/(id or name)/attach/ws

GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1

按 RFC 6455 完成 WebSocket 握手,随后在同一连接上传输相同的流数据。查询参数、状态码与 HTTP 版 attach 完全一致。对于浏览器端或无法处理裸 TCP 流的场景,这是 v1.15 提供的接入通道。

3.4 POST /containers/(id or name)/wait

阻塞直到容器停止,返回 {"StatusCode": 0}200);404500 同上。与 attach 的区别在于:wait 不传任何流,只取退出码,适合编排系统做生命周期收尾判断。

4. 镜像端点(Images)

4.1 列出镜像:GET /images/json

GET /images/json?all=0 HTTP/1.1

响应示例:

[
  {
     "RepoTags": ["ubuntu:12.04", "ubuntu:precise", "ubuntu:latest"],
     "Id": "8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c",
     "Created": 1365714795,
     "Size": 131506275,
     "VirtualSize": 131506275
  },
  {
     "RepoTags": ["ubuntu:12.10", "ubuntu:quantal"],
     "ParentId": "27cf784147099545",
     "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
     "Created": 1364102658,
     "Size": 24653,
     "VirtualSize": 180116135
  }
]

注意 Size(本层增量)与 VirtualSize(含父层的总大小)的区分——这是分层存储模型在 API 层的直接体现。

查询参数:all(默认 false,是否包含中间层/未标记镜像)、filters(JSON 编码,v1.15 可用 dangling=true 过滤悬空镜像)、filter(按名称过滤)。

4.2 创建(拉取/导入)镜像:POST /images/create

该端点一身二职:从 registry 拉取从源导入

POST /images/create?fromImage=ubuntu HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{"status": "Pulling..."}
{"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}}
{"error": "Invalid..."}
...

响应体是逐行 JSON(JSON lines)的进度流status 行推进进度,error 行报告失败——客户端需逐行解析而非等待整体响应。

查询参数:

  • fromImage – 要拉取的镜像名;
  • fromSrc – 导入源,可为 URL 或 -(从请求体读取镜像内容);
  • repo / tag – 仓库与标签。

请求头:X-Registry-Auth – base64 编码的 AuthConfig 对象,用于私有仓库认证。状态码:200 / 500

4.3 检视与历史

GET /images/(name)/json 返回镜像低层信息,含 ContainerConfig(制作该层时的容器配置)、IdParentSizeCreated 等;状态码 200 / 404(无此镜像)/ 500

GET /images/(name)/history 返回镜像历史链(每层的 IdCreatedCreatedBy):

[
     { "Id": "b750fe79269d", "Created": 1364102658, "CreatedBy": "/bin/bash" },
     { "Id": "27cf78414709", "Created": 1364068391, "CreatedBy": "" }
]

4.4 推送、打标签、删除与搜索

推送 POST /images/(name)/push(可选查询参数 tag,请求头 X-Registry-Auth)。响应同样是 JSON lines 进度流:

{"status": "Pushing..."}
{"status": "Pushing", "progress": "1/? (n/a)", "progressDetail": {"current": 1}}

推送到私有 registry 时,镜像必须先 tag 成引用该 registry 主机名与端口的仓库名,URL 中使用该仓库名(与 CLI 流程一致):

POST /images/registry.acme.com:5000/test/push HTTP/1.1

状态码:200 / 404 / 500

打标签 POST /images/(name)/tag,查询参数:repo(目标仓库)、force(默认 false)、tag(新标签名)。成功返回 201;另有 400404409(冲突)、500

删除 DELETE /images/(name),查询参数 forcenoprune(均默认 false)。响应是逐条操作结果数组——先 untag 再逐层删除:

[
 {"Untagged": "3e2f21a89f"},
 {"Deleted": "3e2f21a89f"},
 {"Deleted": "53b4f83ac9"}
]

状态码:200 / 404 / 409 / 500

搜索 GET /images/search?term=sshd:在 Docker Hub 上搜索。v1.15 文档特别注明:响应键名自 v1.6 起改变,改为直接透传 registry 服务器返回给 daemon 的 JSON。响应字段为 descriptionis_officialis_automatednamestar_count

4.5 镜像的导出与加载(Save / Load)

导出单仓库 GET /images/(name)/get:返回包含该仓库所有镜像与元数据的 tarball(application/x-tar 二进制流)。若 name 是具体名+tag(如 ubuntu:latest),只返回该镜像及其父层;若是镜像 ID,同样只返回该镜像及父层,但 tarball 中不含 repositories 文件(因为没有镜像名可引用)。

导出多仓库 GET /images/get?names=<urlencoded name>&names=...:对每个 names 参数按上述规则打包。

加载 POST /images/load:请求体为 tarball,把一组镜像与标签载入本地仓库,成功返回 200

镜像 tarball 格式(get/load 双方共同遵守的容器格式):

  • 每个镜像层一个目录(以长 ID 命名),内含三个文件:
    1. VERSION:文件格式版本(当时为 1.0);
    2. json:该层的详细信息(类似 docker inspect layer_id 的输出);
    3. layer.tar:该层的文件系统变更 tar 包。
  • layer.tar 内使用 aufs 风格的 .wh..wh.aufs 文件与目录来表达属性变更和删除(白名单/删除标记机制);
  • 若 tarball 定义了仓库,根目录还会有 repositories 文件,内容是把“仓库:tag”映射到层 ID 的 JSON,例如:
{"hello-world":
    {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"}
}

这套格式是后来 docker save/docker load 离线分发镜像的底层协议基础。

5. 构建、认证与系统级端点(Misc)

5.1 POST /build:从 tar 流构建镜像

POST /build HTTP/1.1

{{ TAR STREAM }}

请求体是一个 tar 归档(支持 identity/gzip/bzip2/xz 压缩),根目录必须包含名为 Dockerfile 的文件;归档中其他文件进入构建上下文,可被 ADD 指令引用。

响应为 JSON lines 流,逐行返回 stream 行与可能的 error/errorDetail 行:

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

查询参数:t(成功时应用于结果镜像的仓库名:tag)、remote(git 或 HTTP/HTTPS 构建源 URI)、q(静默冗长输出)、nocache(不用缓存)、rm(成功构建后删除中间容器,默认行为)、forcerm(总是删除中间容器,蕴含 rm)。

请求头:Content-type 应为 application/tarX-Registry-Config – base64 编码的 ConfigFile 对象。状态码:200 / 500

5.2 POST /auth:校验认证配置

请求体为 registry 认证四元组(username / password / email / serveraddress),daemon 用它向 registry 验证凭据有效性,成功返回 200(或 204),失败 500。这是 docker login 的 API 底座。

5.3 GET /info:系统级信息

响应包含守护进程的全局状态,v1.15 示例:

{
     "Containers": 11,
     "Images": 16,
     "Driver": "btrfs",
     "ExecutionDriver": "native-0.1",
     "KernelVersion": "3.12.0-1-amd64",
     "Debug": false,
     "NFd": 11,
     "NGoroutines": 21,
     "NEventsListener": 0,
     "InitPath": "/usr/bin/docker",
     "IndexServerAddress": ["https://index.docker.io/v1/"],
     "MemoryLimit": true,
     "SwapLimit": false,
     "IPv4Forwarding": true
}

字段覆盖:容器/镜像计数、存储驱动、内核版本、打开 fd 数、goroutine 数、事件监听器数、内存限制与 swap 限制是否可用、IPv4 转发状态等。监控面板与排障时这是首选端点。

5.4 GET /versionGET /_ping

GET /version 返回 daemon 的 API 版本与构建信息(ApiVersionVersionGitCommitGoVersion)——任何 API 客户端在开始工作前都应以它做能力协商GET /_ping 是存活探针,正常返回纯文本 OKContent-Type: text/plain)。

5.5 POST /commit:从容器变更创建镜像

POST /commit?container=44c004db4b17&comment=message&repo=myrepo HTTP/1.1
Content-Type: application/json
{ ... 新镜像的容器配置(Hostname、User、Memory、CpuShares、Env、Cmd、Volumes、WorkingDir、ExposedPorts 等) ... }

查询参数:container(源容器)、repotagcomment(提交说明)、author(作者,如 "John Hannibal Smith")。成功返回 201 Created 及新镜像 Id:{"Id": "596069db4bf5"}。状态码:201 / 404 / 500

5.6 GET /events:事件流

可流式实时订阅,也可用 since 时间戳轮询。v1.15 中容器会报告事件:

create, destroy, die, export, kill, pause, restart, start, stop, unpause

镜像会报告:

untag, delete

请求与响应示例:

GET /events?since=1374067924
{"status": "create", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924}
{"status": "start", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067924}
{"status": "stop", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067966}
{"status": "destroy", "id": "dfdf82bd3881","from": "ubuntu:latest", "time":1374067970}

查询参数:since / until(轮询用的时间戳)。状态码:200 / 500

6. Exec 系列端点

Exec 在 v1.15 中已拆成“创建 → 启动 →(可选)调整 TTY”三步,这是理解 docker exec 实现的关键。

6.1 Exec Create:POST /containers/(id or name)/exec

在运行中的容器内布置一个 exec 实例:

POST /containers/e90e34656806/exec HTTP/1.1
Content-Type: application/json

{
     "AttachStdin": false,
     "AttachStdout": true,
     "AttachStderr": true,
     "Tty": false,
     "Cmd": ["date"]
}
HTTP/1.1 201 Created
Content-Type: application/json

{ "Id": "f90e34656806" }

JSON 参数:AttachStdin / AttachStdout / AttachStderr(接入 exec 命令的对应流)、Tty(分配伪终端)、Cmd(命令,字符串或数组)。状态码:201 / 404

6.2 Exec Start:POST /exec/(id)/start

POST /exec/e90e34656806/start HTTP/1.1
Content-Type: application/json

{ "Detach": false, "Tty": false }

Detachtrue 时 API 在 exec 命令启动后即返回;否则建立交互式会话,响应为 application/vnd.docker.raw-stream{{ STREAM }}流的行为与 attach API 相同——即第 3.2 节的 8 字节头帧多路复用格式(Tty 开启时则为原始流)。状态码:200 / 404

6.3 Exec Resize:POST /exec/(id)/resize

调整 exec 会话的 tty 尺寸,查询参数 h(高度)/w(宽度);仅当 exec 创建与启动时指定了 tty 才有效。成功返回 201404 表示无此 exec 实例。

7. 组合视角:docker run 背后的 API 调用链

v1.15 文档专门用一节拆解了 docker run 命令行如何组合上述端点,这是把离散端点串成工作流的权威参考:

  1. Create the container——调用 POST /containers/create
  2. 若返回 404(镜像不存在):先尝试 POST /images/create 拉取,然后重试创建容器
  3. Start the container——调用 POST /containers/(id)/start
  4. 非分离模式POST /containers/(id)/attach,参数 logs=1&stream=1logs=1 保证拿到容器启动以来已有的 stdout/stderr,stream=1 保证接续实时流);
  5. 分离模式或仅接入了 stdin:打印容器 Id。

这一段说明了两件事:一是“create 失败→拉取→重试”这种幂等重试模式是官方客户端的标准容错路径;二是 attach 同时打开 logsstream 才能避免“启动瞬间的输出”丢失——自研编排工具复刻 docker run 语义时务必照此实现。

8. Hijacking 与 CORS

  • Hijacking:v1.15 的 /attach(及同协议的 exec start、logs follow 等)通过劫持同一 HTTP 连接来同时传输 stdin、stdout、stderr。文档明确提示“这一行为未来可能改变”,因此客户端实现时不应把 TCP 层细节当作长期契约,而应依赖帧协议(第 3.2 节)做解析。
  • CORS:允许跨域访问 Remote API 需在 daemon 模式启动时添加 --api-enable-cors 参数,例如:
$ docker -d -H="192.168.1.9:2375" --api-enable-cors

9. 小结

v1.15 版 Remote API 文档刻画了 Docker Engine 早期 HTTP 化阶段的完整面貌:容器、镜像两大资源域各 8~10 个端点,外加 build、auth、info、version、ping、commit、events、save/load 与 exec 三类支撑端点;技术特征上则是“REST + JSON lines 进度流 + 8 字节头帧的 hijack 二进制流”三种响应模式的组合。对接这一版本 API 时,重点在于三处:

  1. 状态码语义——304(already started/stopped)、404 触发拉取重试、406(impossible to attach)等细节决定客户端状态机怎么写;
  2. 流式协议——attach/exec start 的帧解析必须区分 Tty 开/关两种形态;
  3. 认证头——拉取与推送统一使用 X-Registry-Auth(base64 AuthConfig),构建使用 X-Registry-Config(base64 ConfigFile)。

如需进一步对照该版本与后续版本的差异,可查阅 api/docs/CHANGELOG.md 以及仓库中更高版本(如 v1.49)的 API 定义;流协议的 Go 实现可参考 api/pkg/stdcopy/stdcopy.go

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