首页
/ Moby Remote API v1.9:Docker 远程接口最初形态的完整端点规范与流复用协议

Moby Remote API v1.9:Docker 远程接口最初形态的完整端点规范与流复用协议

2026-09-04 15:10:28作者:乔或婵

本文以 Moby 仓库 api/docs/v1.9.md 这份历史 API 规范为骨架,完整梳理 Remote API v1.9 的全部容器、镜像与杂项端点:请求/响应示例、查询参数、JSON 参数、状态码,以及文档中最具技术价值的"Attach 流复用(Header + Payload 帧)协议"。同时结合当前仓库源码(api/pkg/stdcopy/stdcopy.godaemon/server/router/container/container_routes.go)印证该协议至今仍在运行的实现事实,并说明 v1.9 在现行 dockerd 中的兼容定位。读完后你将掌握:如何对照 v1.9 规范理解 Docker 早期远程调用模型、如何解析 attach 流的 8 字节帧头,以及 v1.9 与现行 API 版本体系(最低支持 v1.24)的关系。

1. v1.9 的定位:Remote API 取代 rcli 的起点

v1.9 规范开头的三点基本设定奠定了此后十余年 Docker 远程接口的形态:

  • Remote API 取代了 rcli。此前客户端通过 rcli(本地 Unix socket 的简易 RPC 方案)与守护进程通信;v1.9 将其替换为基于 HTTP 的 Remote API。
  • 默认监听 Unix socket。守护进程默认监听 unix:///var/run/docker.sock,但也可以绑定到另一个 host/port 或另一个 Unix socket。
  • 以 REST 为主,必要时劫持连接。API 总体趋向 REST,但对 attachpull 等复杂命令,会直接"劫持"(hijack)HTTP 连接来传输 stdoutstdinstderr

需要说明版本定位:api/docs/README.md 指出,该目录存放"每个受支持 API 版本的版本化文档",且对老版本的支持应视为"尽力而为(best-effort)"。从当前源码看,现行 dockerd 不再接受低于 1.24 的请求路径版本——daemon/server/server.go 中的注释明确写着"我们不再支持 1.24 之前的 API 版本",当请求中携带低于 1.24 的版本号时,服务端会刻意以纯文本(而非 JSON)返回错误,因为老客户端只会按纯文本解析错误。因此 v1.9 在 Moby 仓库中的角色是历史存档与协议演进参照:其中定义的核心机制(流复用帧格式、劫持、X-Registry-Auth、tar 构建上下文等)绝大多数被后续版本继承,但端点路径与字段已大量演进(如 GET /containers/(id)/json 在现行版本中为 GET /containers/(id)/json 的 inspect 语义,而 /images/(name)/json 等路径在现行 api/swagger.yaml 中已有不同的映射)。各版本差异可对照 api/docs/CHANGELOG.md

2. 容器端点(Endpoints: Containers)

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": "base:latest",
        "Command": "echo 1",
        "Created": 1367854155,
        "Status": "Exit 0",
        "Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}],
        "SizeRw": 12288,
        "SizeRootFs": 0
    },
    {
        "Id": "9cd87474be90",
        "Image": "base: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

示例请求

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

{
    "Hostname":"",
    "User":"",
    "Memory":0,
    "MemorySwap":0,
    "CpuShares":0,
    "AttachStdin":false,
    "AttachStdout":true,
    "AttachStderr":true,
    "PortSpecs":null,
    "Tty":false,
    "OpenStdin":false,
    "StdinOnce":false,
    "Env":null,
    "Cmd":["date"],
    "Dns":null,
    "Image":"base",
    "Volumes":{"/tmp": {}},
    "VolumesFrom":"",
    "WorkingDir":"",
    "ExposedPorts":{"22/tcp": {}}
}

示例响应

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

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

JSON 参数

参数 说明
Hostname 容器主机名
User 用户名或 UID
Memory 内存限制(字节)
CpuShares CPU 份额(相对权重)
AttachStdin 是否附加标准输入,默认 false
AttachStdout 是否附加标准输出,默认 false
AttachStderr 是否附加标准错误,默认 false
Tty 是否分配伪终端(pseudo-tty),默认 false
OpenStdin 即使未附加也保持 stdin 打开,默认 false

查询参数

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

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

值得注意的一点是:v1.9 时代主机侧配置(挂载、端口绑定、LXC 选项)尚未并入创建请求,而是留给了 start 端点(见 2.5),这与现行 API 中"create 与 start 之间可传 HostConfig"的设计一脉相承。

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": "base",
        "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
    }
}

