Moby Remote API v1.16 深度解析:容器与镜像端点全解及多路复用流协议
本文以 Moby 仓库中的历史 API 规范文档 api/docs/v1.16.md 为主体,完整还原 Docker Remote API v1.16 的端点定义:容器生命周期管理、镜像仓库交互、构建与事件流、以及 attach/exec 背后基于 HTTP 连接劫持的 stdout/stderr 多路复用协议。读完本文,你将掌握 v1.16 版本 API 的完整请求/响应格式、查询参数与状态码语义,并对照当前仓库源码(版本协商中间件、流拆包器、hijack 客户端)验证这套协议的实现依据与后续演进。
1. v1.16 Remote API 的定位与传输形态
v1.16 规范开篇给出三条基本事实:
- Remote API 取代了 rcli:早期 Docker 的远程客户端 rcli 被统一的 HTTP REST API 取代;
- 默认监听 Unix socket:daemon 监听
unix:///var/run/docker.sock,也可绑定到其它 host/port 或 Unix socket; - 以 REST 为主,流式场景使用 hijack:API 总体倾向于 REST 风格,但对于
attach、pull等复杂命令,HTTP 连接会被"劫持"(hijack),在同一条连接上双向传输STDOUT、STDIN、STDERR。
从源码结构看,当前仓库中这套 API 的入口组织在 daemon/server/router/ 下按资源划分(容器、镜像、exec、系统等),版本协商则由 daemon/server/middleware/version.go 完成:每个请求携带的 API 版本若低于 minAPIVersion 或高于 daemon 的默认版本,会返回 versionUnsupportedError,同时每个响应都会带上 Api-Version 头(见 version.go)。
需要注意适用前提:当前仓库 daemon/config/config.go 中定义的版本范围是 MaxAPIVersion = "1.56"、MinAPIVersion = "1.24",即 v1.16 属于历史规范版本,已低于当前 daemon 支持的下限,但它的端点划分、查询参数与流协议仍是理解整个 Remote API 体系的基线,本文按原文档完整继承其内容。
2. 容器端点(2.1 Containers)
2.1 列出容器:GET /containers/json
示例请求:
GET /containers/json?all=1&before=8dfafdbc3a40&size=1 HTTP/1.1
示例响应(节选,字段与原文档一致):
[
{
"Id": "8dfafdbc3a40",
"Names": ["/boring_feynman"],
"Image": "ubuntu:latest",
"Command": "echo 1",
"Created": 1367854155,
"Status": "Exit 0",
"Ports": [{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}],
"SizeRw": 12288,
"SizeRootFs": 0
},
{
"Id": "9cd87474be90",
"Names": ["/coolName"],
"Image": "ubuntu: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 字段) |
filters |
JSON 编码的 map[string][]string 过滤器。可用:exited=<int>(按退出码过滤)、`status=(restarting |
状态码:200 无错误;400 参数错误;500 服务器错误。
演进佐证:在当前仓库的 client/container_list.go 中,
all/limit/size/filters仍然以相同语义映射为查询参数,但Since、Before选项已被标记为废弃(自 docker 1.12 / API 1.24 起改用since/beforefilter 代替)——v1.16 文档中的since/before查询参数正是这次演变的上一代形态。
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,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": ["FOO=bar", "BAZ=quux"],
"Cmd": ["date"],
"Entrypoint": "",
"Image": "ubuntu",
"Volumes": {"/tmp": {}},
"WorkingDir": "",
"NetworkDisabled": false,
"MacAddress": "12:34:56:78:9a:bc",
"ExposedPorts": {"22/tcp": {}},
"SecurityOpt": [],
"HostConfig": {
"Binds": ["/tmp:/tmp"],
"Links": ["redis3:redis"],
"LxcConf": {"lxc.utsname": "docker"},
"PortBindings": {"22/tcp": [{"HostPort": "11022"}]},
"PublishAllPorts": false,
"Privileged": false,
"Dns": ["8.8.8.8"],
"DnsSearch": [""],
"ExtraHosts": null,
"VolumesFrom": ["parent", "other:ro"],
"CapAdd": ["NET_ADMIN"],
"CapDrop": ["MKNOD"],
"RestartPolicy": {"Name": "", "MaximumRetryCount": 0},
"NetworkMode": "bridge",
"Devices": []
}
}
示例响应:
HTTP/1.1 201 Created
Content-Type: application/json
{"Id": "e90e34656806", "Warnings": []}
顶层 JSON 参数(完整继承原文档):
- Hostname:容器内使用的主机名;
- Domainname:容器内使用的域名;
- User:容器内运行命令的用户;
- Memory:内存限制(字节);
- MemorySwap:总内存限制(内存 + swap);设为
-1启用无限 swap; - CpuShares:CPU 相对权重(相对于其它容器的权重);
- Cpuset:cgroups cpuset,如
"0,1"; - AttachStdin / AttachStdout / AttachStderr:布尔值,是否附加对应标准流;
- Tty:是否将标准流附加到 TTY(含未关闭的 stdin);
- OpenStdin:是否打开 stdin;
- StdinOnce:一个 attach 客户端断开后关闭 stdin;
- Env:
["VAR=value", "VAR2=value2"]形式的环境变量列表; - Cmd:要运行的命令(字符串或字符串数组);
- Entrypoint:入口点(字符串或字符串数组);
- Image:镜像名;
- Volumes:挂载点路径到空对象的映射;
- WorkingDir:工作目录;
- NetworkDisabled:为 true 时禁用容器网络;
- ExposedPorts:
{"<port>/<tcp|udp>: {}}"形式的端口暴露映射; - SecurityOpt:用于 SELinux 等 MLS 系统的标签定制列表。
HostConfig 参数:
- Binds:卷绑定列表,三种形态——
container_path(为容器新建卷)、host_path:container_path(绑定挂载宿主路径)、host_path:container_path:ro(只读挂载); - Links:链接列表,形如
"container_name:alias"; - LxcConf:LXC 专属配置(仅在
lxc执行驱动下生效,该字段后来在 v1.22 中被移除); - PortBindings:
{ "<port>/<protocol>": [{"HostPort": "<port>"}] },注意port是字符串而非整数; - PublishAllPorts:为所有暴露端口随机分配宿主端口(布尔值);
- Privileged:授予容器对宿主机的完全访问权限(布尔值);
- Dns / DnsSearch:DNS 服务器 / DNS 搜索域列表;
- ExtraHosts:追加到容器
/etc/hosts的映射,形式["hostname:IP"]; - VolumesFrom:从其它容器继承卷,形式
<container name>[:<ro|rw>]; - CapAdd / CapDrop:添加/移除的内核 capability 列表;
- RestartPolicy:
Name取"always"(总是重启)或"on-failure"(退出码非零才重启);on-failure时MaximumRetryCount控制重试上限;默认不重启。每次重启前会加入递增延迟(上次延迟的两倍,起始 100ms),防止"重启风暴"打垮服务端; - NetworkMode:网络模式,支持
bridge、host、none、container:<name|id>; - Devices:设备映射,形如
{"PathOnHost": "/dev/deviceName", "PathInContainer": "/dev/deviceName", "CgroupPermissions": "mrw"}。
查询参数:name —— 为容器指定名称,必须匹配 /?[a-zA-Z0-9_-]+。
状态码:201 成功;404 无此容器;406 无法附加(容器未运行);500 服务器错误。
2.3 查看容器详情:GET /containers/(id or name)/json
返回容器 id 的底层信息。示例请求/响应:
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": ["/name:alias"],
"PublishAllPorts": false,
"CapAdd": ["NET_ADMIN"],
"CapDrop": ["MKNOD"]
}
}
状态码:200 无错误;404 无此容器;500 服务器错误。
2.4 列出容器内进程:GET /containers/(id or name)/top
在 Unix 系统上通过执行 ps 命令实现;Windows 不支持。默认 ps_args 为 -ef,可用 ?ps_args=aux 切换:
GET /containers/4fa6e0f0c678/top HTTP/1.1
{
"Titles": ["UID", "PID", "PPID", "C", "STIME", "TTY", "TIME", "CMD"],
"Processes": [
["root", "13642", "882", "0", "17:03", "pts/0", "00:00:00", "/bin/bash"],
["root", "13735", "13642", "0", "17:06", "pts/0", "00:00:00", "sleep 10"]
]
}
GET /containers/4fa6e0f0c678/top?ps_args=aux HTTP/1.1
{
"Titles": ["USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", "STAT", "START", "TIME", "COMMAND"],
"Processes": [
["root", "13642", "0.0", "0.1", "18172", "3184", "pts/0", "Ss", "17:03", "0:00", "/bin/bash"],
["root", "13895", "0.0", "0.0", "4348", "692", "pts/0", "S+", "17:15", "0:00", "sleep 10"]
]
}
状态码:200 无错误;404 无此容器;500 服务器错误。
2.5 获取容器日志:GET /containers/(id or name)/logs
GET /containers/4fa6e0f0c678/logs?stderr=1&stdout=1×tamps=1&follow=1&tail=10 HTTP/1.1
响应 Content-Type: application/vnd.docker.raw-stream,正文为 {{ STREAM }}。
查询参数(全部默认 false,除 tail 默认 all):
- follow – 是否返回流式日志;
- stdout / stderr – 是否分别返回 stdout / stderr 日志;
- timestamps – 是否为每行日志打印时间戳;
- tail – 只输出末尾指定行数:
all或<number>。
状态码:200 / 404 / 500。
2.6 文件系统变更、导出与 TTY 调整
查看变更:GET /containers/(id or name)/changes —— 返回容器文件系统的变更列表,Kind 字段表示变更类型(原文示例中 0 为未变更、1 为修改):
[
{"Path": "/dev", "Kind": 0},
{"Path": "/dev/kmsg", "Kind": 1},
{"Path": "/test", "Kind": 1}
]
导出容器:GET /containers/(id or name)/export —— 以 application/octet-stream 返回 {{ TAR STREAM }}(tar 流)。
调整 TTY:POST /containers/(id or name)/resize?h=<height>&w=<width> —— v1.16 版本中 resize 需要重启容器才生效:
POST /containers/4fa6e0f0c678/resize?h=40&w=80 HTTP/1.1
状态码 200;404 无此容器;500 无法 resize。
这三个端点的状态码均为 200 / 404 / 500。
2.7 生命周期操作:start / stop / restart / kill / pause / unpause
- 启动:
POST /containers/(id or name)/start。注意:为向后兼容,该端点在 v1.16 中接受 JSON 编码的HostConfig作为请求体(见创建容器一节);此后不再接受(v1.24 起移除)。成功 204,已启动 304,无此容器 404,服务器错误 500。 - 停止:
POST /containers/(id or name)/stop,查询参数t为强杀前等待的秒数。成功 204,已停止 304,404,500。 - 重启:
POST /containers/(id or name)/restart,同样支持t参数。204 / 404 / 500。 - 强杀:
POST /containers/(id or name)/kill,查询参数signal可以是信号整数或字符串(如SIGINT);未指定时默认 SIGKILL,且调用会阻塞等待容器退出。204 / 404 / 500。 - 暂停 / 恢复:
POST /containers/(id or name)/pause与/unpause。204 / 404 / 500。
2.8 附加到容器:POST /containers/(id or name)/attach
POST /containers/16253994b7c4/attach?logs=1&stream=0&stdout=1 HTTP/1.1
响应 Content-Type: application/vnd.docker.raw-stream。
查询参数(均默认 false):
- logs – 返回历史日志;
- stream – 返回实时流;
- stdin – 若
stream=true,附加到 stdin; - stdout – 若
logs=true返回 stdout 日志;若stream=true附加到 stdout; - stderr – 对 stderr 同理。
状态码:200;400 参数错误;404;500。
流协议(Stream details) —— 这是 v1.16 文档中最关键的技术细节之一:
- 创建容器时若启用了
Tty,流就是进程 PTY 与客户端 stdin 的原始数据; - 若 TTY 关闭,流是多路复用的,用帧格式区分 stdout 与 stderr。
帧 = Header(8 字节)+ Payload:
header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
STREAM_TYPE:0= stdin(写到 stdout 侧)、1= stdout、2= stderr;SIZE1..SIZE4:载荷长度(uint32,大端编码)。
文档给出的最简实现循环:
- 读 8 字节;
- 按第 1 个字节选择 stdout 或 stderr;
- 从最后 4 字节解出帧长;
- 读取该长度字节并写到对应输出;
- 回到第 1 步。
WebSocket 版本:GET /containers/(id or name)/attach/ws —— 查询参数与 attach 相同,按 RFC 6455 完成 WebSocket 握手:
GET /containers/e90e34656806/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1 HTTP/1.1
源码印证:这套 8 字节帧协议在当前仓库中仍然原样存在。api/pkg/stdcopy/stdcopy.go 定义了 Stdin = 0、Stdout = 1、Stderr = 2,以及 stdWriterPrefixLen = 8、stdWriterFdIndex = 0、stdWriterSizeIndex = 4;StdCopy() 函数(stdcopy.go)逐帧读取、按首字节分流到 destOut/destErr、用 binary.BigEndian.Uint32 解析帧长——与 v1.16 文档中的五步实现一一对应。
2.9 等待 / 删除 / 拷贝
- 等待:
POST /containers/(id or name)/wait—— 阻塞到容器停止并返回退出码:响应体{"StatusCode": 0}。200 / 404 / 500。 - 删除:
DELETE /containers/(id or name)—— 参数v(同时删除关联卷)、force(先 kill 再删)。204;400 参数错误;404;500。 - 从容器拷贝文件:
POST /containers/(id or name)/copy—— 请求体{"Resource": "test.txt"},响应application/x-tar的{{ TAR STREAM }}。200 / 404 / 500。该端点后来在 API v1.24 中被移除(见 api/docs/CHANGELOG.md 中 v1.24 条目)。
2.10 Exec 四端点
- Exec Create:
POST /containers/(id or name)/exec—— 在运行中的容器里建立 exec 实例。JSON 参数:AttachStdin、AttachStdout、AttachStderr、Tty、Cmd。响应 201,返回{"Id": "f90e34656806"}。404 表示无此容器。 - Exec Start:
POST /exec/(id)/start—— JSON 参数Detach(分离模式)、Tty。Detach=true时启动后立即返回;否则建立交互式会话,响应流行为与 attach 完全一致(8 字节帧多路复用)。 - Exec Resize:
POST /exec/(id)/resize?h=&w=—— 仅在 exec 创建与启动时指定了tty才有效。201 / 404。 - Exec Inspect:
GET /exec/(id)/json—— 返回ID、Running、ExitCode、ProcessConfig(含privileged、user、tty、entrypoint、arguments)以及完整的Container快照(State、Config、NetworkSettings、Volume 路径等)。200 / 404 / 500。
客户端侧对应实现可参见 client/container_exec.go。
3. 镜像端点(2.2 Images)
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
}
]
查询参数:all(默认 false);filters(JSON 编码,可用 dangling=true);filter(仅返回指定名称的镜像,该参数后被 filters 取代)。
3.2 创建镜像(拉取或导入):POST /images/create
POST /images/create?fromImage=ubuntu HTTP/1.1
响应是 JSON 进度流:
{"status": "Pulling..."}
{"status": "Pulling", "progress": "1 B/ 100 B", "progressDetail": {"current": 1, "total": 100}}
{"error": "Invalid..."}
查询参数:
- fromImage – 要拉取的镜像名;
- fromSrc – 导入来源,可以是 URL,也可以是
-(从请求体读取镜像); - repo – 仓库名;
- tag – 标签。
请求头:X-Registry-Auth – base64 编码的 AuthConfig 对象(拉取私有仓库时携带认证)。状态码:200 / 500。
3.3 其余镜像端点
- 查看:
GET /images/(name)/json—— 返回Created、Container、ContainerConfig(含Hostname/User/Memory/Tty/Cmd/Image/Volumes等)、Id、Parent、Size。200 / 404 / 500。(Container与ContainerConfig字段后来在 v1.45 被移除。) - 历史:
GET /images/(name)/history—— 返回Id、Created、CreatedBy数组(/bin/bash等层创建命令)。200 / 404 / 500。 - 推送:
POST /images/(name)/push—— 返回{"status": "Pushing..."}式进度流。推私有仓库时,镜像必须先 tag 到引用该 registry 主机名的仓库,URL 中即使用该仓库名(与 CLI 流程一致),例如POST /images/registry.acme.com:5000/test/push。查询参数tag;请求头X-Registry-Auth。200 / 404 / 500。 - 打标签:
POST /images/(name)/tag?repo=myrepo&force=0&tag=v42—— 201 成功;400 参数错误;404;409 冲突;500。 - 删除:
DELETE /images/(name)—— 参数force、noprune。响应为数组,如[{"Untagged": "3e2f21a89f"}, {"Deleted": "3e2f21a89f"}, {"Deleted": "53b4f83ac9"}]。200 / 404 / 409 / 500。 - 搜索:
GET /images/search?term=sshd—— 在 Docker Hub 上搜索;注意 v1.6 起响应键名已改为 registry 服务返回的原始 JSON(description、is_official、is_automated、name、star_count)。200 / 500。
3.4 镜像 tarball:save / load 与格式
- 单仓库导出:
GET /images/(name)/get—— 返回application/x-tar二进制流。name为具体仓库:tag时只导出该镜像(含父层);为镜像 ID 时同样只导出该镜像,且 tarball 中不包含repositories文件(因为没有名称可引用)。 - 多仓库导出:
GET /images/get?names=myname%2Fmyapp%3Alatest&names=busybox——names可重复,语义同上。 - 导入:
POST /images/load—— tarball 放在请求体中,200 表示成功。
镜像 tarball 格式(原文档完整继承):每个镜像层一个以长 ID 命名的目录,内含三个文件:
VERSION:格式版本,当前为1.0;json:层的详细信息,类似docker inspect layer_id;layer.tar:该层文件系统变更的 tar 文件,其中使用 aufs 风格的.wh..wh.aufs文件与目录保存属性变更与删除信息。
若 tarball 定义了一个仓库,根目录还会有 repositories 文件,列出仓库与标签到层 ID 的映射:
{"hello-world":
{"latest": "565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1"}
}
4. 其它端点(2.3 Misc)
4.1 构建:POST /build
POST /build HTTP/1.1
{{ TAR STREAM }}
响应是构建输出流:
{"stream": "Step 1..."}
{"stream": "..."}
{"error": "Error...", "errorDetail": {"code": 123, "message": "Error..."}}
约束与参数(完整继承原文档):
- 流必须是 tar 归档,压缩算法限 identity(不压缩)、gzip、bzip2、xz 之一;
- 归档根目录必须包含
Dockerfile,其余文件都进入构建上下文(对应 Dockerfile 的 ADD 指令); - 查询参数:t(成功时给结果镜像打的仓库名/标签)、remote(git 或 HTTP/HTTPS 构建源)、q(静默输出)、nocache(不用缓存)、pull(即使本地存在旧镜像也尝试拉取)、rm(成功后删除中间容器,默认行为)、forcerm(总是删除中间容器,含 rm 的语义);
- 请求头:
Content-type应为"application/tar";X-Registry-Config– base64 编码的 ConfigFile 对象。
状态码:200 / 500。
4.2 认证检查:POST /auth
请求体(原文档示例):
{
"username": "hannibal",
"password": "xxxx",
"email": "hannibal@a-team.com",
"serveraddress": "https://index.docker.io/v1/"
}
响应 200 或 204 表示无错误;500 服务器错误。
4.3 系统信息:GET /info
响应示例(v1.16 时代的字段集合):
{
"Containers": 11,
"Images": 16,
"Driver": "btrfs",
"DriverStatus": [[""]],
"ExecutionDriver": "native-0.1",
"KernelVersion": "3.12.0-1-amd64",
"NCPU": 1,
"MemTotal": 2099236864,
"Name": "prod-server-42",
"ID": "7TRN:IPZB:QYBB:VPBQ:UMPP:KARE:6ZNR:XE6T:7EWV:PKF4:ZOJD:TPYS",
"Debug": false,
"NFd": 11,
"NGoroutines": 21,
"NEventsListener": 0,
"InitPath": "/usr/bin/docker",
"InitSha1": "",
"IndexServerAddress": ["https://index.docker.io/v1/"],
"MemoryLimit": true,
"SwapLimit": false,
"IPv4Forwarding": true,
"Labels": ["storage=ssd"],
"DockerRootDir": "/var/lib/docker",
"OperatingSystem": "Boot2Docker"
}
其中 Driver 为存储驱动名,ID 为产品密钥标识,DockerRootDir 为数据根目录。200 / 500。
4.4 版本、心跳与提交
- 版本:
GET /version—— 返回ApiVersion、Version、GitCommit、GoVersion(示例响应为{"ApiVersion": "1.12", "Version": "0.2.2", ...})。 - 心跳:
GET /_ping—— 返回200 OK,正文OK(text/plain)。 - 提交:
POST /commit—— 基于容器变更创建新镜像:
POST /commit?container=44c004db4b17&comment=message&repo=myrepo HTTP/1.1
JSON 体是容器的 config(Hostname/User/CpuShares/Tty/Env/Cmd/Volumes/ExposedPorts 等,见创建容器一节)。响应 201,返回 {"Id": "596069db4bf5"}。查询参数:container(源容器)、repo、tag、comment(提交信息)、author。状态码 201 / 404 / 500。
4.5 事件流:GET /events
支持实时流式或按 since 轮询。容器事件:create, destroy, die, export, kill, pause, restart, start, stop, unpause;镜像事件:untag, delete。
GET /events?since=1374067924
{"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(轮询起点时间戳)、until(轮询终点时间戳)、filters(JSON 编码,可用 event=<string>、image=<string>、container=<string>)。200 / 500。
5. 深入:v1.16 的三个机制(Going further)
5.1 docker run 背后的 API 调用序列
原文档给出的 docker run 调用链(完整继承):
- 创建容器(
POST /containers/create); - 若返回 404,说明镜像不存在:先尝试 pull(
POST /images/create),然后重试创建容器; - 启动容器(
POST /containers/(id)/start); - 若非分离模式:attach 到容器,使用
logs=1(拿到从容器启动起的 stdout/stderr)与stream=1; - 若是分离模式或仅附加 stdin:直接显示容器 ID。
5.2 Hijacking(连接劫持)
v1.16 中 /attach 使用 hijacking 在同一条 socket 上传输 stdin、stdout、stderr。当前仓库中该机制的客户端实现在 client/hijack.go:postHijacked() 发送 POST 后接管底层连接,setupHijackConn() 负责处理服务器 hijack 时的握手(并处理 HTTP 层已缓冲数据的兼容路径);服务器侧则由 daemon/server/ 下的路由在 attach/exec start 等端点直接接管 http.Hijacker。文档同时注明该设计"未来可能变化"——事实上后续版本新增了 WebSocket 通道与会话端点,但 8 字节帧协议沿用至今(见 api/pkg/stdcopy/stdcopy.go)。
5.3 CORS 请求
要允许跨域请求访问 Remote API,以 daemon 模式运行 docker 时加上 --api-enable-cors 标志:
$ docker -d -H="192.168.1.9:2375" --api-enable-cors
6. 历史坐标:从 v1.16 看后续演进
结合 api/docs/CHANGELOG.md 与当前源码,v1.16 文档中的几处设计在后来的版本中有明确去向,阅读旧文档时需注意:
- 容器列表的
since/before查询参数:当前 client/container_list.go 中Since/Before选项标注"自 docker 1.12(API 1.24)起不再支持,请改用since/beforefilter"——v1.16 时代的独立查询参数被过滤器机制统一取代; POST /containers/{id}/copy(本文 2.9 节):CHANGELOG 记录该端点在 API v1.24 起移除并返回错误;POST /containers/start接受 HostConfig 体(本文 2.7 节):v1.24 起不再接受;LxcConf:随 LXC 执行驱动退出,在 v1.22 从 create/inspect 中移除;- 版本协商:v1.25 起 API 版本必须出现在 URL 路径中(
/v1.25/containers/json),且每个响应携带Api-Version与Docker-Experimental头。
这些演进的版本边界由 daemon/server/middleware/version.go 的中间件统一执行:客户端请求的版本低于 minAPIVersion 会得到明确的 versionUnsupportedError,而不是静默降级——这正是 v1.16 这类历史文档仍能精确复现旧行为的前提。
小结:v1.16 文档的价值在于它以最小的端点集合完整定义了"REST + 连接劫持流"的 Docker 远程控制范式——容器 CRUD 与生命周期(2.1 节)、镜像仓库交互与 tarball 格式(2.2 节)、构建/认证/事件(2.3 节)、以及 8 字节多路复用帧协议。对照当前仓库的 api/pkg/stdcopy/stdcopy.go、client/hijack.go 与 api/docs/CHANGELOG.md,可以确认这套协议的核心帧格式与调用序列延续至今,而查询参数、废弃字段等外围细节则沿着 CHANGELOG 逐版本收敛。
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