1. 引言

Docker 作为现代应用开发和部署的基石,其命令行工具是与容器交互的核心。掌握常用 Docker 命令,能极大提升开发、测试和运维效率。本文将以实战为导向,系统梳理并详解一系列高频 Docker 命令,涵盖镜像管理、容器生命周期、日志查看、文件操作等核心场景,助你快速上手 Docker 日常操作。

2. 镜像管理

镜像是容器运行的基础模板,管理镜像是 Docker 操作的第一步。

2.1 删除镜像

使用 docker rmi 命令删除本地镜像。-f 参数用于强制删除,即使有容器正在使用该镜像(慎用)。

镜像名与镜像ID:命令中的 <镜像名或ID> 可以是镜像的完整名称(如 ubuntu:22.04)、仓库名(如 nginx)或镜像ID(如 docker images 列出的短ID或长ID)。通常使用镜像名(带标签)更为直观。如果镜像存在多个标签,删除其中一个标签不会删除镜像层,只有删除最后一个标签或使用镜像ID时才会真正移除镜像数据。

# 删除指定镜像
docker rmi <镜像名或ID>
# 强制删除指定镜像
docker rmi -f <镜像名或ID>

2.2 列出镜像

docker images 用于列出本地镜像,常用组合参数如下:

# 列出所有镜像(包括中间层镜像)
docker images -a
# 只显示镜像ID
docker images -q
# 组合使用:列出所有镜像的ID
docker images -a -q
# 或简写为
docker images -aq

2.3 拉取与搜索镜像

从远程仓库获取镜像是常见操作。

# 从 Docker Hub 拉取指定镜像(默认最新标签)
docker pull <镜像名>[:标签]
# 示例:拉取 Ubuntu 22.04
docker pull ubuntu:22.04

# 在 Docker Hub 中搜索镜像
docker search <关键词>
# 示例:搜索与 Nginx 相关的镜像
docker search nginx

2.4 镜像构建与历史

除了从仓库拉取,我们还可以通过构建或提交容器来创建镜像。

从容器创建镜像 (docker commit):将当前容器的文件系统更改保存为一个新的镜像层,常用于快速保存实验状态或创建自定义镜像。

# 将正在运行的容器提交为新镜像
docker commit <容器名或ID> [新镜像名[:标签]]
# 示例:将容器 myapp 提交为镜像 myapp:v1
docker commit myapp myapp:v1
  • 提交时会包含容器的文件系统更改、环境变量、工作目录等,但不包含数据卷中的数据。
  • 通常用于临时保存状态,生产环境更推荐使用 docker build 和 Dockerfile 进行可重复构建。

从 Dockerfile 构建镜像 (docker build):这是创建自定义镜像的标准方式,通过编写 Dockerfile 定义构建步骤,确保构建过程可重复、可版本化。

# 在当前目录(包含 Dockerfile)构建镜像
docker build -t <镜像名:标签> .
# 示例:构建并标记为 myapp:latest
docker build -t myapp:latest .

# 使用 -f 参数指定 Dockerfile 路径
docker build -f <Dockerfile路径> -t <镜像名:标签> <构建上下文路径>
# 示例:使用子目录中的 Dockerfile 构建
docker build -f ./dockerfiles/Dockerfile.prod -t myapp:custom .
  • -t:为构建的镜像指定名称和标签。
  • -f:指定 Dockerfile 的路径(默认查找当前目录下的 Dockerfile 文件)。
  • .:指定构建上下文路径(通常为 Dockerfile 所在目录)。
  • Dockerfile 中每一条指令(如 FROMRUNCOPYCMD)都会生成一个镜像层。
    查看镜像构建历史 (docker history):显示镜像的构建层历史,包括每层的大小、创建命令等,有助于调试和优化镜像。
