首页
/ Moby Docker Remote API v1.12 参考指南:从容器端点到 Hijack 流协议的全景解析

Moby Docker Remote API v1.12 参考指南:从容器端点到 Hijack 流协议的全景解析

2026-09-06 20:31:04作者:鲍丁臣Ursa

本文基于 Moby 仓库中的 Remote API v1.12 文档,系统梳理该版本 API 的全部端点(容器、镜像、通用接口)、请求参数与状态码,并结合当前仓库源码深入讲解 Attach 流的多路复用帧协议、Hijack 传输机制以及 docker run 背后的真实调用链。读完本文,你将能够直接使用 HTTP 客户端调用 Docker 守护进程完成容器全生命周期管理,并能自行实现 attach 流的解复用解析。

1. API 概述:REST 与 Hijack 的混合模型

v1.12 是 Docker 早期 Remote API(取代了命令行客户端 rcli)中的一个里程碑版本,文档开篇明确说明三个基本事实:

  • Remote API 已经取代了 rcli,一切管理操作都通过 HTTP 接口完成;
  • 守护进程默认监听 unix:///var/run/docker.sock,也可以通过 -H 参数绑定到其他主机/端口或 Unix socket。当前仓库中,默认 socket 路径在 daemon/pkg/opts/hosts.go 中定义:DefaultUnixSocket = "/var/run/docker.sock"
  • API 整体倾向于 REST 风格,但对于 attachpull 这类复杂命令,HTTP 连接会被 hijack(劫持),在同一连接上双向传输 STDOUTSTDINSTDERR

这种"REST + 流劫持"的混合模型一直沿用至今:简单资源操作用标准 REST 语义(GET 查询、POST 动作、DELETE 删除、状态码表达结果),而需要长连接和双向通道的操作则绕过 HTTP 响应体语义,直接接管底层连接。

2. 容器(Containers)端点

以下端点在文档中按操作逐一给出。需要说明的是,当前仓库的路由注册见 daemon/server/router/container/container.go,其中路由已统一为 /containers/{name:.*}/... 的命名风格,且新增了 pruneresizeupdate、exec 系列等 v1.12 之后的能力;本文以 v1.12 文档为准讲解各端点的请求与响应。

2.1 列出容器:GET /containers/json

示例请求

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

示例响应

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

[
     {
             "Id": "8dfafdbc3a40",
             "Image": "ubuntu:latest",
             "Command": "echo 1",
             "Created": 1367854155,
             "Status": "Exit 0",
             "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}],
             "SizeRw": 12288,
             "SizeRootFs": 0
     },
     {
             "Id": "9cd87474be90",
             "Image": "ubuntu:latest",
             "Command": "echo 222222",
             "Created": 1367854155,
             "Status": "Exit 0",
             "Ports": [],
             "SizeRw": 12288,
             "SizeRootFs": 0
     },
     {
             "Id": "3176a2479c92",
             "Image": "ubuntu:latest",
             "Command": "echo 3333333333333333",
             "Created": 1367854154,
             "Status": "Exit 0",
             "Ports":[],
             "SizeRw":12288,
             "SizeRootFs":0
     },
     {
             "Id": "4cb07b47f9fb",
             "Image": "ubuntu:latest",
             "Command": "echo 444444444444444444444444444444444",
             "Created": 1367854152,
             "Status": "Exit 0",
             "Ports": [],
             "SizeRw": 12288,
             "SizeRootFs": 0
     }
]

查询参数

  • all1/True/true0/False/false,是否显示全部容器;默认只显示运行中的容器
  • limit – 只显示最近创建的 limit 个容器(含非运行状态)
  • since – 只显示该 Id 之后创建的容器(含非运行状态)
  • before – 只显示该 Id 之前创建的容器(含非运行状态)
  • size1/True/true0/False/false,是否附带容器大小
  • filters – JSON 编码的过滤条件(map[string][]string

状态码200 成功;400 参数错误;500 服务端错误。

2.2 创建容器:POST /containers/create

示例请求

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,
     "PortSpecs":null,
     "Tty":false,
     "OpenStdin":false,
     "StdinOnce":false,
     "Env":null,
     "Cmd":[
             "date"
     ],
     "Image":"ubuntu",
     "Volumes":{
             "/tmp": {}
     },
     "WorkingDir":"",
     "NetworkDisabled": false,
     "ExposedPorts":{
             "22/tcp": {}
     }
}

