首页
/ Moby Remote API v1.10 详解:容器、镜像与流式协议接口参考

Moby Remote API v1.10 详解:容器、镜像与流式协议接口参考

2026-09-05 09:34:23作者:翟江哲Frasier

本文基于 Moby 仓库中保留的历史 API 规范 api/docs/v1.10.md,完整梳理 Remote API v1.10 的全部端点、查询参数与状态码,并结合仓库中现存的 Go 客户端与 daemon 源码(如 client/hijack.goapi/pkg/stdcopy/stdcopy.go)验证其底层实现,帮助读者掌握如何直接以 HTTP 请求操作 dockerd、理解 attach 流复用协议(stream framing)的字节格式,以及 docker run 背后的 API 调用序列。

1. Remote API 基本设定

v1.10 文档的开篇明确了三件核心设定:

  • Remote API 取代了早期的 rcli(基于原始 socket 的旧客户端协议),此后客户端与 daemon 之间统一走 HTTP;
  • daemon 默认监听 Unix socket unix:///var/run/docker.sock,也可以绑定到其他 host/port 或另一个 Unix socket 上;
  • API 整体是 REST 风格,但对于 attachpull 等复杂命令,HTTP 连接会被"劫持"(hijack),在同一个 socket 上直接传输 stdoutstdinstderr,以绕过 HTTP 请求/响应模型的单向限制。

这一点在仓库当前代码中依然成立。以容器列表为例,client/container_list.go 中的 ContainerList 方法就是对 GET /containers/json 的封装,负责把 alllimitsize 等选项翻译成 query 参数:

query := url.Values{}

if options.All {
    query.Set("all", "1")
}
if options.Limit > 0 {
    query.Set("limit", strconv.Itoa(options.Limit))
}
if options.Size {
    query.Set("size", "1")
}

需要特别注意的是,从源码结构看,v1.10 文档中的 sincebefore 查询参数在现代客户端中已被移除:client/container_list.go#L12-L33 明确标注 Since/Before 选项自 API 1.24(Docker 1.12)起不再受支持,应改用 filterssince/before 过滤;Latest 也被标记为非功能性选项,推荐用 Limit: 1 替代。这说明 v1.10 是 API 参数演进过程中的一次快照,阅读历史规范时应以对应版本的 daemon 为准。

2. 容器端点

2.1 列出容器:GET /containers/json

列出容器列表,v1.10 示例请求:

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

响应示例(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
     }
]

查询参数:

  • all – 取 1/True/true0/False/false,是否显示所有容器。默认只显示运行中的容器(即默认 false);
  • limit – 只显示最近创建的 limit 个容器(包含未运行的);
  • since – 只显示该容器 Id 之后创建的容器(包含未运行的);
  • before – 只显示该容器 Id 之前创建的容器(包含未运行的);
  • size – 取 1/True/true0/False/false,是否在响应中附带容器大小(即上述 SizeRw/SizeRootFs 字段)。

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

2.2 创建容器:POST /containers/create

创建容器,请求体为容器配置的 JSON:

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

{
     "Hostname":"",
     "User":"",
     "Memory":0,
     "MemorySwap":0,
     "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":[]
}

参数说明:

  • config(请求体 JSON)– 容器的配置,即上文示例中的 HostnameUserMemoryAttachStdin/Stdout/StderrTtyCmdImageVolumesWorkingDirNetworkDisabledExposedPorts 等字段;
  • name(query 参数)– 为容器指定名称,必须匹配正则 /?[a-zA-Z0-9_-]+

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

2.3 检查容器:GET /containers/(id)/json

返回容器 id 的底层详细信息。示例请求:

GET /containers/4fa6e0f0c678/json HTTP/1.1

响应示例展示了 v1.10 时代 inspect 的完整结构,包含四大部分:

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

结构要点:

  • Config 与创建时提交的配置一致,是"期望配置";
  • State 反映运行时状态(RunningPidExitCodeStartedAtGhost);
  • NetworkSettings 描述网络接入(IP、前缀长度、网关、网桥、端口映射);
  • HostConfig 是宿主侧配置,v1.10 已包含 BindsLxcConfPrivilegedPortBindingsLinksPublishAllPorts 等字段。

状态码:200 无错误;404 容器不存在;500 服务器错误。

2.4 列出容器内进程:GET /containers/(id)/top

列出容器 id 内正在运行的进程。示例请求:

GET /containers/4fa6e0f0c678/top HTTP/1.1

响应示例:

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

TitlesProcesses 行内元素按列一一对应,客户端可直接渲染为表格。

查询参数:ps_args – 传给 ps 的参数(例如 aux),用于自定义列。

状态码:200 无错误;404 容器不存在;500 服务器错误。

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