# 查看指定镜像的构建历史
docker history <镜像名或ID>
# 显示完整命令(不截断)
docker history --no-trunc <镜像名或ID>
# 仅显示镜像ID和创建命令
docker history --format "{{.ID}}\t{{.CreatedBy}}" <镜像名或ID>
  • 输出按层从最新到最旧排列。
  • 可用于检查镜像层内容、排查构建问题或优化 Dockerfile。

3. 容器生命周期管理

容器是镜像的运行实例,管理其创建、运行和停止是核心任务。

3.1 创建并运行容器

docker run 是最重要的命令之一,用于从镜像创建并启动一个新容器。

# 交互式运行一个容器
docker run -it <镜像名> <启动命令>
# 示例:运行 Ubuntu 22.04 容器并进入其 bash shell
docker run -it ubuntu:22.04 /bin/bash
  • -i:保持标准输入(STDIN)打开,允许交互。
  • -t:分配一个伪终端(pseudo-TTY)。

启动命令 (/bin/bash)/bin/bash 是容器启动后要执行的命令,它启动一个 Bash Shell 会话。-it 参数(交互式终端)与 /bin/bash 结合,使得我们能够立即进入容器的命令行环境进行交互操作。如果省略此命令,容器会使用镜像中定义的默认命令(CMD)启动,可能不会提供交互式 Shell。
数据卷挂载 (-v)-v 参数用于将主机上的目录或文件挂载到容器内部,实现数据持久化和共享。其基本语法为 -v <主机目录>:<容器内目录>

# 将主机 /home/user/data 目录挂载到容器的 /app/data 目录
docker run -it -v /home/user/data:/app/data ubuntu:22.04 /bin/bash
  • 如果容器内目录不存在,Docker 会自动创建。
  • 挂载后,数据是双向同步的:在容器内对 /app/data 的读写会直接反映到主机的 /home/user/data 目录,反之亦然。
  • 主机目录路径可以是绝对路径(如 /home/user/data)或相对路径(如 ./data),但建议使用绝对路径以避免混淆。
  • 此功能常用于配置文件、日志、数据库文件等需要持久化或与主机共享的场景。

Docker 卷 (docker volume)-v 参数使用的是绑定挂载,直接将主机目录映射到容器。Docker 还提供了更高级的(Volume)机制,用于持久化存储和容器间共享数据。卷由 Docker 管理,独立于容器的生命周期,通常存储在 /var/lib/docker/volumes/ 下,比绑定挂载更安全、更易备份和迁移。

# 创建一个名为 mydata 的卷
docker volume create mydata

# 列出所有卷
docker volume ls

# 查看卷详情
docker volume inspect mydata

# 使用卷运行容器(将卷挂载到容器内路径)
docker run -it -v mydata:/app/data ubuntu:22.04 /bin/bash

# 删除未使用的卷
docker volume prune
  • 卷 vs 绑定挂载:绑定挂载 (-v /host/path:/container/path) 依赖主机目录结构,卷 (-v volume_name:/container/path) 由 Docker 管理,不依赖主机路径。
  • 卷的优势:跨容器共享、备份恢复更方便(docker volume create/backup)、更好的性能(某些存储驱动)、更安全(避免主机路径暴露)。
  • 常用场景:数据库数据文件(如 MySQL 的 /var/lib/mysql)、应用配置文件、需要持久化的用户上传文件等。

容器间共享卷 (--volumes-from)--volumes-from 参数允许新容器挂载另一个容器已挂载的所有数据卷,实现容器间的数据共享。这在多容器应用(如 Web 应用与数据库)中非常有用,无需重复定义卷或绑定挂载。

# 创建一个使用卷的容器(源容器)
docker run -d --name app-server -v app-data:/data nginx