示例响应

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

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

JSON 参数config —— 容器的完整配置对象(即请求体)。

查询参数

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

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

从源码结构看,请求体中的 MemoryCpuSharesCpusetTtyAttachStdout 等字段与镜像配置(Config)中的字段同构,v1.12 的 inspect 响应(见 2.3)中也会原样回显,说明创建时提交的是"容器配置",而主机侧配置(binds、端口绑定等)在 v1.12 中还散落在 start 请求中(见 2.7),这是该版本 API 与后续版本最大的差异之一。

2.3 查看容器详情:GET /containers/(id)/json

示例请求

GET /containers/4fa6e0f0c678/json HTTP/1.1

示例响应(节选核心结构):

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

{
             "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,
                     "PortSpecs": null,
                     "Tty": false,
                     "OpenStdin": false,
                     "StdinOnce": false,
                     "Env": null,
                     "Cmd": [
                             "date"
                     ],
                     "Dns": null,
                     "Image": "ubuntu",
                     "Volumes": {},
                     "VolumesFrom": "",
                     "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
             },
             "SysInitPath": "/home/kitty/go/src/github.com/docker/docker/bin/docker",
             "ResolvConfPath": "/etc/resolv.conf",
             "Volumes": {},
             "HostConfig": {
                 "Binds": null,
                 "ContainerIDFile": "",
                 "LxcConf": [],
                 "Privileged": false,
                 "PortBindings": {
                    "80/tcp": [
                        {
                            "HostIp": "0.0.0.0",
                            "HostPort": "49153"
                        }
                    ]
                 },
                 "Links": null,
                 "PublishAllPorts": false
             }
}

状态码200 成功;404 无此容器;500 服务端错误。

注意响应区分了三个层次的配置:Config(容器配置,随镜像/创建参数走)、HostConfig(主机配置:BindsPortBindingsLxcConfPrivilegedLinksPublishAllPorts)以及运行时状态 State(含 RunningPidExitCodeGhost)。v1.12 的 Ghost 字段标识容器是否存在于文件系统但运行时已丢失,这在后续版本中被移除。

2.4 查看容器内进程:GET /containers/(id)/top

示例请求

GET /containers/4fa6e0f0c678/top HTTP/1.1

示例响应

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

{
     "Titles": [
             "USER",
             "PID",
             "%CPU",
             "%MEM",
             "VSZ",
             "RSS",
             "TTY",
             "STAT",
             "START",
             "TIME",
             "COMMAND"
             ],
     "Processes": [
             ["root","20147","0.0","0.1","18060","1864","pts/4","S","10:06","0:00","bash"],
             ["root","20271","0.0","0.0","4312","352","pts/4","S+","10:07","0:00","sleep","10"]
     ]
}

查询参数ps_args – 传给 ps 的参数(如 aux)。

状态码200 成功;404 无此容器;500 服务端错误。

2.5 获取容器日志:GET /containers/(id)/logs

示例请求

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

示例响应

HTTP/1.1 200 OK
Content-Type: application/vnd.docker.raw-stream

{{ STREAM }}

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

  • follow – 是否返回流式输出
  • stdout – 若 logs=true,是否返回 stdout 日志
  • stderr – 若 logs=true,是否返回 stderr 日志
  • timestamps – 若 logs=true,是否为每行日志打印时间戳

状态码200 成功;404 无此容器;500 服务端错误。

响应体不是 JSON,而是原始流。当容器创建时未启用 TTY,日志流同样是 2.8 节所述的多路复用帧格式,客户端需要按帧解析后才能分离出 stdout/stderr。

2.6 查看容器文件系统变更:GET /containers/(id)/changes

示例请求

GET /containers/4fa6e0f0c678/changes HTTP/1.1

示例响应

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

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

Kind 是整型枚举:0 表示修改(modify),1 表示新增(add)。当前仓库中该枚举在 api/types/container/change_types.go 中定义:ChangeModify ChangeType = 0ChangeAdd ChangeType = 1ChangeDelete ChangeType = 22 为后续版本新增的删除语义)。daemon 侧的处理入口在 daemon/changes.goContainerChanges 方法中,它先按名称定位容器,再委托给 image service 计算 diff;文档中的 Kind 数值即来源于此。