检查容器 id 文件系统相对镜像的变更。示例请求:

GET /containers/4fa6e0f0c678/changes HTTP/1.1

响应示例中 Kind 为变更类型编号(0 表示无变更,1 表示修改/新增,2 表示删除):

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

状态码:200 无错误;404 容器不存在;500 服务器错误。

2.6 导出容器:GET /containers/(id)/export

导出容器 id 的内容。示例请求:

GET /containers/4fa6e0f0c678/export HTTP/1.1

响应为裸字节流:

HTTP/1.1 200 OK
Content-Type: application/octet-stream

{{ TAR STREAM }}

即响应体是一个 tar 流,可直接落盘为归档文件。状态码:200404500

2.7 生命周期管理:start / stop / restart / kill

启动容器 POST /containers/(id)/start。v1.10 允许在启动时通过请求体补充宿主配置(hostConfig):

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

{
     "Binds":["/tmp:/tmp"],
     "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 – 容器宿主配置(可选)。状态码:204404500

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

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

查询参数 t – 强制 kill 之前等待的秒数。响应 204,另有 404/500

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

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

查询参数同样为 t(kill 前等待秒数)。状态码:204404500

杀掉容器 POST /containers/(id)/kill

POST /containers/e90e34656806/kill HTTP/1.1

查询参数 signal – 发送给容器的信号,可为整数或 SIGINT 这样的字符串;未指定时默认 SIGKILL,并且调用会等待容器退出。状态码:204404500

2.8 Attach 到容器:POST /containers/(id)/attach

attach 是 v1.10 中最具协议复杂度的端点。示例请求:

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

查询参数(布尔值均可取 1/True/true0/False/false):

  • logs – 返回日志,默认 false
  • stream – 返回流,默认 false
  • stdin – 若 stream=true,则 attach 到 stdin,默认 false
  • stdout – 若 logs=true 返回 stdout 日志,若 stream=true 则 attach 到 stdout,默认 false
  • stderr – 若 logs=true 返回 stderr 日志,若 stream=true 则 attach 到 stderr,默认 false

状态码:200 无错误;400 参数错误;404 容器不存在;500 服务器错误。

流复用格式(Stream details)

如果创建容器(参见上一版规范 api/docs/v1.9.md)时启用了 Tty 设置,流就是进程 PTY 与客户端 stdin 的原始数据;TTY 关闭时,流被复用(multiplexed)以区分 stdout 和 stderr。每帧由 HeaderPayload 组成:

  • HEADER:8 字节,指示数据属于哪条流(stdout 或 stderr),并用最后 4 字节编码帧长度(uint32):

    header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
    

    STREAM_TYPE 取值:0 为 stdin(读取时会被写到 stdout)、1 为 stdout、2 为 stderr;SIZE1..SIZE4 是按大端序(big endian)编码的 uint32 帧长。

  • PAYLOAD:帧长 SIZE 字节的原始流数据。

文档给出的最简实现流程是:1. 读 8 字节;2. 按第 1 字节选择 stdout 或 stderr;3. 从最后 4 字节解析帧长;4. 读出该长度并输出到对应流;5. 回到第 1 步。

这套 8 字节帧格式至今未变,可直接在仓库源码中验证。api/pkg/stdcopy/stdcopy.go#L10-L24 定义了流类型与帧布局:

const (
    Stdin     StdType = 0 // 读取时输出到 stdout
    Stdout    StdType = 1
    Stderr    StdType = 2
    Systemerr StdType = 3 // daemon 侧系统错误,读取时作为 error 返回
)

const (
    stdWriterPrefixLen = 8
    stdWriterFdIndex   = 0
    stdWriterSizeIndex = 4
)

StdCopy 函数正是文档中"最简实现"的生产级版本:循环读满 8 字节头、按 buf[0] 分流出站、用 binary.BigEndian.Uint32(buf[4:8]) 取帧长后再读 payload。相比 v1.10 文档,现代实现还增加了 Systemerr3)这一类型用于回传 daemon 内部错误。

再看 daemon 侧:daemon/attach.go#L69-L79 中有一行关键判断——

multiplexed := !ctr.Config.Tty && req.MuxStreams

即只有当容器未启用 TTY 且客户端请求复用流时,daemon 才会把 outStream/errStreamstdcopymux.NewStdWriter 包装成带 8 字节头的写入器。这与文档"TTY 开启则为裸 PTY 数据、关闭则复用"的描述完全吻合。客户端侧的对应实现在 client/hijack.goclient/container_attach.go

2.9 通过 WebSocket attach: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 }}。查询参数与状态码同 2.8 节(logs/stream/stdin/stdout/stderr200400404500)。