# 创建另一个容器,共享 app-server 的所有卷
docker run -it --volumes-from app-server ubuntu:22.04 /bin/bash
  • 工作原理:新容器会继承源容器(app-server)的所有卷挂载点,访问相同的卷数据。
  • 使用场景
    • 备份容器:创建一个临时容器,使用 --volumes-from 挂载数据卷,然后执行备份命令。
    • 数据迁移:在两个容器间迁移数据,无需通过主机中转。
    • 多服务共享配置:多个服务容器共享同一套配置文件卷。
  • 注意事项
    • 源容器无需运行,只要存在即可。
    • 共享的是卷定义,不是文件系统;每个容器对卷的读写是独立的,但数据通过卷同步。
    • 删除源容器不会自动删除共享的卷,卷的生命周期由 Docker 管理(除非使用 docker volume rm 手动删除)。

后台运行 (-d)-d 参数让容器在后台运行(detached mode),不占用当前终端。这对于运行 Web 服务器、数据库等需要长期运行的服务非常有用。

# 以后台模式运行一个 Nginx 容器
docker run -d nginx

运行后,容器会在后台启动,并返回一个容器 ID。可以使用 docker ps 查看其运行状态,使用 docker logs <容器ID> 查看其输出。

端口映射 (-p)-p 参数将主机的端口映射到容器的端口,使得外部可以通过主机 IP 和端口访问容器内服务。语法为 -p <主机端口>:<容器端口>

# 将主机的 8080 端口映射到容器的 80 端口
docker run -d -p 8080:80 nginx

运行后,在浏览器中访问 http://localhost:8080 即可看到 Nginx 的欢迎页面。可以指定多个 -p 参数来映射多个端口。

设置环境变量 (-e)-e 参数用于向容器内传递环境变量,这对于配置应用行为(如数据库连接字符串、API密钥、运行模式等)非常有用。可以多次使用 -e 来设置多个变量。

# 运行一个 MySQL 容器,并设置 root 密码和环境变量
docker run -d --name mysql-db \
  -e MYSQL_ROOT_PASSWORD=my-secret-pw \
  -e MYSQL_DATABASE=myapp \
  mysql:8.0
  • 环境变量在容器内部通过 echo $变量名 或应用代码读取。
  • 可以使用 --env-file 参数从文件批量加载环境变量。

指定容器名称 (--name)--name 参数为容器指定一个自定义名称,便于后续通过名称(而非随机生成的容器ID)来引用和管理容器。

# 运行一个 Nginx 容器,并命名为 my-web
docker run -d --name my-web -p 8080:80 nginx
  • 容器名称在宿主机上必须唯一。
  • 指定名称后,可以使用 docker stop my-webdocker logs my-web 等命令,比使用容器ID更方便。

3.2 查看容器

docker ps 用于列出容器。

# 查看正在运行的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a

3.3 启动、停止与重启容器

对于已存在的容器(无论是已停止还是正在运行),可以使用以下命令管理其运行状态。

启动容器 (docker start):启动一个已停止的容器。

# 启动一个已停止的容器
docker start <容器名或ID>
# 启动并附加到容器的输出(类似 docker run -it 的交互效果)
docker start -a <容器名或ID>
# 启动并在后台运行(默认行为)
docker start <容器名或ID>
  • 如果容器之前是以交互式模式(-it)运行的,docker start 默认在后台启动,不会自动附加终端。使用 -a(attach)参数可以连接到容器的标准输出/错误流。
  • 启动后,容器会以原来的配置(端口映射、卷挂载、环境变量等)运行。

停止容器 (docker stop):优雅地停止一个运行中的容器,发送 SIGTERM 信号,允许容器进行清理操作。

# 停止一个运行中的容器
docker stop <容器名或ID>
# 指定超时时间(秒),超时后强制停止
docker stop -t <秒数> <容器名或ID>
  • 默认超时时间为 10 秒。如果容器在超时后仍未停止,Docker 会发送 SIGKILL 强制终止。

强制停止容器 (docker kill):立即强制终止容器,发送 SIGKILL 信号。