状态码200 成功;404 无此容器;500 服务端错误。

2.7 启动、停止、重启与终止容器

这四个端点构成容器的运行控制面,文档为每个端点都给出了完整的请求/响应示例。

启动容器 POST /containers/(id)/start(注意:v1.12 允许在启动请求体中携带 host 配置,这是与后续版本的显著差异):

POST /containers/(id)/start HTTP/1.1
Content-Type: application/json

{
     "Binds":["/tmp:/tmp"],
     "Links":["redis3:redis"],
     "LxcConf":[{"Key":"lxc.utsname","Value":"docker"}],
     "PortBindings":{ "22/tcp": [{ "HostPort": "11022" }] },
     "PublishAllPorts":false,
     "Privileged":false,
     "Dns": ["8.8.8.8"],
     "VolumesFrom": ["parent", "other:ro"]
}

响应为 HTTP/1.1 204 No Content。JSON 参数 hostConfig 为可选的容器主机配置。状态码:204 成功;404 无此容器;500 服务端错误。

停止容器 POST /containers/(id)/stop

POST /containers/e90e34656806/stop?t=5 HTTP/1.1

查询参数 t – 等待多少秒后强制 kill。响应 204 No Content;状态码 204 / 404 / 500

重启容器 POST /containers/(id)/restart

POST /containers/e90e34656806/restart?t=5 HTTP/1.1

查询参数 t 语义与 stop 相同;响应 204 No Content;状态码 204 / 404 / 500

终止容器 POST /containers/(id)/kill

POST /containers/e90e34656806/kill HTTP/1.1

查询参数 signal – 要发送的信号,可以是整数或 SIGINT 这类字符串;未指定时默认发送 SIGKILL,且调用会等待容器退出。响应 204 No Content;状态码 204 / 404 / 500

2.8 暂停与恢复容器

暂停 POST /containers/(id)/pause

POST /containers/e90e34656806/pause HTTP/1.1

恢复 POST /containers/(id)/unpause

POST /containers/e90e34656806/unpause HTTP/1.1

两者响应均为 204 No Content,状态码均为 204 / 404 / 500。这两个端点在 v1.12 是新增能力,对应文档 events 一节中列出的 pause/unpause 事件类型。

2.9 Attach 到容器:POST /containers/(id)/attach 与 WebSocket 变体

HTTP 劫持版本 POST /containers/(id)/attach

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

示例响应

HTTP/1.1 200 OK
Content-Type: application/vnd.docker.raw-stream

{{ STREAM }}

查询参数(默认均为 false):

  • logs – 是否回读历史日志
  • stream – 是否附加实时流
  • stdin – 若 stream=true,是否附加 stdin
  • stdout – 若 logs=true,返回 stdout 日志;若 stream=true,附加 stdout
  • stderr – 若 logs=true,返回 stderr 日志;若 stream=true,附加 stderr

状态码200 成功;400 参数错误;404 无此容器;500 服务端错误。

流格式细节(核心协议):创建容器时若启用 TTY,流是进程 PTY 的原始数据流(与客户端 stdin 直通);若未启用 TTY,流则是多路复用的,需要按帧分离 stdout 与 stderr。

帧 = 8 字节 Header + Payload

header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
  • STREAM_TYPE0 = stdin(读取时写到 stdout)、1 = stdout、2 = stderr
  • SIZE1~SIZE4:帧载荷长度,按 big endian 编码的 uint32,位于头部的最后 4 字节

文档给出的最小实现步骤:1) 读 8 字节;2) 按首字节选择 stdout/stderr;3) 从末 4 字节取出帧大小;4) 读取该数量的字节并输出到对应流;5) 回到第 1 步。

当前仓库中这套协议由 api/pkg/stdcopy/stdcopy.go 实现,与文档完全一致:常量 stdWriterPrefixLen = 8stdWriterFdIndex = 0stdWriterSizeIndex = 4StdCopy 函数循环读取完整头、按 buf[stdWriterFdIndex] 分流、用 binary.BigEndian.Uint32 解析帧长,再读取整帧写入目标流。值得注意的是,源码中还定义了文档未提及的 Systemerr StdType = 3 流:当读到该流时,StdCopy 不写入任何输出,而是把载荷作为 daemon 报错返回并终止流处理——这是守护进程在流中注入错误的私有扩展通道。