现代 Go 客户端的 hijack 升级机制同样基于 HTTP 的 Connection: Upgrade / Upgrade 头,可参考 client/hijack.go#L45-L80setupHijackConn:发起升级请求后校验服务器返回 101 Switching Protocols,并把 TCP KeepAlive 设为 30 秒,以避免长时间无输出的会话被网络层 ECONNRESET 打断。

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}

状态码:200404500

2.11 删除容器:DELETE /containers/(id)

把容器 id 从文件系统移除。示例请求:

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

响应 HTTP/1.1 204 No Content。查询参数:

  • v1/True/true0/False/false,是否删除容器关联的卷,默认 false
  • force1/True/true0/False/false,容器正在运行时也强制删除,默认 false

状态码:204400(参数错误)、404500

2.12 从容器复制文件:POST /containers/(id)/copy

复制容器 id 中的文件或目录。示例请求:

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

状态码:200404500

3. 镜像端点

3.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 是叠加全部父层后的总大小;带 ParentId 的条目表示它构建于另一层之上。

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

创建镜像——从 registry 拉取或从源导入。示例请求:

POST /images/create?fromImage=ubuntu HTTP/1.1

响应是逐行 JSON(JSON stream),依次推送进度:

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

从 registry 拉取时,可以用 X-Registry-Auth 请求头携带 base64 编码的 AuthConfig 对象完成认证。

查询参数:

  • fromImage – 要拉取的镜像名;
  • fromSrc – 导入源,- 表示从 stdin 读取;
  • repo – 仓库名;
  • tag – 标签;
  • registry – 拉取所指向的 registry。

请求头:X-Registry-Auth – base64 编码的 AuthConfig 对象。

状态码:200500

3.3 向镜像中插入文件:POST /images/(name)/insert

把来自 url 的文件插入镜像 namepath 位置。示例请求:

POST /images/test/insert?path=/usr&url=myurl HTTP/1.1

响应同样是 JSON 进度流:

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

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

查询参数:url – 文件来源 URL;path – 文件存放路径。状态码:200500

3.4 检查镜像:GET /images/(name)/json

返回镜像 name 的底层信息。示例请求:

GET /images/ubuntu/json HTTP/1.1

响应示例(注意与容器 inspect 不同,镜像 inspect 以"层"为视角,container_config 记录了该层构建时所用容器的配置):

{
     "id":"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
     "parent":"27cf784147099545",
     "created":"2013-03-23T22:24:18.818426-07:00",
     "container":"3d67245a8d72ecf13f33dffac9f79dcdf70f75acb84d308770391510e0c23ad0",
     "container_config":
             {
                     "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"]
                     "Image":"ubuntu",
                     "Volumes":null,
                     "WorkingDir":""
             },
     "Size": 6824592
}

状态码:200404500

3.5 获取镜像历史:GET /images/(name)/history

示例请求:

GET /images/ubuntu/history HTTP/1.1

响应示例:

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

状态码:200404500

3.6 推送镜像:POST /images/(name)/push

把镜像 name 推送到 registry。示例请求与 JSON 进度流响应:

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 – 镜像在 registry 上关联的 tag(可选)。请求头:X-Registry-Auth – base64 编码的 AuthConfig 对象。状态码:200404500

3.7 给镜像打 tag:POST /images/(name)/tag

示例请求:

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

响应 HTTP/1.1 201 OK。查询参数:

  • repo – 目标仓库;
  • force1/True/true0/False/false,默认 false
  • tag – 新 tag 名。

状态码:201400404409(冲突)、500

3.8 删除镜像:DELETE /images/(name)

把镜像 name 从文件系统移除。示例请求:

DELETE /images/test HTTP/1.1

响应示例(200,逐条报告 untag 与删除动作):

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

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

查询参数:force – 强制删除,默认 falsenoprune – 不自动清理父层,默认 false。状态码:200404409500

3.9 搜索镜像:GET /images/search

在 Docker Hub 上搜索镜像。注意:响应键名自 API v1.6 起随 registry 服务器下发的 JSON 而变化。示例请求:

GET /images/search?term=sshd HTTP/1.1

响应示例:

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

查询参数:term – 搜索词。状态码:200500

4. 其他端点(Misc)

4.1 从 stdin 构建镜像:POST /build

通过 stdin 传入 tar 流构建镜像。示例请求:

POST /build HTTP/1.1

{{ TAR STREAM }}

响应为构建过程的 JSON 流:

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 – 构建成功后应用于产出镜像的仓库名(可含 tag);
  • remote – git 或 HTTP/HTTPS URI 构建源;
  • q – 抑制冗长的构建输出;
  • nocache – 构建时不使用缓存;
  • rm – 构建成功后删除中间容器。

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