# 强制终止容器
docker kill <容器名或ID>
# 发送指定信号
docker kill -s <信号> <容器名或ID>
  • 通常用于容器无响应或需要立即终止的场景。

重启容器 (docker restart):先停止再启动容器,相当于 docker stop 后接 docker start

# 重启容器
docker restart <容器名或ID>
  • 适用于应用配置更新后需要重启容器的场景。

暂停/恢复容器 (docker pause / docker unpause):临时冻结容器内所有进程,不释放资源;恢复后进程继续执行。

# 暂停容器
docker pause <容器名或ID>
# 恢复容器
docker unpause <容器名或ID>
  • 适用于临时节省资源或调试场景。

3.3 退出容器

在容器内部,有不同的退出方式,对容器状态影响不同:

  • 输入 exit 或按 Ctrl+D:容器内的主进程(如 bash)会终止,容器随之停止
  • Ctrl+P 然后 Ctrl+Q:从容器终端分离(detach),但容器仍在后台运行。之后可以使用 docker attach 重新连接。

3.4 查看容器进程与详情

# 查看容器内部运行的进程
docker top <容器名或ID>

# 查看容器的底层详细信息(JSON格式),包括配置、网络、数据卷等
docker inspect <容器名或ID>

3.5 进入运行中的容器

有两种主要方式进入一个正在运行的容器:

# 方式一:docker exec (推荐)
# 在运行中的容器内启动一个新的进程(通常是新的 bash 会话)
docker exec -it <容器名或ID> /bin/bash

关于启动命令/bin/bash 是常见的交互式 Shell,但并非唯一选择。<启动命令> 可以是容器内任何可执行命令,例如 /bin/sh(Alpine 镜像常用)、/bin/zsh,或直接运行特定程序如 pythonnode。关键在于容器镜像中必须包含该命令。docker exec 的本质是在容器内启动一个新进程,因此你可以执行任何容器内存在的命令。

  • exec 是“执行”的意思,会新建一个进程。这是与运行中容器交互的首选方式,更安全灵活。
# 方式二:docker attach
# 附着到容器正在运行的主进程(如最初的 bash)
docker attach <容器名或ID>
  • attach 是“附着”的意思,连接到容器启动时创建的那个主进程。如果该进程已结束或阻塞,attach 可能无法工作或直接退出导致容器停止。

核心区别exec 创建新会话,原主进程不受影响;attach 连接现有主进程,退出(如exit)会导致主进程结束,容器停止。

4. 容器与主机间文件操作

4.1 复制文件

docker cp 命令用于在容器和本地文件系统之间复制文件或目录。

# 从容器复制文件或目录到主机
docker cp <容器名或ID>:<容器内路径> <主机目标路径>
# 示例:将容器内的 /app/logs/app.log 复制到主机的 /tmp 目录
docker cp mycontainer:/app/logs/app.log /tmp/

# 从主机复制文件或目录到容器
docker cp <主机文件路径> <容器名或ID>:<容器内路径>

5. 查看容器日志

容器内应用的标准输出(STDOUT)和标准错误(STDERR)会被 Docker 捕获为日志。

# 查看容器日志
docker logs <容器名或ID>

# 实时跟踪日志输出(类似 tail -f)
docker logs -f <容器名或ID>

# 查看最后 N 行日志
docker logs --tail <行数> <容器名或ID>

# 查看特定时间戳之后的日志
docker logs --since <时间戳或时长> <容器名或ID>
# 示例:查看最近10分钟的日志
docker logs --since 10m <容器名或ID>

6. 总结

本文涵盖了从镜像拉取、删除到容器运行、交互、文件管理和日志查看的 Docker 基础命令闭环。理解 docker rundocker execdocker attach 的区别,掌握 docker psdocker logsdocker cp 等命令,是高效使用 Docker 进行日常开发和调试的关键。建议在安全的环境(如测试容器)中多加练习,形成肌肉记忆。

指令图

更多推荐