WebSocket 版本 GET /containers/(id)/attach/ws

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

按 RFC 6455 执行 WebSocket 握手后直接输出 {{ STREAM }};查询参数与状态码(200 / 400 / 404 / 500)与 HTTP 劫持版本相同。WebSocket 变体适合浏览器或不便处理连接劫持的客户端。

2.10 等待、删除与复制

等待容器退出 POST /containers/(id)/wait:阻塞直至容器 id 停止,然后返回退出码。

POST /containers/16253994b7c4/wait HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{"StatusCode": 0}

状态码:200 / 404 / 500

删除容器 DELETE /containers/(id)

DELETE /containers/16253994b7c4?v=1 HTTP/1.1

查询参数:v – 是否同时删除关联卷;force – 是否强制删除运行中的容器。响应 204 No Content;状态码 204 / 400 / 404 / 500

从容器复制文件 POST /containers/(id)/copy(请求体指定 Resource,响应为 tar 流):

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

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

{{ TAR STREAM }}

状态码:200 / 404 / 500

导出容器 GET /containers/(id)/export:请求示例 GET /containers/4fa6e0f0c678/export HTTP/1.1,响应为 Content-Type: application/octet-stream{{ TAR STREAM }};状态码 200 / 404 / 500

3. 镜像(Images)端点

3.1 列出镜像:GET /images/json

GET /images/json?all=0 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[
  {
     "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
  }
]

查询参数

  • all1/True/true0/False/false,默认 false
  • filters – JSON 编码的过滤条件,可用 dangling=true
  • filter – 仅返回指定名称的镜像

3.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 对象),用于向客户端报告拉取/导入进度。拉取私有仓库时可使用 X-Registry-Auth 头携带 base64 编码的 AuthConfig 对象。

查询参数

  • fromImage – 要拉取的镜像名
  • fromSrc – 导入源,- 表示 stdin
  • repo – 仓库名
  • tag – 标签
  • registry – 目标 registry

状态码200 成功;500 服务端错误。

3.3 查看镜像详情与历史

查看镜像 GET /images/(name)/json

GET /images/ubuntu/json HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

{
     "Created": "2013-03-23T22:24:18.818426-07:00",
     "Container": "3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0",
     "ContainerConfig":
             {
                     "Hostname": "",
                     "User": "",
                     "Memory": 0,
                     "MemorySwap": 0,
                     "AttachStdin": false,
                     "AttachStdout": false,
                     "AttachStderr": false,
                     "PortSpecs": null,
                     "Tty": true,
                     "OpenStdin": true,
                     "StdinOnce": false,
                     "Env": null,
                     "Cmd": ["/bin/bash"],
                     "Dns": null,
                     "Image": "ubuntu",
                     "Volumes": null,
                     "VolumesFrom": "",
                     "WorkingDir": ""
             },
     "Id": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
     "Parent": "27cf784147099545",
     "Size": 6824592
}

状态码:200 / 404 / 500

查看历史 GET /images/(name)/history

GET /images/ubuntu/history HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

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

状态码:200 / 404 / 500

3.4 推送、打标签与删除镜像

推送 POST /images/(name)/push

POST /images/test/push HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

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

推送私有 registry 上的镜像时,镜像必须已经 tag 到引用该 registry 主机名和端口的仓库名,然后 URL 中使用该仓库名,与 CLI 流程一致,例如:

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

查询参数tag – 要关联的标签(可选)。请求头X-Registry-Auth – base64 编码的 AuthConfig。状态码:200 / 404 / 500

打标签 POST /images/(name)/tag

POST /images/test/tag?repo=myrepo&force=0&tag=v42 HTTP/1.1

查询参数:repo – 目标仓库;force – 是否强制;tag – 新标签名。响应 201 OK;状态码 201 / 400 / 404 / 409(冲突)/ 500

删除 DELETE /images/(name)

