☰
Docker CE `docker start` 命令深度解析:用法、参数与源码级实现原理
2026/10/12 2:01:44 网站建设 项目流程
  • 容器运行时
  • 云原生

【免费下载链接】docker-ce

:warning: This repository is deprecated and will be archived (Docker CE itself is NOT deprecated) see the https://github.com/docker/docker-ce/blob/master/README.md :warning:

项目地址:https://gitcode.com/gh_mirrors/do/docker-ce
点击查看免费下载

docker start是 Docker CE 中用于启动一个或多个已停止(stopped)容器的基础命令,与docker run不同,它不会创建新容器,而是重新运行既有容器中已配置的进程。本文以 start.md 官方参考文档为主体,结合 docker-ce 仓库中 CLI 与 engine 的源码实现,系统讲解docker start的完整用法、参数语义、前台挂载(attach)模式、分离键(detach keys)配置以及从命令行到守护进程(daemon)的底层调用链,帮助读者在掌握命令实操的同时,理解其内部工作机制与常见错误处理逻辑。

命令概览与核心语法

docker start的完整语法定义在 CLI 源码 start.go 中:

Usage: docker start [OPTIONS] CONTAINER [CONTAINER...] Start one or more stopped containers Options: -a, --attach Attach STDOUT/STDERR and forward signals --detach-keys string Override the key sequence for detaching a container --help Print usage -i, --interactive Attach container's STDIN

在源码实现中,命令通过cobra.Command注册,其Use字段为start [OPTIONS] CONTAINER [CONTAINER...],Short描述为Start one or more stopped containers。参数校验使用cli.RequiresMinArgs(1)(见 required.go),即至少传入一个容器 ID 或名称,否则命令会报错并提示用法。这一设计与docker run只需一个容器不同,docker start天然支持一次操作多个容器。

需要特别说明的是,docker start面向的对象是已停止的容器(状态为exited)。正在运行的容器、已暂停(paused)的容器、正在移除或已处于 dead 状态的容器都无法被启动,具体校验逻辑将在后文「daemon 端状态校验」一节展开。

基础用法:启动单个或多个已停止容器

启动单个容器

官方参考文档给出的最简示例:

$ docker start my_container

my_container是容器的名称(也可以使用容器 ID 或 ID 前缀)。命令成功执行后,CLI 会在标准输出打印该容器的名称或 ID,作为启动成功的确认。

同时启动多个容器

由于语法中支持CONTAINER [CONTAINER...],可以一次启动多个容器:

$ docker start web_server db_server redis_cache web_server db_server redis_cache

多个容器逐个、顺序发起启动请求。从源码实现看(start.go 的startContainersWithoutAttachments),CLI 遍历容器列表,对每个容器调用ContainerStart;启动成功的容器名称会被打印到标准输出,而启动失败的容器名称会被记录,最终返回一条汇总错误:

Error: failed to start containers: <失败容器名列表>

这意味着当你批量启动时,即便某个容器因状态异常启动失败,其余容器依然会被正常启动,最终的错误信息会明确列出失败名单,便于排查。

前置条件:容器必须是 stopped 状态

docker start只能启动已停止的容器,因此在使用前通常先通过以下命令确认容器状态:

$ docker ps -a

docker ps -a会列出包括 exited 在内的全部容器。容器进入 stopped 状态的常见途径包括:

  • docker stop/docker kill主动停止;
  • docker run启动的进程自然退出(exit);
  • 主机重启后未配置--restart策略而停止的容器。

docker start与docker run的本质区别在于:run是"创建 + 启动"新容器,而start是"复用 + 重启"既有容器,后者不会重新解析docker run的参数,而是使用容器创建时固化在配置中的设置(镜像、命令、端口映射、卷、网络等)。

前台模式:--attach与--interactive

默认情况下,docker start在后台启动容器后立即返回。如果你希望像docker attach那样重新挂接到容器的标准输出/错误流,并转发本地信号,则需要使用-a, --attach选项;若容器进程需要从标准输入接收交互指令,可配合-i, --interactive选项挂接 STDIN。

选项语义

选项完整形式作用
-a--attach挂接容器的 STDOUT/STDERR,并转发本地信号(如 Ctrl+C)到容器
-i--interactive挂接容器的 STDIN,允许向容器进程交互式输入

典型交互场景示例——启动一个之前以交互模式创建、现已退出的容器:

$ docker start -a -i my_container

这会同时挂接标准输入输出,使容器前台运行、直接接收键盘输入。

源码中的 attach 流程

