Moby(Docker) Remote API v1.8 全解析容器生命周期端点、镜像管理与 hijack 流式协议【免费下载链接】mobyThe Moby Project - a collaborative project for the container ecosystem to assemble container-based systems项目地址: https://gitcode.com/GitHub_Trending/mo/moby本篇以 api/docs/v1.8.md 记载的 Remote API v1.8 为蓝本完整梳理其容器与镜像端点、查询/JSON 参数、状态码语义以及 attach 场景中经典的 8 字节头多路复用流协议并结合当前仓库中 api/pkg/stdcopy/stdcopy.go、client/hijack.go 与 容器路由 等源码还原这套 API 在 Moby 守护进程中的真实实现帮助读者既掌握 v1.8 时代的 API 全貌也理解它延续至今的底层协议机制。1. Remote API 是什么取代 rcli 的 HTTP 接口v1.8 文档开篇给出了三条核心定位这也是理解整份规范的前提Remote API 取代了 rcli在此之前客户端通过私有协议与守护进程通信v1.8 开始统一为基于 HTTP 的 REST 风格接口默认监听 Unix Socket守护进程默认监听unix:///var/run/docker.sock也可以绑定到任意 host/port 或另一个 Unix socket 上REST 为主hijack 为辅绝大多数端点是标准 REST 请求但对attach、pull这类需要传输stdin、stdout、stderr的复杂命令HTTP 连接会被“劫持hijack”在同一连接上直接透传原始字节流。当前仓库中api/目录仍然是这套 Engine API 的归属地。api/README.md 明确写道“The Engine API is an HTTP API used by the command-line client to communicate with the daemon. It can also be used by third-party software to control the daemon.” 从 v1.8 的 md 文档到 api/docs/CHANGELOG.md 记载的版本演进再到 v1.25 之后以 YAML 形式维护、由 api/swagger.yaml 生成文档的新规范见 api/docs/v1.55.yamlv1.8 正是这条演进线的早期里程碑。2. 容器端点/containers/...2.1 列出容器GET /containers/json请求支持五个查询参数示例请求为GET /containers/json?all1before8dfafdbc3a40size1 HTTP/1.1参数说明all1/True/true或0/False/false。显示全部容器默认只显示运行中的容器默认 falselimit只显示最近创建的limit个容器包含非运行状态的since只显示 Id 之后创建的容器包含非运行状态的before只显示 Id 之前创建的容器包含非运行状态的size1/True/true或0/False/false。显示容器占用大小响应为 JSON 数组每个元素包含Id、Image、Command、CreatedUnix 时间戳、Status、PortsPrivatePort/PublicPort/Type、以及SizeRw、SizeRootFs两个尺寸字段[ { 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 } ]状态码200无错误400参数错误500服务端错误。2.2 创建容器POST /containers/createv1.8 的创建接口把所有配置容器级配置都放在请求体 JSON 中示例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: {}} }请求体 JSON 参数参数说明Hostname容器主机名User用户名或 UIDMemory内存限制字节CpuSharesCPU 权重相对权重AttachStdin是否附加标准输入默认 falseAttachStdout是否附加标准输出默认 falseAttachStderr是否附加标准错误默认 falseTty是否分配伪终端pseudo-tty默认 falseOpenStdin即使未附加也保持 stdin 打开默认 false查询参数name—— 为容器指定名称必须匹配/?[a-zA-Z0-9_-]。成功时返回201 Created并给出容器短 Id 与告警HTTP/1.1 201 Created Content-Type: application/json { Id:e90e34656806, Warnings:[] }状态码201无错误404容器不存在406无法附加容器未运行500服务端错误。2.3 检查容器GET /containers/(id)/json返回容器的底层详细信息包括完整 Id、创建时间、入口Path/Args、创建时的Config快照、StateRunning、Pid、ExitCode、StartedAt、Ghost、镜像 Id、NetworkSettingsIpAddress、IpPrefixLen、Gateway、Bridge、PortMapping以及宿主侧的HostConfigBinds、PortBindings、Links、Privileged等。文档示例响应节选{ Id: 4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2, Created: 2013-05-07T14:51:42.04184702:00, Path: date, Args: [], Config: { Hostname: 4fa6e0f0c678, User: , Memory: 0, AttachStdin: false, AttachStdout: true, AttachStderr: true, Tty: false, Cmd: [date], Image: base, Volumes: {}, VolumesFrom: , WorkingDir: }, State: { Running: false, Pid: 0, ExitCode: 0, StartedAt: 2013-05-07T14:51:42.08765802:00, Ghost: false }, Image: b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc, NetworkSettings: { IpAddress: , IpPrefixLen: 0, Gateway: , Bridge: , PortMapping: null }, HostConfig: { Binds: null, ContainerIDFile: , LxcConf: [], Privileged: false, PortBindings: { 80/tcp: [ { HostIp: 0.0.0.0, HostPort: 49153 } ] }, Links: null, PublishAllPorts: false } }状态码200无错误404无此容器500服务端错误。2.4 观察容器top、changes、export列出容器内进程GET /containers/(id)/top查询参数ps_args指定 ps 参数如aux。响应含Titles列头与Processes二维数组{ 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] ] }查看文件系统变更GET /containers/(id)/changes返回Path与Kind组成的数组Kind为变更类型编码如示例中 0/1[ { Path: /dev, Kind: 0 }, { Path: /dev/kmsg, Kind: 1 }, { Path: /test, Kind: 1 } ]导出容器GET /containers/(id)/export返回application/octet-stream的 TAR 流。三个端点的状态码一致200 / 404无此容器/ 500。2.5 生命周期控制start / stop / restart / kill值得注意的是v1.8 时代的start 接口还承载了宿主侧配置——POST /containers/(id)/start的请求体可以包含Binds、LxcConf、PortBindings、PublishAllPorts、Privileged等字段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 }各字段语义Binds创建绑定挂载host-path:container-path:rw|ro容器路径不存在则新建卷LxcConf自定义 lxc 选项键值对PortBindings暴露端口并可指定宿主端口PublishAllPorts发布所有暴露端口默认 falsePrivileged授予扩展权限默认 false。成功返回204 No Content。其余三个控制端点形态类似StopPOST /containers/(id)/stop查询参数t为等待秒数超时后强制 kill例如POST /containers/e90e34656806/stop?t5RestartPOST /containers/(id)/restart同样支持t参数KillPOST /containers/(id)/kill直接终止容器。三者均返回204成功/** 404**无此容器/** 500**服务端错误。2.6 附加到容器POST /containers/(id)/attach与多路复用流协议这是 v1.8 中最具协议深度的端点。示例请求与响应POST /containers/16253994b7c4/attach?logs1stream0stdout1 HTTP/1.1 HTTP/1.1 200 OK Content-Type: application/vnd.docker.raw-stream {{ STREAM }}查询参数参数说明logs返回日志默认 falsestream返回实时流默认 falsestdinstreamtrue时附加 stdin默认 falsestdoutlogstrue时返回 stdout 日志streamtrue时附加 stdout默认 falsestderr同 stdout但作用于 stderr默认 false状态码200无错误400参数错误404无此容器500服务端错误。流帧格式Stream details若创建容器时启用了 TTY流就是进程 PTY 的原始数据若未启用 TTY流会把 stdout 与 stderr多路复用为带帧头的字节流。帧 HEADERPAYLOAD头部固定 8 字节header : [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}第 1 字节STREAM_TYPE0 stdin读取时写到 stdout、1 stdout、2 stderr第 5~8 字节为 payload 大小uint32大端编码payload 为原始流数据。文档给出的最简实现步骤1. 读 8 字节头2. 按第 1 字节判断 stdout/stderr3. 从后 4 字节解出帧大小4. 读取该大小的数据并写到对应输出5. 回到第 1 步。这套协议至今仍在仓库中生效。api/pkg/stdcopy/stdcopy.go 中的StdCopy就是该协议的去复用实现stdWriterPrefixLen 8、stdWriterFdIndex 0、stdWriterSizeIndex 4用binary.BigEndian.Uint32读取帧大小并把Stdin类型0与Stdout一样写到 stdout——与 v1.8 文档逐字对应。当前实现还在此基础上增加了Systemerr 3类型用于传递守护进程侧错误但 v1.8 文档描述的 0/1/2 三种类型完全保留。服务端对应实现见 daemon/server/router/container/container_routes.go 的postContainersAttach它断言http.ResponseWriter实现http.Hijacker调用hijacker.Hijack()拿到裸连接后自行写出HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream响应头——正是文档中application/vnd.docker.raw-stream这一内容类型的来源。2.7 WebSocket 版本GET /containers/(id)/attach/wsv1.8 同时提供了 WebSocket 变体按 RFC 6455 握手示例GET /containers/e90e34656806/attach/ws?logs0stream1stdin1stdout1stderr1 HTTP/1.1查询参数与状态码与 2.6 的 attach 完全一致200 / 400 / 404 / 500。在当前仓库中该路由仍注册于 daemon/server/router/container/container.go/containers/{name:.*}/attach/ws与 POST 版 attach 并列存在。2.8 等待、删除与复制WaitPOST /containers/(id)/wait阻塞直到容器停止返回退出码{StatusCode: 0}。状态码 200/404/500。RemoveDELETE /containers/(id)查询参数v1/True/true或0/False/false默认 false为是否同时删除关联卷。状态码204成功400参数错误404无此容器500服务端错误。CopyPOST /containers/(id)/copyv1.8 采用 POST 请求体形式指定资源返回 TAR 流POST /containers/4fa6e0f0c678/copy HTTP/1.1 Content-Type: application/json { Resource: test.txt }状态码 200/404/500。3. 镜像端点/images/...3.1 列出镜像GET /images/json示例GET /images/json?all0响应元素含RepoTags、Id、Created、Size、VirtualSize带ParentId的条目表示上层镜像[ { 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 } ]3.2 创建镜像POST /images/createpull / import 二合一该端点既可从 registry 拉取也可从源导入。查询参数参数说明fromImage要拉取的镜像名fromSrc导入来源-表示 stdinrepo仓库名tag标签registry要拉取的 registry请求头X-Registry-Auth—— base64 编码的 AuthConfig 对象用于私有仓库认证。响应是一个进度消息流JSON 行序列例如{status: Pulling...} {status: Pulling, progress: 1 B/ 100 B, progressDetail: {current: 1, total: 100}} {error: Invalid...}状态码200成功、500服务端错误。这套status/progress/error的流式消息格式在后续版本中被stream/id/aux等字段取代但其“逐行 JSON 汇报进度”的思想一以贯之。3.3 向镜像插入文件POST /images/(name)/insert把url处的文件插入镜像name的path位置例如POST /images/test/insert?path/usrurlmyurl响应同样是带progress/progressDetail的进度流。状态码 200/500。该端点在后续 API 版本中被移除属于 v1.8 时代特有的端点。3.4 检查、历史、推送、打标签、删除、搜索InspectGET /images/(name)/json返回id、parent、created、container、container_config创建该层所用容器的完整配置快照含Cmd、Tty、OpenStdin等与Size。状态码 200/404/500。HistoryGET /images/(name)/history返回各层Id、Created、CreatedBy如/bin/bash。状态码 200/404/500。PushPOST /images/(name)/push请求头携带 base64 编码的X-Registry-Auth响应为 Pushing 进度流。状态码 200/404/500。TagPOST /images/(name)/tag查询参数repo目标仓库、force默认 false、tag新标签名例如POST /images/test/tag?repomyrepoforce0tagv42。状态码201成功400参数错误404无此镜像409冲突500服务端错误。RemoveDELETE /images/(name)返回Untagged/Deleted事件数组[ {Untagged: 3e2f21a89f}, {Deleted: 3e2f21a89f}, {Deleted: 53b4f83ac9} ]状态码 200/404/409/500。SearchGET /images/search查询参数term在 Docker Hub 上搜索。文档特别注明响应键名在 v1.6 之后已变更改为直接透传 registry 服务器返回的 JSONdescription、is_official、is_trusted、name、star_count状态码 200/500。4. 其他端点Misc4.1 从 Dockerfile 构建POST /build请求体是tar 压缩包流支持 identity不压缩、gzip、bzip2、xz 四种算法归档根目录必须包含名为Dockerfile的文件可附带任意构建上下文文件供ADD指令引用。响应为构建进度流{stream: Step 1...} {stream: ...} {error: Error..., errorDetail: {code: 123, message: Error...}}查询参数t成功时应用到结果镜像的仓库名和可选标签、remote构建源 URIgit 或 HTTPS/HTTP、q静默输出、nocache不使用构建缓存。请求头Content-type应为application/tarX-Registry-Auth为 base64 编码的 AuthConfig。状态码 200/500。4.2 认证校验POST /auth提交username/password/email/serveraddress四字段校验凭据成功返回 200 或 204无响应体500 为服务端错误。4.3 系统信息GET /info与版本GET /version/info返回守护进程全局状态v1.8 示例字段{ Containers:11, Images:16, Debug:false, NFd: 11, NGoroutines:21, MemoryLimit:true, SwapLimit:false, IPv4Forwarding:true }/version返回Version、GitCommit、GoVersion。两者状态码均为 200/500。4.4 提交镜像POST /commit把容器变更固化为新镜像查询参数container源容器、repo、tag、m提交说明、author、run运行期自动应用的配置如{Cmd: [cat, /world], PortSpecs:[22]}。示例POST /commit?container44c004db4b17mmessagerepomyrepo HTTP/1.1 HTTP/1.1 201 OK Content-Type: application/vnd.docker.raw-stream {Id: 596069db4bf5}状态码 201/404/500。4.5 事件流GET /events以流式或轮询since时间戳方式获取事件。v1.8 中容器报告create, destroy, die, export, kill, pause, restart, start, stop, unpause镜像报告untag, delete{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。4.6 镜像 tarballGET /images/(name)/get、POST /images/load与格式定义get导出仓库全部镜像与标签的 tarballapplication/x-tar二进制流load把 tarball 载入本地仓库两者互为逆操作。文档明确了image tarball 格式每个镜像层一个以长 Id 命名的目录内含三个文件VERSION文件格式版本当前为1.0json层的详细信息类似docker inspect layer_id的输出layer.tar该层的文件系统变更 tar 包其中用 aufs 风格的.wh..wh.aufs文件/目录记录属性变更与删除若 tarball 定义了仓库根目录还会有repositories文件将仓库/标签名映射到层 Id{hello-world: {latest: 565a9d68a73f6706862bfe8409a7f659776d4d60a8d096eb4a3cbce6999cc2a1} }状态码均为 200/500。5.docker run的底层调用序列文档 “Going further” 一节给出了 v1.8 时代客户端如何组合上述端点实现docker run这也是理解 API 组装关系的最佳范例创建容器POST /containers/create若返回404说明镜像不存在——先执行pullPOST /images/create再重试创建容器启动容器POST /containers/(id)/start;非分离模式下以logs1stream1附加到容器POST /containers/(id)/attach从而拿到容器启动以来的 stdout/stderr分离模式或仅附加 stdin 时直接打印容器 Id。6. Hijack 机制与 CORSv1.8 的两条特殊通道Hijacking。v1.8 明确写道/attach使用 hijacking 在同一 socket 上传输 stdin、stdout、stderr且“未来可能改变”。客户端侧的实现可见 client/hijack.gosetupHijackConn在请求中设置Connection: Upgrade与Upgrade头、对 TCP 连接开启 30 秒 KeepAlive避免长静默命令触发 ECONNTIMEOUT随后等待服务端的101 Switching Protocols响应拿到裸连接client/container_attach.go 等文件则基于postHijacked发起 attach/exec 请求。服务端侧则如 2.6 节所述由路由层完成Hijacker.Hijack()并手写响应头。这一“客户端发起 Upgrade、服务端握手后接管连接”的对称设计正是 v1.8 文档中 hijack 描述的具体落地。CORS Requests。v1.8 通过守护进程参数开启跨域访问示例$ docker -d -H192.168.1.9:2375 --api-enable-cors即在 daemon 模式下附加--api-enable-cors标志把远程 API 暴露到192.168.1.9:2375这类 TCP 端点。从当前仓库的守护进程参数定义如 daemon/config 包看早期这类docker -d -H的顶层参数已被-H/--host等 dockerd 启动选项取代但“API 默认走 Unix socket、TCP 暴露需显式绑定”这一安全基线始终未变。7. 如何阅读这份历史文档与当前代码api/docs/v1.8.md 是 api/docs/ 目录中按 API 版本归档的历史规范之一与 api/docs/CHANGELOG.md 构成版本演进索引。阅读它时有三点实用结论端点路径基本稳定/containers/json、/containers/{id}/start|stop|attach、/images/json、/build、/events等路径从 v1.8 一直沿用至今在 api/docs/v1.55.yaml 等新版规范与 api/swagger.yaml 中均可找到同名路径请求体结构发生了大迁移v1.8 中 start 携带的Binds/PortBindings等宿主配置在后续版本被拆分到独立的HostConfigcreate 接口的请求体也随之重构——对照 api/types/container 包中的HostConfig类型即可看到演进结果流式协议原封保留8 字节帧头STREAM_TYPE 3 字节保留 大端 uint32 长度与application/vnd.docker.raw-stream媒体类型从 v1.8 文档、到 api/pkg/stdcopy/stdcopy.go 的StdCopy/NewStdWriter、再到 daemon/server/router/container/container_routes.go 的 attach 处理函数是完全一致的三代证据链。综上掌握 v1.8 这份文档不仅是在读一段 API 历史它把容器端点的参数语义、镜像 tarball 的二进制格式、以及贯穿至今的 hijack stdcopy 流协议一次性讲透是理解 Moby Engine API 设计基因的最短路径。【免费下载链接】mobyThe Moby Project - a collaborative project for the container ecosystem to assemble container-based systems项目地址: https://gitcode.com/GitHub_Trending/mo/moby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考