响应结构清晰地呈现了 v1.9 时代容器模型的三大块:Config(镜像层配置与用户覆盖)、State(运行状态,含 Ghost 字段表示进程曾异常退出、需重启守护进程清理,这是 LXC 时代的遗留概念)、HostConfig(挂载、端口绑定、特权等主机侧设置)。NetworkSettings 中单数的 IpAddress/PortMapping 也说明当时每个容器只有单网卡、单地址的网络模型。

状态码200404 容器不存在;500

2.4 查看容器内进程 / 文件系统变更 / 导出内容

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

GET /containers/4fa6e0f0c678/top HTTP/1.1

响应包含 Titles(ps 列标题)与 Processes(进程数组):

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

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

GET /containers/4fa6e0f0c678/changes HTTP/1.1

响应是一个变更列表,Kind 为变更类型编码(示例中 0 表示属性变化、1 表示新增):

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

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

状态码:200 / 404 / 500

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

GET /containers/4fa6e0f0c678/export HTTP/1.1

响应为 Content-Type: application/octet-stream{{ TAR STREAM }} 原始 tar 流,即容器文件系统的完整导出。状态码:200 / 404 / 500

2.5 生命周期控制:start / stop / restart / kill

启动容器 POST /containers/(id)/start——v1.9 中 start 请求体承载主机侧配置,这是理解早期 API 的关键:

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
}

响应:HTTP/1.1 204 No Content

JSON 参数

参数 说明
Binds host-path:container-path:rw|ro 形式创建绑定挂载;容器内路径不存在时会新建卷
LxcConf 自定义 LXC 选项的映射
PortBindings 暴露容器端口,可选地通过 HostPort 发布到宿主机
PublishAllPorts 将所有暴露端口发布到宿主机接口,默认 false
Privileged 授予容器扩展特权,默认 false

状态码:204 / 404 / 500

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

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

查询参数 t——在终止容器前等待的秒数。响应 HTTP/1.1 204。状态码:204 / 404 / 500

重启容器 POST /containers/(id)/restart:同样支持 t 参数,响应 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.6 Attach 与流复用协议(v1.9 最有价值的技术细节)

附加到容器 POST /containers/(id)/attach

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

响应(注意 Content-Type,它与当前 dockerd 的实现完全一致,可对照 daemon/server/router/container/container_routes.gopostContainersAttach 直接写出的 HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n):

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

{{ STREAM }}

查询参数

参数 说明
logs 是否回传历史日志,默认 false
stream 是否回传实时流,默认 false
stdin stream=true,附加到 stdin,默认 false
stdout logs=true 回传 stdout 日志;若 stream=true 附加到 stdout,默认 false
stderr logs=true 回传 stderr 日志;若 stream=true 附加到 stderr,默认 false

状态码:200 / 400(参数错误)/ 404 / 500

流格式(Stream details)——这是 v1.9 文档的技术核心

当创建容器时开启了 Tty,流就是进程 PTY 与客户端 stdin 的原始数据,不做复用;当 Tty 关闭时,stdout 与 stderr 会被**复用(multiplex)**到同一条 TCP 连接上,形成 Header + Payload 的帧结构。

帧头(HEADER)编码规则:

header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
  • 第 1 字节 STREAM_TYPE 标识本帧属于哪条流:
    • 0:stdin(读取时会被写到 stdout 上)
    • 1:stdout
    • 2:stderr
  • 中间 3 字节为 0(保留);
  • 最后 4 字节是帧负载大小(uint32,大端序)。

文档给出的客户端解析实现步骤:

  1. 读 8 字节;
  2. 按首字节决定输出到 stdout 还是 stderr;
  3. 从后 4 字节取出帧长度;
  4. 读取该长度字节并输出到对应流;
  5. 回到第 1 步。

源码印证:这段协议在 Moby 当前代码中依然原样执行——api/pkg/stdcopy/stdcopy.go 定义的 StdType 常量 Stdin=0Stdout=1Stderr=2 与文档完全一致;stdWriterPrefixLen = 8stdWriterFdIndex = 0stdWriterSizeIndex = 4 三个常量精确对应"首字节流类型 + 偏移 4 处的 4 字节大端长度"的帧布局;StdCopy() 函数即是文档所述"读 8 字节 → 判定流 → 读帧长 → 输出 → 循环"解复用算法的直接实现(它还额外定义了 StdType 3 系统错误流用于向客户端回传守护进程错误,这属于后续版本在 v1.9 帧格式基础上的扩展)。客户端侧的劫持与流处理可进一步参考 client/hijack.goclient/internal/json-stream.go

2.7 Attach(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)同 2.6 的 attach 端点。