DELETE /images/test HTTP/1.1
HTTP/1.1 200 OK
Content-type: application/json

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

查询参数:force – 强制删除;noprune – 不删除悬空父层。状态码:200 / 404 / 409 / 500

3.5 搜索镜像:GET /images/search

在 Docker Hub 上搜索镜像。文档特别注明:响应键名自 API v1.6 起有所变化,以对齐 registry 服务器返回的 JSON。

GET /images/search?term=sshd HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json

[
        {
            "description": "",
            "is_official": false,
            "is_automated": false,
            "name": "wma55/u1210sshd",
            "star_count": 0
        },
        {
            "description": "",
            "is_official": false,
            "is_automated": false,
            "name": "jdswinbank/sshd",
            "star_count": 0
        },
        {
            "description": "",
            "is_official": false,
            "is_automated": false,
            "name": "vgauthier/sshd",
            "star_count": 0
        }
...
]

查询参数term – 搜索词。状态码:200 / 500

4. 通用(Misc)端点

4.1 构建镜像:POST /build

构建上下文以 tar 流形式通过请求体上传:

POST /build HTTP/1.1

{{ TAR STREAM }}
HTTP/1.1 200 OK
Content-Type: application/json

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

约束:tar 流必须使用 identity(不压缩)、gzip、bzip2 或 xz 之一压缩;归档根部必须包含 Dockerfile 文件;归档中的其他文件会进入构建上下文(对应 ADD 指令的构建上下文)。

查询参数

  • t – 构建成功后应用到结果镜像的仓库名(可含标签)
  • remote – git 或 HTTP/HTTPS URI 构建源
  • q – 抑制冗长的构建输出
  • nocache – 构建时不使用缓存
  • rm – 构建成功后移除中间容器(默认行为)
  • forcerm – 总是移除中间容器(包含 rm 语义)

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

4.2 校验认证配置:POST /auth

POST /auth HTTP/1.1
Content-Type: application/json

{
     "username":" hannibal",
     "password: "xxxx",
     "email": "hannibal@a-team.com",
     "serveraddress": "https://index.docker.io/v1/"
}

成功时返回 HTTP/1.1 200 OK。状态码:200 / 204 / 500

4.3 系统信息与版本

系统信息 GET /info

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

{
     "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
}

状态码:200 / 500

版本信息 GET /version

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

{
     "ApiVersion": "1.12",
     "Version": "0.2.2",
     "GitCommit": "5a2a5cc+CHANGES",
     "GoVersion": "go1.0.3"
}

状态码:200 / 500

Ping GET /_ping:返回 HTTP/1.1 200 OKContent-Type: text/plain、正文 OK;状态码 200 / 500_ping 是客户端探测守护进程可用性的最轻端点,CLI 在执行大部分命令前都会先 ping 一次。

4.4 提交新镜像:POST /commit

POST /commit?container=44c004db4b17&comment=message&repo=myrepo 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,
     "PortSpecs": null,
     "Tty": false,
     "OpenStdin": false,
     "StdinOnce": false,
     "Env": null,
     "Cmd": [
             "date"
     ],
     "Volumes": {
             "/tmp": {}
     },
     "WorkingDir": "",
     "NetworkDisabled": false,
     "ExposedPorts": {
             "22/tcp": {}
     }
}
HTTP/1.1 201 Created
Content-Type: application/json

{"Id": "596069db4bf5"}

JSON 参数config – 容器配置。查询参数container – 源容器;repo – 仓库;tag – 标签;comment – 提交说明;author – 作者(如 "John Hannibal Smith hannibal@a-team.com")。状态码:201 / 404 / 500

4.5 监控事件:GET /events

可实时流式获取,也可用 since 轮询:

GET /events?since=1374067924
HTTP/1.1 200 OK
Content-Type: application/json

