docker-run-调用链全图解 📅 2026/7/13 8:51:17 图 1分层架构总览╔══════════════════════════════════════════════════════════════════╗ ║ 用户层 ║ ║ docker run -it ubuntu bash ← 你在终端敲的命令 ║ ╚══════════════════════════════════════════════════════════════════╝ │ HTTP POST ▼ ╔══════════════════════════════════════════════════════════════════╗ ║ HTTP 路由层 daemon/server/router/ ║ ║ container/container.go 路由表URL → handler ║ ║ container/container_routes.go handler解析请求 / 序列化响应 ║ ║ container/backend.go Backend 接口合同 ║ ╚══════════════════════════════════════════════════════════════════╝ │ 调 Backend 接口方法 ▼ ╔══════════════════════════════════════════════════════════════════╗ ║ 业务层 daemon/op.g o ★ 本文档讲的就是这一层 ★ ║ ║ create.go ContainerCreate → containerCreate → create ║ ║ start.go ContainerStart → containerStart ║ ║ stop.go ContainerStop → containerStop ║ ║ ... ║ ╚══════════════════════════════════════════════════════════════════╝ │ 调底层服务 ▼ ╔══════════════════════════════════════════════════════════════════╗ ║ 底层服务 ║ ║ daemon/container/ 容器对象 状态机 ║ ║ daemon/images/ 镜像服务 ║ ║ daemon/libnetwork/ 网络libnetwork ║ ║ daemon/volume/ 卷服务 ║ ║ daemon/containerd/ containerd 客户端 ║ ╚══════════════════════════════════════════════════════════════════╝ │ gRPC / shim ▼ ╔══════════════════════════════════════════════════════════════════╗ ║ 运行时 ║ ║ containerd 容器运行时守护进程 ║ ║ └─ containerd-shim 进程级 supervisor ║ ║ └─ runc OCI runtimefork 容器进程 ║ ║ └─ Linux kernelnamespace cgroup ║ ╚══════════════════════════════════════════════════════════════════╝图 2docker run的两阶段调用链docker run在协议层是两个独立的 HTTP 请求先 create再 start。┌──────────────────────────────────────────────────────────────────────┐ │ 阶段 1docker createPOST /containers/create │ ├──────────────────────────────────────────────────────────────────────┤ │ │ │ CLI docker run ──► POST /v1.xx/containers/create │ │ │ │ │ ▼ │ │ router/container/container.go::initRoutes │ │ NewPostRoute(/containers/create, c.postContainersCreate) │ │ │ │ │ ▼ │ │ router/container/container_routes.go::postContainersCreate │ │ 解析 JSON body → ContainerCreateConfig │ │ 调 backend.ContainerCreate(ctx, config) │ │ │ │ │ ▼ │ │ daemon/create.go::ContainerCreate │ │ 加 OTel span、平台校验、默认 RestartPolicy │ │ 调 daemon.containerCreate(...) │ │ │ │ │ ▼ │ │ daemon/create.go::containerCreate │ │ verifyContainerSettings │ │ imageService.GetImage找镜像 │ │ validateNetworkingConfig │ │ 调 daemon.create(...) │ │ │ │ │ ▼ │ │ daemon/create.go::create │ │ ① newContainer 新建 *Container │ │ ② createContainerFS 准备 rootfs │ │ ③ setSecurityOptions SELinux/AppArmor │ │ ④ registerLinks 处理 --link │ │ ⑤ registerMountPoints 注册挂载点 │ │ ⑥ imageService.CreateLayer 创建可写层 │ │ ⑦ register 注册到 daemon.containers │ │ ⑧ LogContainerEvent(ActionCreate) │ │ │ │ │ ▼ │ │ 返回 {Id: abc123..., Warnings: []} │ │ │ └──────────────────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────────────────┐ │ 阶段 2docker startPOST /containers/{id}/start │ ├──────────────────────────────────────────────────────────────────────┤ │ │ │ CLI docker run ──► POST /v1.xx/containers/abc123.../start │ │ │ │ │ ▼ │ │ router/container/container.go::initRoutes │ │ NewPostRoute(/containers/{name:.*}/start, postContainersStart)│ │ │ │ │ ▼ │ │ router/container/container_routes.go::postContainersStart │ │ 解析路径参数 name │ │ 调 backend.ContainerStart(ctx, name, , ) │ │ │ │ │ ▼ │ │ daemon/start.go::ContainerStart │ │ daemon.GetContainer(name) │ │ validateState(ctr) 不能在 Dead/Paused 时启动 │ │ verifyContainerSettings 校验 hostConfig │ │ 调 daemon.containerStart(...) │ │ │ │ │ ▼ │ │ daemon/start.go::containerStart ★ 10 个阶段 ★ │ │ ① OTel span 状态守卫 │ │ ② 失败兜底 defer │ │ ③ 准备运行环境 │ │ conditionalMountOnStart │ │ initializeNetworking ← libnetwork │ │ setupContainerDirs │ │ setupMounts │ │ ④ createSpec ← 把容器配置编译成 OCI runtime spec │ │ ⑤ restart-manager / AppArmor │ │ ⑥ libcontainerd.ReplaceContainer ← 在 containerd 注册 │ │ ⑦ ctr.NewTask ← 创建 taskfork shim 进程但还没运行 │ │ ⑧ initializeCreatedTask ← 注入 cgroup / namespace │ │ ⑨ tsk.Start ★★★ 真正 fork 出容器进程 ★★★ │ │ ⑩ 状态更新 健康监控 事件上报 │ │ SetRunning(Pid, StartedAt) │ │ initHealthMonitor │ │ CheckpointTo持久化 │ │ LogContainerEvent(ActionStart) │ │ │ │ │ ▼ │ │ 返回 204 No Content │ │ │ └──────────────────────────────────────────────────────────────────────┘图 3daemon/op.go的代码骨架每个op.go都长这样记住这个骨架就能快速读懂任何文件package daemon import (...) // ╔════════════════════════════════════════════════════════════╗ // ║ 公开 API大写开头 ║ // ║ 实现 Backend 接口被 router 调用 ║ // ║ 职责参数校验 查容器 状态判断 调内部实现 ║ // ╚════════════════════════════════════════════════════════════╝ func (daemon *Daemon) ContainerXxx(ctx context.Context, name string, ...) (..., error) { // 1. 找容器按 全ID / 名字 / 短ID前缀 ctr, err : daemon.GetContainer(name) if err ! nil { return ..., err } // 2. 状态机校验用 errdefs 返回标准 typed error if !ctr.State.IsRunning() { return ..., errdefs.Conflict(errors.New(...)) } // 3. 调内部小写实现 return daemon.containerXxx(ctx, ctr, ...) } // ╔════════════════════════════════════════════════════════════╗ // ║ 内部实现小写开头 ║ // ║ 真正干活的地方可被 daemon 内部其他流程复用 ║ // ║ 职责加锁 → 调底层 → 改状态 → 持久化 → 发事件 ║ // ╚════════════════════════════════════════════════════════════╝ func (daemon *Daemon) containerXxx(ctx context.Context, ctr *container.Container, ...) (retErr error) { // 1. OTel 追踪 span可选 ctx, span : otel.Tracer().Start(ctx, daemon.containerXxx) defer func() { otelutil.RecordStatus(span, retErr) span.End() }() // 2. 容器级锁 ctr.Lock() defer ctr.Unlock() // 3. 失败回滚 defer可选用于资源清理 defer func() { if retErr ! nil { // 清理已分配的资源... } }() // 4. 业务逻辑调底层服务 tsk, err : ctr.GetRunningTask() if err ! nil { return err } if err : tsk.Xxx(ctx); err ! nil { return err } // 5. 改状态 ctr.State.Xxx true // 6. 持久化到 config.v2.json if err : ctr.CheckpointTo(ctx, daemon.containersReplica); err ! nil { log.G(ctx).WithError(err).Warn(could not save container to disk) } // 7. 上报事件docker events 能看到 daemon.LogContainerEvent(ctr, events.ActionXxx) return nil }图 4容器状态机ContainerCreate │ ▼ ┌───────────┐ │ created │ (State.Runningfalse, State.Pausedfalse) └───────────┘ │ ContainerStart ▼ ┌───────────┐ ┌────────►│ running │◄────────┐ │ └───────────┘ │ │ │ │ │ │ ContainerStop│ │ContainerPause │ │ │ │ │ ▼ ▼ │ │ ┌───────────┐ │ │ │ stopped │ │ │ └───────────┘ │ │ │ │ │ │ ContainerStart │ ContainerUnpause │ │ (重启) │ └──────────────┴─────────────────┘ │ │ ContainerRm ▼ ┌───────────┐ │ dead │ (State.Deadtrue, 已从 daemon.containers 删除) └───────────┘ 特殊状态 - restarting: 正在 restartcontainerStop containerStart 中间态 - exited: stopped 的子状态表示进程已退出有 ExitCode - paused: running 的子状态进程还活着只是被冻结图 5错误类型 → HTTP 状态码映射daemon 代码里返回 router 转换后 客户端看到 ───────────────────────────── ────────────────── ────────────── errdefs.InvalidParameter(err) → 400 Bad Request → 参数错误 errdefs.NotFound(err) → 404 Not Found → 资源不存在 errdefs.Conflict(err) → 409 Conflict → 状态冲突 errdefs.NotModified(err) → 304 Not Modified → 已经是目标状态 errdefs.System(err) → 500 Internal → daemon 内部错误 errdefs.Forbidden(err) → 403 Forbidden → 操作不被允许 errdefs.Unauthorized(err) → 401 Unauthorized → 未认证新手记法在 daemon 代码里看到errdefs.Xxx(err)就知道这条错误最终会被 router 翻译成对应的 HTTP 状态码。图 6daemon 持有的核心组件daemon/daemon.go第 100 行的Daemon结构体字段节选type Daemon struct { id string // daemon 实例 ID repository string // /var/lib/docker/containers containers container.Store // 内存中的容器表ID → *Container containersReplica *container.ViewDB // 容器快照数据库支持按前缀/名字查询 execCommands *container.ExecStore // exec 命令存储 imageService ImageService // 镜像服务 configStore atomic.Pointer[configStore] // 配置atomic 实现无锁读 statsCollector *stats.Collector // 资源指标采集 defaultLogConfig containertypes.LogConfig // 默认日志配置 registryService *registry.Service // 镜像仓库 EventsService *events.Events // 事件总线 netController *libnetwork.Controller // 网络控制器 volumes *volumesservice.VolumesService // 卷服务 root string // /var/lib/docker shutdown bool // 是否在关闭中 containerdClient *containerd.Client // containerd gRPC 客户端 containerd libcontainerdtypes.Client // containerd 抽象层 cluster Cluster // Swarm 集群 linkIndex *linkIndex // --link 索引 linkIndex *linkIndex pruneRunning atomic.Bool // prune 并发保护 CDICache *cdi.Cache // CDI 设备缓存 // ... }新手记法看到 daemon 代码里daemon.xxx就来这里查xxx是什么。图 7Backend接口的子接口分组┌──────────────────┐ │ Backend │ daemon.Daemon 实现了这个接口 └────────┬─────────┘ │ ┌────────────────┼─────────────────┬──────────────┬─────────────┐ ▼ ▼ ▼ ▼ ▼ ┌────────────┐ ┌──────────────┐ ┌────────────┐ ┌──────────┐ ┌──────────┐ │stateBackend│ │monitorBackend│ │execBackend │ │copyBackend│ │attachBack│ │ │ │ │ │ │ │ │ │ end │ │ Create │ │ Inspect │ │ ExecCreate │ │ Archive │ │ Attach │ │ Start │ │ Containers │ │ ExecStart │ │ Extract │ │ │ │ Stop │ │ Logs │ │ ExecInspect│ │ Stat │ │ │ │ Kill │ │ Stats │ │ ExecResize │ │ Export │ │ │ │ Pause │ │ Top │ │ ExecExists │ │ │ │ │ │ Unpause │ │ Changes │ │ │ │ │ │ │ │ Restart │ │ │ │ │ │ │ │ │ │ Rm │ │ │ │ │ │ │ │ │ │ Rename │ │ │ │ │ │ │ │ │ │ Update │ │ │ │ │ │ │ │ │ │ Wait │ │ │ │ │ │ │ │ │ │ Resize │ │ │ │ │ │ │ │ │ └────────────┘ └──────────────┘ └────────────┘ └──────────┘ └──────────┘ │ ▼ ┌────────────┐ ┌──────────────┐ ┌──────────────────┐ │systemBack │ │commitBackend │ │sysInfoProvider │ │ │ │ │ │ │ │ Prune │ │CreateImage │ │ RawSysInfo │ │ │ │FromContainer │ │ │ └────────────┘ └──────────────┘ └──────────────────┘图 8常见 docker 命令 → daemon 文件速查docker 命令HTTP 方法 URLhandlerdaemon 文件docker createPOST/containers/createpostContainersCreatecreate.godocker startPOST/containers/{id}/startpostContainersStartstart.godocker stopPOST/containers/{id}/stoppostContainersStopstop.godocker restartPOST/containers/{id}/restartpostContainersRestartrestart.godocker killPOST/containers/{id}/killpostContainersKillkill.godocker pausePOST/containers/{id}/pausepostContainersPausepause.godocker unpausePOST/containers/{id}/unpausepostContainersUnpauseunpause.godocker rmDELETE/containers/{id}deleteContainersdelete.godocker waitPOST/containers/{id}/waitpostContainersWaitwait.godocker psGET/containers/jsongetContainersJSONlist.godocker inspectGET/containers/{id}/jsongetContainersByNameinspect.godocker logsGET/containers/{id}/logsgetContainersLogslogs.godocker statsGET/containers/{id}/statsgetContainersStatsstats.godocker topGET/containers/{id}/topgetContainersToptop.godocker diffGET/containers/{id}/changesgetContainersChangeschanges.godocker attachPOST/containers/{id}/attachpostContainersAttachattach.godocker execPOST/containers/{id}/exec POST/exec/{id}/startpostContainerExecCreatepostContainerExecStartexec.godocker cp宿主机→容器PUT/containers/{id}/archiveputContainersArchivearchive.godocker cp容器→宿主机GET/containers/{id}/archivegetContainersArchivearchive.godocker exportGET/containers/{id}/exportgetContainersExportexport.godocker commitPOST/commitpostCommitcommit.godocker renamePOST/containers/{id}/renamepostContainerRenamerename.godocker updatePOST/containers/{id}/updatepostContainerUpdateupdate.godocker container prunePOST/containers/prunepostContainersPruneprune.godocker resizeTTYPOST/containers/{id}/resizepostContainersResizeresize.go图 9一次docker stop的完整时序CLI router daemon/op.go container containerd │ │ │ │ │ │ POST /stop │ │ │ │ ├────────────────►│ │ │ │ │ │ postContainersStop │ │ │ │ ├─────────────────────►│ │ │ │ │ │ ContainerStop │ │ │ │ ├────────────────────►│ │ │ │ │ GetContainer │ │ │ │ │◄───────────────────┤ │ │ │ │ IsRunning? │ │ │ │ │ no → 304 NotMod │ │ │ │ │ yes ↓ │ │ │ │ │ containerStop │ │ │ │ │ 1. 取 stopSignal │ │ │ │ │ 2. killWithSignal ├─────────────────►│ │ │ │ │ task.Kill(sig) │ │ │ │ 3. State.Wait(ctx,│ │ │ │ │ NotRunning) │ │ │ │ │ ◄── exit ─────┤ │ │ │ │ 4. 超时→ Kill() ├─────────────────►│ │ │ │ │ task.Kill(SIGKILL) │ │ │ 5. LogContainer │ │ │ │ │ Event(Stop) │ │ │ │ 204 No Content │ │ │ │ │◄─────────────────────┤ │ │ │ 204 │ │ │ │ │◄────────────────┤ │ │ │