2.8 wait / remove / copy

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

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——是否同时删除关联卷,默认 false。响应 204 No Content。状态码:204 / 400 / 404 / 500

从容器拷贝文件 POST /containers/(id)/copy

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

{
    "Resource": "test.txt"
}

响应为 application/octet-stream{{ TAR STREAM }}。状态码:200 / 404 / 500

3. 镜像端点(Endpoints: 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
  }
]

响应中 Size 为本层增量大小,VirtualSize 为含所有父层的镜像总大小——这反映了当时 aufs 叠加层的存储模型。

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

从 registry 拉取,或从源导入:

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

流式响应(逐行 JSON 消息,这是 v1.9 起延续至今的进度报告风格):

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

查询参数

参数 说明
fromImage 要拉取的镜像名
fromSrc 导入源,- 表示 stdin
repo 仓库名
tag 标签
registry 拉取所用 registry

请求头X-Registry-Auth——base64 编码的 AuthConfig 对象(私有仓库认证,该约定沿用至今)。

状态码:200 / 500

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

url 下载文件插入镜像 namepath

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

响应同样是逐行 JSON 流(Inserting... / progress / 可能的 error)。查询参数:url(文件来源)、path(存放路径)。状态码:200 / 500

3.4 镜像详情与历史:GET /images/(name)/jsonGET /images/(name)/history

Inspect

GET /images/base/json HTTP/1.1

响应包含镜像 idparentcreated、生成该层的 container、完整 container_config(与容器创建请求同构)以及 Size

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

{
    "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"], "Dns":null, "Image":"base",
        "Volumes":null, "VolumesFrom":"", "WorkingDir":""
    },
    "Size": 6824592
}

状态码:200 / 404(无此镜像)/ 500

History

GET /images/base/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.5 推送 / 打标签 / 删除

推送 POST /images/(name)/push

POST /images/test/push HTTP/1.1

响应为逐行进度流(Pushing... / progressDetail / error)。请求头 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(默认 false)、tag(新标签名)。响应 HTTP/1.1 201 OK。状态码:201 / 400 / 404 / 409(冲突,如目标标签已存在且未 force)/ 500

删除 DELETE /images/(name)

DELETE /images/test HTTP/1.1

响应列出实际发生的动作——先 Untagged 标签,再逐层 Deleted

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

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

状态码:200 / 404 / 409 / 500

3.6 搜索镜像:GET /images/search

在 Docker Hub 上搜索。规范中特别注明:从 API v1.6 起响应键名已随 registry 服务端返回给 daemon 的 JSON 而变更。

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

[
    {
        "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。状态码:200 / 500

3.7 镜像 tarball:get / load 及其格式

导出仓库 tarball GET /images/(name)/get

GET /images/ubuntu/get

响应为 Content-Type: application/x-tar 的二进制流,包含该仓库所有镜像与标签。状态码:200 / 500

导入 tarball POST /images/load:请求体即 tarball,响应 200。状态码:200 / 500

镜像 tarball 格式(v1.9 时代 docker save/docker load 的底层格式):

  • tarball 中每个镜像层一个目录,以层的长 ID 命名,每个目录包含三个文件:
    1. VERSION:当前为 1.0,文件格式版本号;
    2. json:层的详细信息,类似 docker inspect layer_id 的输出;
    3. layer.tar:该层文件系统变更的 tar 文件。
  • layer.tar 中包含 aufs 风格的 .wh..wh.aufs 文件与目录,用于保存属性变更与删除标记(叠加层的"白"文件语义)。
  • 若 tarball 定义了仓库,根目录还会有 repositories 文件,内容为仓库/标签名到层 ID 的映射,例如:
{"hello-world":
    {"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"}
}

4. 杂项端点(Misc)

4.1 从 Dockerfile 构建:POST /build

构建上下文以压缩 tar 流作为 POST 请求体:

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

规范要求:流必须是 identity(不压缩)、gzip、bzip2、xz 之一压缩的 tar 归档;归档根部必须包含名为 Dockerfile 的文件;归档中其他文件均可在构建上下文中被 ADD 等指令引用。

查询参数

参数 说明
t 构建成功后应用到结果镜像的仓库名(可含标签)
remote 构建源 URI(git 或 HTTPS/HTTP),用于远程 Dockerfile
q 静默构建输出
nocache 构建时不使用缓存
rm 构建成功后删除中间容器

请求头Content-type 应设为 application/tarX-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/"
}

响应为 200/204(无错误,无正文)。状态码: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,
    "Debug":false,
    "NFd": 11,
    "NGoroutines":21,
    "MemoryLimit":true,
    "SwapLimit":false,
    "IPv4Forwarding":true
}