从 start.go 的runStart实现可以看出,当指定了--attach或--interactive时,CLI 会进入"挂接启动"分支,其关键流程如下:

  1. 单容器限制:挂接模式下只允许启动一个容器,若同时传入多个容器,CLI 直接报错you cannot start and attach multiple containers at once(start.go)。

  2. 先 inspect 后 attach:CLI 先通过ContainerInspect查询容器详情(拿到容器 ID 与Config.Tty等配置),再发起 attach。若容器未启用 TTY(!c.Config.Tty),CLI 会启动信号转发协程ForwardAllSignals,将本地终端的信号转发给容器进程(start.go)。

  3. 构造挂接请求:ContainerAttachOptions中,Stdin取值为opts.openStdin && c.Config.OpenStdin,即--interactive生效的前提是容器在创建时已配置OpenStdin(例如docker run -i创建的容器);Stdout/Stderr恒为true(start.go)。

  4. hijacked 流式传输:attach 响应通过hijackedIOStreamer在 CLI 的 stdin/stdout/stderr 与容器之间进行双向流式数据传输(start.go)。

  5. 等待退出与移除:waitExitOrRemoved并行监听容器退出状态。对于 API 1.30 及以上版本,使用ContainerWait等待NextExit(或Removed)条件;对于更老的 daemon,则退化为通过 Events API 监听die、detach、destroy事件获取退出码(utils.go)。

  6. TTY 尺寸同步:若容器启用了 TTY 且当前 CLI 输出是终端,MonitorTtySize会持续同步本地终端窗口尺寸(start.go)。

  7. 退出码透传:挂接模式下,容器退出码会作为docker start命令自身的退出码返回(cli.StatusError{StatusCode: status},见 start.go)。因此docker start -a非常适合在脚本中判断容器进程的执行结果。

信号转发细节

ForwardAllSignals(signals.go)会将本地收到的所有信号通过ContainerKill转发给容器,但有三个例外被过滤掉:

  • SIGCHLD与SIGPIPE:属于 CLI 自身运行机制的信号,不转发;
  • 运行时信号(如 Go 1.14+ 的SIGURG,用于支持可抢占系统调用):同样不转发;
  • 信号名映射查不到的信号:直接忽略。

这一机制使得用户在挂接状态下按 Ctrl+C 时,信号可以传递到容器内主进程(容器以 TTY 模式运行时更常见的行为),保证前后台交互体验与docker attach一致。

分离键序列:--detach-keys

docker start -a挂接容器后,默认可以通过CTRL-p CTRL-q分离键序列脱离容器而不停止它。当该默认序列与本地其他应用冲突时,可用--detach-keys覆盖:

$ docker start -a --detach-keys ctrl-a my_container