4.2 校验认证配置:POST /auth

获取默认的 username 与 email。示例请求:

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

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

响应为空的 200Content-Type: text/plain)。状态码:200204500

4.3 系统信息:GET /info

GET /info HTTP/1.1

响应示例:

{
     "Containers":11,
     "Images":16,
     "Debug":false,
     "NFd": 11,
     "NGoroutines":21,
     "MemoryLimit":true,
     "SwapLimit":false,
     "IPv4Forwarding":true
}

状态码:200500

4.4 版本信息:GET /version

GET /version HTTP/1.1

响应示例:

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

状态码:200500

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

把容器 id 的变更提交为新镜像。示例请求:

POST /commit?container=44c004db4b17&m=message&repo=myrepo HTTP/1.1
Content-Type: application/json

{
     "Hostname":"",
     "User":"",
     "Memory":0,
     "MemorySwap":0,
     "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 OK
Content-Type: application/vnd.docker.raw-stream

{"Id": "596069db4bf5"}

JSON 参数 config – 新镜像的配置。查询参数:container(源容器)、repo(仓库)、tag(标签)、m(commit 消息)、author(作者,如 John Hannibal Smith <hannibal@a-team.com>)。状态码:201404500

4.6 监控事件:GET /events

通过流式(real time)或轮询(since 时间戳)获取 daemon 事件。容器会报告以下事件:

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

镜像会报告:

untag, delete

示例请求与逐行 JSON 响应:

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}

查询参数:since – 轮询使用的 Unix 时间戳。状态码:200500

4.7 保存与加载镜像 tarball

保存仓库 tarball GET /images/(name)/get:获取包含仓库 name 全部镜像与元数据的 tarball。示例:

GET /images/ubuntu/get

响应 Content-Type: application/x-tar,为二进制数据流。状态码:200500

加载 tarball POST /images/load:把一组镜像与 tag 加载进本地仓库,请求体即 tarball,成功返回 200。状态码:200500

镜像 tarball 格式

一个镜像 tarball 为每个镜像层包含一个目录(以长 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"的映射:

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

5. docker run 背后的 API 调用序列

文档 "Going further" 一节拆解了 docker run 的完整流程,理解了它就理解了如何组合上述端点实现一个最小容器客户端:

  1. Create the containerPOST /containers/create);
  2. 若状态码为 404,说明镜像不存在:先尝试 pull(POST /images/create),然后重试 create;
  3. Start the containerPOST /containers/(id)/start);
  4. 若未处于 detached 模式:attach 到容器,使用 logs=1(获取容器启动以来的 stdout 和 stderr)与 stream=1
  5. 若处于 detached 模式或只 attach 了 stdin:显示容器 id。

6. Hijacking 机制与 CORS

在 v1.10 中,/attach 使用 hijacking 在同一个 socket 上同时传输 stdin、stdout 和 stderr(文档注明未来可能改变)。其本质是:客户端发出普通 HTTP 请求后,服务器接管(hijack)底层 TCP 连接,此后双方直接读写 socket,不再受 HTTP 请求/响应边界约束。仓库中 client/hijack.gosetupHijackConn 展示了握手细节:请求携带 Connection: UpgradeUpgrade 头,服务器必须以 101 Switching Protocols 应答,客户端再从响应头读取 Content-Type(如 application/vnd.docker.raw-stream 或复用流类型)来决定是否按 8 字节帧格式解复用。

另外,v1.10 支持通过 daemon 启动参数开启跨域请求(CORS):

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

-H 绑定 TCP 监听地址、--api-enable-cors 允许浏览器端发起跨源请求。

7. 小结:如何把 v1.10 规范用到今天

  • 端点面:v1.10 已具备完整的容器生命周期(list/create/inspect/top/changes/export/start/stop/restart/kill/attach/wait/remove/copy)、镜像生命周期(list/create/insert/inspect/history/push/tag/remove/search)与运维端点(build/auth/info/version/commit/events/get/load),后续版本在此骨架上持续扩充而非推倒重来;
  • 流协议:attach 的 8 字节帧格式([type,0,0,0,size big-endian uint32] + payload)被今天的 api/pkg/stdcopy/stdcopy.go 原样沿用,是理解 docker attachdocker logs 输出分流的底层依据;
  • 演进注意:以 v1.10 写客户端时,since/before 等列表过滤参数在 API 1.24 后被 filters 取代(见 client/container_list.go#L24-L32 的弃用注释);对接现代 daemon 时应先调用 GET /version 协商 API 版本,再选择对应版本的规范文档(如 api/docs/v1.10.md 同目录下的其他版本)作为依据。
登录后查看全文
热门项目推荐
相关项目推荐