状态码:200 / 500

4.4 版本信息:GET /version

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

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

状态码:200 / 500

4.5 提交容器为镜像:POST /commit

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":"",
    "DisableNetwork": false,
    "ExposedPorts":{"22/tcp": {}}
}

响应:

HTTP/1.1 201 Created
Content-Type: application/vnd.docker.raw-stream

{"Id": "596069db4bf5"}

参数:JSON 中的 config 为容器配置;查询参数 container(源容器)、repo(仓库)、tag(标签)、m(提交信息)、author(作者,如 "John Hannibal Smith <hannibal@a-team.com>")。状态码:201 / 404 / 500

4.6 事件监控:GET /events

实时流式或基于 since 的时间戳轮询获取事件。容器事件:create, destroy, die, export, kill, pause, restart, start, stop, unpause;镜像事件:untag, delete

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

{"status": "create", "id": "dfdf82bd3881","from": "base:latest", "time":1374067924}
{"status": "start", "id": "dfdf82bd3881","from": "base:latest", "time":1374067924}
{"status": "stop", "id": "dfdf82bd3881","from": "base:latest", "time":1374067966}
{"status": "destroy", "id": "dfdf82bd3881","from": "base:latest", "time":1374067970}

查询参数 since——轮询用时间戳。状态码:200 / 500

5. 深入理解:docker run 的端点组合、Hijacking 与 CORS

5.1 docker run 背后的 API 调用序列

v1.9 规范明确拆解了 docker run 的客户端步骤,是理解早期 CLI 与 daemon 分工的直接证据:

  1. 创建容器(POST /containers/create);
  2. 若返回 404,说明镜像不存在——尝试拉取(POST /images/create),然后重试创建;
  3. 启动容器(POST /containers/(id)/start);
  4. 若非分离模式:附加到容器,使用 logs=1(拿到容器启动以来的 stdout/stderr)和 stream=1
  5. 若为分离模式或只附加了 stdin:直接显示容器 ID。

5.2 Hijacking 机制

文档指出:在 v1.9 中,/attach 通过 hijacking 在同一个 socket 上同时传输 stdin、stdout 和 stderr,并声明"这在未来可能改变"。实现上,服务端在写回 200 OKapplication/vnd.docker.raw-stream 响应头后,把底层 TCP 连接从 HTTP 层剥离,直接在裸连接上读写帧数据——当前 dockerd 的 postContainersAttach 仍沿用该模式:调用 hijacker.Hijack() 取得裸连接后写响应头,再交给容器 IO 复用。客户端侧的对应实现见 client/hijack.go。这一机制使 attach、exec、logs 等端点得以用一条连接承载双向、多路复用 I/O。

5.3 启用跨域请求(CORS)

v1.9 时代若要以 HTTP 方式从浏览器等跨源场景访问远程 API,需要以 --api-enable-cors 标志启动守护进程,例如:

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

该历史细节提示:在 v1.9 中,HTTP 绑定(-H 指定 host/port)与 CORS 开关是独立于 Unix socket 的另一条访问路径。

6. 小结:如何把 v1.9 放进现行 Moby 的坐标里

  • 端点清单:v1.9 定义了容器(list/create/inspect/top/changes/export/start/stop/restart/kill/attach/attach-ws/wait/remove/copy)、镜像(list/create/insert/inspect/history/push/tag/remove/search/get/load)与杂项(build/auth/info/version/commit/events)三大类共二十余个端点,每个端点都带有请求/响应示例、参数表和状态码表——这份完整清单是研究 Docker API 演进的基线版本。
  • 协议遗产:attach 的 8 字节帧头复用格式(STREAM_TYPE + 3 字节保留 + 4 字节大端长度)是 v1.9 留下的最持久设计,当前代码 api/pkg/stdcopy/stdcopy.go 中的常量与解复用循环与文档逐条对应;X-Registry-Auth 请求头、build 的 tar 上下文与逐行 JSON 进度流、镜像 tarball 的"每层目录 + VERSION/json/layer.tar"结构也均源出于此期规范并延续至今。
  • 版本治理api/docs/README.md 将 v1.9 这样的老版本文档定位为"尽力而为"的兼容存档,各版本差异见 api/docs/CHANGELOG.md;现行服务端对低于 1.24 的版本请求仅返回纯文本错误(见 daemon/server/server.go)。因此本文档的实用价值在于协议考古与客户端兼容性分析,而非直接对接当前 dockerd——对接现行版本应以 api/swagger.yaml 为准。
登录后查看全文
热门项目推荐
相关项目推荐