--detach-keys接受单个字母,或ctrl-<value>形式的组合键,其中<value>支持:a-z(单个小写字母)、@(@ 符号)、[(左方括号)、\\(两个反斜杠)、_(下划线)、^(脱字符)。合法的键序列示例包括a、ctrl-a、X、ctrl-\等。该语法说明详见 man 文档 attach.md。

从源码实现看,CLI 支持两种设置方式(start.go):

  1. 命令行覆盖:--detach-keys选项直接写入 CLI 的配置对象dockerCli.ConfigFile().DetachKeys;
  2. 配置文件默认值:如果命令行未指定,则使用配置文件中的detachKeys字段(file.go)。该字段存在于 Docker CLI 配置文件中(默认位置为~/.docker/config.json),可以设置全局默认分离键。

分离键最终会随 attach 请求发送给 daemon(ContainerAttachOptions.DetachKeys),当用户在挂接状态下按下该键序列时,会触发term.EscapeError,CLI 将其识别为"用户主动脱离",正常返回且不报错(start.go)。

实验性选项:checkpoint 与 checkpoint-dir

docker start还支持两个实验性选项(当前文档的--help输出中未列出,但源码中已注册,见 start.go):

选项作用标注
--checkpoint string从指定 checkpoint 恢复容器experimental、仅 Linux
--checkpoint-dir string使用自定义 checkpoint 存储目录experimental、仅 Linux

使用时需要 daemon 开启实验模式(experimental: true),否则 daemon 端会返回错误checkpoint is only supported in experimental mode(见 daemon/start.go)。

当指定--checkpoint时,同样只允许操作单个容器(you cannot restore multiple containers at once),且该分支不会挂接终端(start.go)。此外,从 daemon 实现看,checkpoint-dir目前会返回custom checkpointdir is not supported(daemon/start.go),因此实际使用中通常只依赖--checkpoint。

源码级调用链:从 CLI 到 daemon 的完整旅程

docker start命令虽然直观,但其背后是一整套完整的请求链路。梳理这条链路有助于理解命令行为与故障排查方向:

  1. CLI 命令层:runStart依据选项选择三条分支(start.go):

    • --attach/--interactive→ 挂接启动分支(如前文所述);
    • --checkpoint→ 恢复分支;
    • 其余情况 → 批量启动分支(startContainersWithoutAttachments)。
  2. Go SDK 客户端层:dockerCli.Client().ContainerStart(ctx, container, options)构造 HTTP POST 请求。CheckpointID/CheckpointDir会作为checkpoint、checkpoint-dir查询参数拼接到 URL 中,最终请求POST /containers/{id}/start(container_start.go)。

  3. API Server 路由层:engine 侧将路由注册为POST /containers/{name:.*}/start(container.go),处理器为postContainersStart。该处理器解析checkpoint与checkpoint-dir表单参数后调用后端ContainerStart,成功时返回204 No Content(container_routes.go)。注意:自 API v1.24 起,start 请求体中不再允许携带 hostConfig(bodyOnStartError,见 container_routes.go),所有运行配置都应在docker run/docker create阶段固化。

  4. daemon 后端层:Daemon.ContainerStart执行状态校验后调用containerStart,后者完成存储、网络、cgroup 等运行环境准备,最终向容器进程发出启动信号(daemon/start.go)。

daemon 端状态校验与常见错误

docker start最常遇到的失败都源于容器状态不满足启动条件。daemon 的校验逻辑集中在 daemon/start.go:

容器状态处理错误信息
Paused(已暂停)拒绝启动cannot start a paused container, try unpause instead
Running(运行中)拒绝重复启动返回containerNotModifiedError(提示容器已在运行)
RemovalInProgress(移除中)拒绝启动container is marked for removal and cannot be started
Dead(已死)拒绝启动container is marked for removal and cannot be started

因此,实际排查时可遵循以下顺序:

$ docker ps -a # 查看容器状态 $ docker inspect <container> # 查看详细状态字段(State.Status / State.Paused) $ docker unpause <container> # 若为 paused 状态,先解除暂停

另外两类值得注意的边界行为:

  • --rm容器与自动移除:若容器以--rm创建,启动失败时 daemon 会继续等待容器被移除,CLI 端通过waitExitOrRemoved与c.HostConfig.AutoRemove配合,确保挂接模式下的等待/移除流程正确收尾(start.go)。
  • hostConfig 不再支持:向已停止容器补充 hostConfig 的做法在 Linux 上已标记为废弃(Docker 1.12 起移除),Windows 上则直接拒绝。所有主机配置必须在docker create/docker run时指定(daemon/start.go)。

实战要点小结

  • 后台重启:docker start my_container是最常用形式,适合重启退出状态的容器并立即返回;
  • 前台观察输出:docker start -a my_container可重新观察容器 stdout/stderr,信号会实时转发;
  • 交互式会话恢复:docker start -a -i my_container可恢复交互式终端(前提是容器创建时启用了-i/-t);
  • 脚本内判断结果:docker start -a会把容器退出码透传为命令退出码,便于自动化流程捕获执行结果;
  • 批量启动:docker start c1 c2 c3顺序启动多个容器,单个失败不影响其他容器;
  • 自定义分离键:--detach-keys ctrl-x可解决默认CTRL-p CTRL-q的键位冲突,也可通过~/.docker/config.json的detachKeys字段设置全局默认值。

延伸阅读

  • 命令参考文档原文:start.md
  • CLI 命令实现:start.go
  • 等待退出/移除辅助逻辑:utils.go
  • 信号转发实现:signals.go
  • SDK 客户端实现:container_start.go
  • API Server 路由注册与处理器:container.go、container_routes.go
  • daemon 端启动逻辑:daemon/start.go
  • 分离键序列说明:attach.md、配置文件detachKeys字段定义:file.go
  • 容器运行时
  • 云原生

【免费下载链接】docker-ce

:warning: This repository is deprecated and will be archived (Docker CE itself is NOT deprecated) see the https://github.com/docker/docker-ce/blob/master/README.md :warning:

项目地址:https://gitcode.com/gh_mirrors/do/docker-ce
点击查看免费下载
上一篇:Ice macOS 菜单栏管理教程:3步搞定,把挤满图标的状态栏变清爽
下一篇:3个简单步骤:用JavaScript让手机自动工作,告别重复点击

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询