Moby Remote API v1.9:Docker 远程接口最初形态的完整端点规范与流复用协议
本文以 Moby 仓库 api/docs/v1.9.md 这份历史 API 规范为骨架,完整梳理 Remote API v1.9 的全部容器、镜像与杂项端点:请求/响应示例、查询参数、JSON 参数、状态码,以及文档中最具技术价值的"Attach 流复用(Header + Payload 帧)协议"。同时结合当前仓库源码(api/pkg/stdcopy/stdcopy.go、daemon/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,但对
attach、pull等复杂命令,会直接"劫持"(hijack)HTTP 连接来传输stdout、stdin和stderr。
需要说明版本定位: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/true 或 0/False/false。显示全部容器;默认只显示运行中的容器(默认 false) |
limit |
只显示最近创建的 limit 个容器,包含非运行态 |
since |
只显示在该 Id 之后创建的容器,包含非运行态 |
before |
只显示在该 Id 之前创建的容器,包含非运行态 |
size |
1/True/true 或 0/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 也说明当时每个容器只有单网卡、单地址的网络模型。
状态码:200;404 容器不存在;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.go 中 postContainersAttach 直接写出的 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:stdout2:stderr
- 中间 3 字节为 0(保留);
- 最后 4 字节是帧负载大小(
uint32,大端序)。
文档给出的客户端解析实现步骤:
- 读 8 字节;
- 按首字节决定输出到 stdout 还是 stderr;
- 从后 4 字节取出帧长度;
- 读取该长度字节并输出到对应流;
- 回到第 1 步。
源码印证:这段协议在 Moby 当前代码中依然原样执行——api/pkg/stdcopy/stdcopy.go 定义的 StdType 常量 Stdin=0、Stdout=1、Stderr=2 与文档完全一致;stdWriterPrefixLen = 8、stdWriterFdIndex = 0、stdWriterSizeIndex = 4 三个常量精确对应"首字节流类型 + 偏移 4 处的 4 字节大端长度"的帧布局;StdCopy() 函数即是文档所述"读 8 字节 → 判定流 → 读帧长 → 输出 → 循环"解复用算法的直接实现(它还额外定义了 StdType 3 系统错误流用于向客户端回传守护进程错误,这属于后续版本在 v1.9 帧格式基础上的扩展)。客户端侧的劫持与流处理可进一步参考 client/hijack.go 与 client/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 下载文件插入镜像 name 的 path:
POST /images/test/insert?path=/usr&url=myurl HTTP/1.1
响应同样是逐行 JSON 流(Inserting... / progress / 可能的 error)。查询参数:url(文件来源)、path(存放路径)。状态码:200 / 500。
3.4 镜像详情与历史:GET /images/(name)/json、GET /images/(name)/history
Inspect:
GET /images/base/json HTTP/1.1
响应包含镜像 id、parent、created、生成该层的 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 命名,每个目录包含三个文件:
VERSION:当前为1.0,文件格式版本号;json:层的详细信息,类似docker inspect layer_id的输出;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/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/"
}
响应为 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 分工的直接证据:
- 创建容器(
POST /containers/create); - 若返回 404,说明镜像不存在——尝试拉取(
POST /images/create),然后重试创建; - 启动容器(
POST /containers/(id)/start); - 若非分离模式:附加到容器,使用
logs=1(拿到容器启动以来的 stdout/stderr)和stream=1; - 若为分离模式或只附加了 stdin:直接显示容器 ID。
5.2 Hijacking 机制
文档指出:在 v1.9 中,/attach 通过 hijacking 在同一个 socket 上同时传输 stdin、stdout 和 stderr,并声明"这在未来可能改变"。实现上,服务端在写回 200 OK 与 application/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 为准。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00