Moby Docker Remote API v1.12 参考指南:从容器端点到 Hijack 流协议的全景解析
本文基于 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 风格,但对于
attach、pull这类复杂命令,HTTP 连接会被 hijack(劫持),在同一连接上双向传输STDOUT、STDIN和STDERR。
这种"REST + 流劫持"的混合模型一直沿用至今:简单资源操作用标准 REST 语义(GET 查询、POST 动作、DELETE 删除、状态码表达结果),而需要长连接和双向通道的操作则绕过 HTTP 响应体语义,直接接管底层连接。
2. 容器(Containers)端点
以下端点在文档中按操作逐一给出。需要说明的是,当前仓库的路由注册见 daemon/server/router/container/container.go,其中路由已统一为 /containers/{name:.*}/... 的命名风格,且新增了 prune、resize、update、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
}
]
查询参数:
- all –
1/True/true或0/False/false,是否显示全部容器;默认只显示运行中的容器 - limit – 只显示最近创建的
limit个容器(含非运行状态) - since – 只显示该 Id 之后创建的容器(含非运行状态)
- before – 只显示该 Id 之前创建的容器(含非运行状态)
- size –
1/True/true或0/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 服务端错误。
从源码结构看,请求体中的 Memory、CpuShares、Cpuset、Tty、AttachStdout 等字段与镜像配置(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(主机配置:Binds、PortBindings、LxcConf、Privileged、Links、PublishAllPorts)以及运行时状态 State(含 Running、Pid、ExitCode、Ghost)。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×tamps=1&follow=1 HTTP/1.1
示例响应:
HTTP/1.1 200 OK
Content-Type: application/vnd.docker.raw-stream
{{ STREAM }}
查询参数(均取 1/True/true 或 0/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 = 0、ChangeAdd ChangeType = 1、ChangeDelete ChangeType = 2(2 为后续版本新增的删除语义)。daemon 侧的处理入口在 daemon/changes.go 的 ContainerChanges 方法中,它先按名称定位容器,再委托给 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_TYPE:0= stdin(读取时写到 stdout)、1= stdout、2= stderrSIZE1~SIZE4:帧载荷长度,按 big endian 编码的 uint32,位于头部的最后 4 字节
文档给出的最小实现步骤:1) 读 8 字节;2) 按首字节选择 stdout/stderr;3) 从末 4 字节取出帧大小;4) 读取该数量的字节并输出到对应流;5) 回到第 1 步。
当前仓库中这套协议由 api/pkg/stdcopy/stdcopy.go 实现,与文档完全一致:常量 stdWriterPrefixLen = 8、stdWriterFdIndex = 0、stdWriterSizeIndex = 4;StdCopy 函数循环读取完整头、按 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
}
]
查询参数:
- all –
1/True/true或0/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 OK、Content-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}
容器会报告的事件:create、destroy、die、export、kill、pause、restart、start、stop、unpause;镜像会报告:untag、delete。
查询参数: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 命名的目录,目录内含三个文件:
VERSION:文件格式版本,当前为1.0json:该层的详细信息,类似docker inspect layer_id的输出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 关系的关键:
- 创建容器(
POST /containers/create); - 若状态码为
404(镜像不存在):尝试拉取(POST /images/create),然后重试创建容器; - 启动容器(
POST /containers/(id)/start); - 非分离模式下:附加到容器(
POST /containers/(id)/attach,使用logs=1以拿到容器启动以来的 stdout/stderr,并设置stream=1); - 分离模式下或仅附加 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)/changes的Kind字段从 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.go、daemon/server/router/container/container.go、daemon/changes.go 等)相互印证,既可以作为对接旧版守护进程的 API 参考,也是阅读 Moby 现代 API 实现时的最佳历史坐标。
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 StartedRust0624
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