- 容器运行时
- 云原生
【免费下载链接】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:
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_containermy_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 -adocker 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 会进入"挂接启动"分支,其关键流程如下:
单容器限制:挂接模式下只允许启动一个容器,若同时传入多个容器,CLI 直接报错
you cannot start and attach multiple containers at once(start.go)。先 inspect 后 attach:CLI 先通过
ContainerInspect查询容器详情(拿到容器 ID 与Config.Tty等配置),再发起 attach。若容器未启用 TTY(!c.Config.Tty),CLI 会启动信号转发协程ForwardAllSignals,将本地终端的信号转发给容器进程(start.go)。构造挂接请求:
ContainerAttachOptions中,Stdin取值为opts.openStdin && c.Config.OpenStdin,即--interactive生效的前提是容器在创建时已配置OpenStdin(例如docker run -i创建的容器);Stdout/Stderr恒为true(start.go)。hijacked 流式传输:attach 响应通过
hijackedIOStreamer在 CLI 的 stdin/stdout/stderr 与容器之间进行双向流式数据传输(start.go)。等待退出与移除:
waitExitOrRemoved并行监听容器退出状态。对于 API 1.30 及以上版本,使用ContainerWait等待NextExit(或Removed)条件;对于更老的 daemon,则退化为通过 Events API 监听die、detach、destroy事件获取退出码(utils.go)。TTY 尺寸同步:若容器启用了 TTY 且当前 CLI 输出是终端,
MonitorTtySize会持续同步本地终端窗口尺寸(start.go)。退出码透传:挂接模式下,容器退出码会作为
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):
- 命令行覆盖:
--detach-keys选项直接写入 CLI 的配置对象dockerCli.ConfigFile().DetachKeys; - 配置文件默认值:如果命令行未指定,则使用配置文件中的
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命令虽然直观,但其背后是一整套完整的请求链路。梳理这条链路有助于理解命令行为与故障排查方向:
CLI 命令层:
runStart依据选项选择三条分支(start.go):--attach/--interactive→ 挂接启动分支(如前文所述);--checkpoint→ 恢复分支;- 其余情况 → 批量启动分支(
startContainersWithoutAttachments)。
Go SDK 客户端层:
dockerCli.Client().ContainerStart(ctx, container, options)构造 HTTP POST 请求。CheckpointID/CheckpointDir会作为checkpoint、checkpoint-dir查询参数拼接到 URL 中,最终请求POST /containers/{id}/start(container_start.go)。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阶段固化。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:
相关推荐
深入解析 Docker CLI 的 `docker attach` 命令:用法、参数与源码实现
深入解析 Docker CLI 的 docker attach 命令:用法、参数与源码实现 docker attach 是 Docker CLI 中用于将本地标
CLI开发工具Docker CLI 插件升级实战:`docker plugin upgrade` 命令用法与源码原理深度解析
Docker CLI 插件升级实战: docker plugin upgrade 命令用法与源码原理深度解析 本篇技术指南以 Docker CLI 官方参考文档
CLI开发工具Docker CE `docker logs` 命令完全指南:从基础用法到源码级日志读取原理
Docker CE docker logs 命令完全指南:从基础用法到源码级日志读取原理 docker logs 是 Docker CE 中最常用的容器运维命令
容器运行时云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考