{"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}

容器会报告的事件:createdestroydieexportkillpauserestartstartstopunpause;镜像会报告:untagdelete

查询参数since – 轮询起始时间戳;until – 轮询截止时间戳。状态码:200 / 500

4.6 镜像 tar 包:保存与加载

导出仓库 GET /images/(name)/get:返回包含该仓库所有镜像与标签的 tar 包。

GET /images/ubuntu/get
HTTP/1.1 200 OK
Content-Type: application/x-tar

Binary data stream

加载 POST /images/load:请求体为 tar 包,响应 200 OK

镜像 tar 包格式:每个镜像层对应一个以其长 ID 命名的目录,目录内含三个文件:

  1. VERSION:文件格式版本,当前为 1.0
  2. json:该层的详细信息,类似 docker inspect layer_id 的输出
  3. layer.tar:包含该层文件系统变更的 tar 文件

layer.tar 中会包含 aufs 风格的 .wh..wh.aufs 文件与目录,用于记录属性变更和删除。若 tar 包定义了仓库,根目录还会有 repositories 文件,内容是"仓库/标签名 → 层 ID"的映射:

{"hello-world":
    {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"}
}

状态码(get/load 两个端点均为):200 / 500

5. 深入理解:docker run 的 API 调用序列

文档"Going further"一节给出了 docker run 命令在 v1.12 API 下的完整调用序列,这是理解 CLI 与 API 关系的关键:

  1. 创建容器(POST /containers/create);
  2. 若状态码为 404(镜像不存在):尝试拉取(POST /images/create),然后重试创建容器;
  3. 启动容器(POST /containers/(id)/start);
  4. 非分离模式下:附加到容器(POST /containers/(id)/attach,使用 logs=1 以拿到容器启动以来的 stdout/stderr,并设置 stream=1);
  5. 分离模式下或仅附加 stdin 时:显示容器 ID。

也就是说,一条 docker run 最多触发 create → pull → create → start → attach 共五次 API 调用,而 404 作为"镜像缺失"的信号量驱动了自动拉取的回退逻辑。

6. Hijack 机制与 CORS

Hijacking:在 v1.12 中,/attach 使用 hijack 在同一 socket 上同时承载 stdin、stdout、stderr。文档明确指出"这在未来可能会改变"——从当前仓库源码结构看,hijack 确实仍是核心机制:daemon/server/httputils/httputils.go 中定义了 hijackWriter/hijackResponse,attach、logs 等端点通过它接管底层连接;同时 attach/ws 的 WebSocket 变体在 daemon/server/router/container/container.go 的路由表中依然存在(/containers/{name:.*}/attach/ws),两种传输方式并行至今。

CORS 跨域请求:若希望浏览器等跨域客户端直接调用 Remote API,需要以守护进程模式运行时加上 --api-enable-cors 标志,例如:

$ docker -d -H="192.168.1.9:2375" --api-enable-cors

7. 从 v1.12 到当前代码库的演进线索

v1.12 文档是理解 Moby API 历史演进的基准线,对照当前仓库源码,有几条清晰的演进线索(以下均从源码结构得出,供读者对照参考):

  • 路由命名:v1.12 文档中路径参数写作 (id)/(name),当前路由统一为 /containers/{name:.*}/... 风格,且 prune 等端点通过 WithMinimumAPIVersion("1.25") 做版本门控;
  • 流协议扩展:8 字节帧头协议保持不变,但 api/pkg/stdcopy/stdcopy.go 新增了 Systemerr = 3 流,让守护进程能在流内回传系统错误;
  • 变更类型枚举/containers/(id)/changesKind 字段从 v1.12 的 0/1 扩展为 0/1/2(modify/add/delete),定义在 api/types/container/change_types.go
  • 默认 socket:文档中"daemon listens on unix:///var/run/docker.sock"在 daemon/pkg/opts/hosts.go 中以 DefaultUnixSocket = "/var/run/docker.sock" 落地。

8. 小结

Remote API v1.12 奠定了 Docker 远程 API 的基本形态:REST 风格的管理端点覆盖容器与镜像的完整生命周期(list / create / inspect / start / stop / pause / kill / logs / changes / export / copy / wait / remove / commit / search / build / events / save / load),attach 端点用 8 字节帧头的多路复用协议在同一连接上承载三向流,docker run 则通过 create → pull → start → attach 的调用链把这些端点串起来。仓库中保留的 api/docs/v1.12.md 与实现代码(api/pkg/stdcopy/stdcopy.godaemon/server/router/container/container.godaemon/changes.go 等)相互印证,既可以作为对接旧版守护进程的 API 参考,也是阅读 Moby 现代 API 实现时的最佳历史坐标。

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