Docker 容器命令深度解析:从docker run到docker ps的精通之路
在当今云原生和 DevOps 浪潮中,Docker 已成为应用容器化的事实标准。它通过将应用及其依赖打包进轻量、可移植的容器中,彻底改变了软件的开发、交付和运维方式。对于每一位希望驾驭这门技术的开发者或系统管理员来说,熟练掌握其核心命令行工具是至关重要的一步。
本文将以您提供的学习笔记为蓝本,深入挖掘其中每一个知识点,为您呈现一篇详尽的 Docker 核心命令教程。我们将不仅解释“如何做”,更会阐述“为什么这么做”,并确保笔记中的每一张截图都能在文中找到其精准的定位与诠释。让我们一起踏上从入门到精通的 Docker 命令行之旅。
第一章:docker run — 容器生命周期的起点
docker run 命令是 Docker 中最核心、最强大的命令,没有之一。它集创建与启动于一身,是赋予镜像生命、使其成为一个运行中容器的魔法咒语。它的基本语法结构清晰明了:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
- [OPTIONS]: 配置项,用于精细化控制容器的各种运行时行为,如网络、资源、命名等。
- IMAGE: 镜像,创建容器的模板或蓝图。
- [COMMAND] [ARG…]: 可选项,用于覆盖镜像中定义的默认启动命令。
接下来,我们将逐一深入探讨那些至关重要的 [OPTIONS] 参数。
1.1 容器的运行模式:前台与后台 (-it, -d)
在运行一个容器时,首要问题便是决定它与我们终端的交互方式。
理解容器为何会自动退出
在深入参数之前,我们必须先理解一个常见现象。首先,按照笔记中的操作,我们将 centos:7 镜像拉取到本地:
docker pull centos:7
然后,尝试不带任何参数直接运行它:
docker run centos:7
执行后,你会发现终端几乎没有任何输出,然后命令就结束了。这是否意味着容器创建失败了?我们来验证一下。

上图展示了docker run centos:7命令执行后立即返回终端提示符,似乎什么也未发生。
使用 docker ps 命令可以查看当前正在运行的容器:
docker ps

docker ps 的输出为空,证明当前没有任何容器在运行。
这引出了一个核心概念:容器的生命周期与其内部运行的主进程绑定。centos:7 镜像的默认命令是启动一个 Bash shell。当我们执行 docker run centos:7 时,Docker 在后台创建并启动了一个容器,然后在容器内执行了 bash 命令。但由于我们没有为这个 shell 提供一个交互式的终端(TTY),也未给它任何需要执行的任务,这个 bash 进程发现无事可做,便立即退出了。主进程一旦退出,容器的使命便宣告完成,其状态也就变成了“已退出(Exited)”。
为了看到这些“昙花一现”的容器,我们需要给 docker ps 命令加上 -a 参数,它会显示所有容器,包括已停止的。
docker ps -a

使用 -a 参数后,我们清楚地看到,刚刚创建的容器确实存在过,其状态为 Exited。
后台运行模式 (-d)
对于需要长时间运行的服务,如 Web 服务器或数据库,我们显然不希望它占用我们的终端。这时,-d(--detach)参数就派上了用场。它会让容器在后台以“守护进程”的方式运行。
让我们尝试以后台模式运行一个能持续运行的命令,例如一个无限循环的 shell 脚本:
docker run -d centos:7 /bin/sh -c "while true; do echo hello world; sleep 1; done"

执行 -d 参数后,命令不再阻塞终端,而是立即返回了一长串字符,这就是新创建容器的完整 ID。
现在,再次查询运行中的容器:
docker ps

可以看到,我们的 CentOS 容器现在正稳定地在后台运行,状态为 Up。
交互模式 (-i 与 -t)
与后台模式相对的是前台交互模式,这对于需要进入容器内部进行操作的场景至关重要,例如调试或执行临时命令。这通常由 -i 和 -t 两个参数协同完成。
- -i(- --interactive): 保持标准输入(STDIN)的开启。即使没有附加到容器上,它也允许你向容器内部的进程发送输入。
- -t(- --tty): 为容器分配一个伪终端(pseudo-TTY)。这模拟了一个真实的终端环境,我们才能看到熟悉的命令行提示符,并使用 Tab 补全、方向键查看历史命令等功能。
-it 的黄金组合
通常,-i 和 -t 会被合并为 -it 一同使用,这样我们就能获得一个功能齐全的交互式 Shell。
docker run -it centos:7 bash

执行后,可以看到终端提示符发生了变化,变成了 [root@d87e076a5992 /]# 的形式,这表明我们已经成功进入了容器内部的 Bash 环境。
在这个交互式终端里,我们可以像在任何一台 Linux 服务器上一样执行命令。

上图展示了在容器内执行 ls 命令,并成功列出了根目录下的文件。
单独使用 -i 或 -t 会发生什么?
为了更深刻地理解这两个参数的作用,我们可以分别测试它们:
- 
只使用 -idocker run -i centos:7 bash 
 执行后,光标会停留在下一行,没有任何提示符。此时,标准输入是打开的,我们可以输入命令(如 ls)并按回车。
  
 输入ls后,命令被执行,并返回了结果。
  
 再输入pwd,同样得到了响应。结论: -i确保了我们可以与容器内的bash进程进行交互,但由于没有分配伪终端(-t),我们得不到一个用户友好的命令行界面。
- 
只使用 -tdocker run -t centos:7 bash 
 执行后,我们看到了熟悉的[root@... /]#提示符,这是-t分配伪终端的效果。然而,当我们尝试输入任何命令并按回车时,会发现没有任何反应。这是因为标准输入( -i)没有打开,我们无法将键盘输入传递给容器内的bash进程。
通过这些对比实验,我们可以清晰地认识到,-it 是进入容器进行交互式操作不可或缺的黄金搭档。
1.2 网络连接的桥梁:端口映射 (-p, -P)
默认情况下,容器的网络环境是与宿主机隔离的。如果我们想从外部访问容器内运行的服务(例如一个网站),就需要搭建一座桥梁——这就是端口映射。
指定端口映射 (-p)
-p(--publish)参数允许我们将宿主机的端口精确地映射到容器的某个端口。其格式非常灵活:主机端口:容器端口。
让我们以一个 Nginx 容器为例,将宿主机的 8081 端口映射到容器内部 Nginx 服务默认监听的 80 端口。
docker run -d -p 8081:80 nginx:1.24.0

命令执行后,一个 Nginx 容器将在后台启动。
通过 docker ps 查看容器状态,重点关注 PORTS 这一列。```bash
docker ps
*输出中的 `0.0.0.0:8081->80/tcp` 清晰地表明,宿主机上所有网络接口的 `8081` 端口的 TCP 流量,都将被转发到该容器的 `80` 端口。*现在,在浏览器中访问 `http://<宿主机IP>:8081`,你就能看到 Nginx 的欢迎页面了。#### **随机端口映射 (`-P`)**在某些场景下,我们可能不关心具体的宿主机端口号,只希望容器的服务能被外界访问即可。`-P`(`--publish-all`)参数便为此而生。它会自动将镜像中通过 `EXPOSE` 指令声明的所有端口,随机映射到宿主机的一个高位端口上。```bash
docker run -d -P nginx:1.24.0
 使用
使用 -P 参数后,我们看到 PORTS 列显示为 0.0.0.0:49153->80/tcp,Docker 为我们自动选择了一个未被占用的端口 49153。
1.3 身份与配置:容器的标识与环境 (--name, -h, -e)
为容器设置清晰的标识和正确的配置,是规范化管理的第一步。
指定容器名称 (--name)
如果不指定名称,Docker 会为每个容器分配一个随机、异想天开的名字(如 adoring_turing)。虽然有趣,但这对于后续的管理(如停止、删除、查看日志)非常不便。--name 参数让我们能够赋予容器一个有意义的、唯一的名称。
docker run -d --name mynginx1 nginx:1.24.0

docker ps 的输出中,NAMES 列现在显示为我们指定的 mynginx1。
有了这个名字,我们就可以方便地对它进行操作。例如,停止这个容器:
docker stop mynginx1

命令成功执行,我们通过名字精确地停止了目标容器。
指定容器主机名 (-h)
-h (--hostname) 参数用于设置容器内部的主机名。这是容器内部进程通过 hostname 命令看到的名字。
默认情况下,主机名是容器 ID 的缩写:```bash
docker run -it centos:7 bash
*进入容器后,命令行提示符显示的主机名是一串随机字符。*现在,我们使用 `-h` 参数指定一个自定义主机名:
```bash
docker run -it -h mycentos7 centos:7 bash

可以看到,提示符中的主机名已经变成了我们指定的 mycentos7。
设置环境变量 (-e)
环境变量是向容器内应用程序传递配置信息的标准方式,它实现了配置与代码的分离,是“十二因子应用”方法论的核心实践之一。-e (--env) 参数可以用来设置一个或多个环境变量。
docker run -it -h mycentos7 -e myenv=test centos:7 bash
在进入容器后,我们可以用 env 命令来验证环境变量是否设置成功。
env | grep myenv

输出结果显示 myenv=test,证明我们设置的环境变量已经生效。
1.4 资源限制:为容器戴上“镣铐” (--cpuset-cpus, -m)
在多租户或资源密集型的环境中,对容器的资源使用进行限制至关重要,这可以防止某个“失控”的容器耗尽整个宿主机的资源,影响其他服务的稳定性。
- --cpuset-cpus: 将容器绑定到指定的 CPU 核心上运行。这可以避免多核系统中 CPU 缓存失效带来的性能抖动,对于性能敏感型应用尤其重要。其值可以是范围(如 “0-1”)或列表(如 “0,2”)。
- -m(- --memory): 设置容器可以使用的最大内存量。支持单位后缀,如- m(兆字节) 或- g(吉字节)。
docker run -d --name mynginx_limited --cpuset-cpus="0-1" -m 512m nginx:1.24.0

这条命令启动了一个 Nginx 容器,并限制它只能在 CPU 核心 0 和 1 上运行,并且最大只能使用 512MB 的内存。
通过 docker stats 命令可以实时监控容器的资源使用情况,验证我们的限制是否生效。


1.5 容器间通信的旧方式 (--link)
重要提示:
--link是一个已废弃的遗留特性。 虽然了解其工作原理有助于理解 Docker 的发展,但在新项目中,强烈建议使用自定义网络(docker network) 来实现容器间的通信,因为它更灵活、更强大,并且是官方推荐的方式。
在自定义网络出现之前,--link 是实现容器间通信的主要方式。它的作用是在目标容器的 /etc/hosts 文件中添加一条记录,将源容器的名称解析到其 IP 地址。
让我们模拟一下这个过程:
首先,启动一个名为 mycentos1 的容器。
docker run -it --name mycentos1 centos:7 bash
然后,打开一个新的终端,启动第二个容器 mycentos2,并使用 --link 连接到 mycentos1。
docker run -it --name mycentos2 --link mycentos1:mywebsite1 centos:7 bash
这里的 --link mycentos1:mywebsite1 意味着:
- 链接到名为 mycentos1的容器。
- 在 mycentos2容器内部,为mycentos1创建一个别名mywebsite1。

进入 mycentos2 后,我们可以通过 ping mywebsite1 来测试连通性,可以看到它被成功解析到了 mycentos1 的 IP 地址。
1.6 “阅后即焚”:临时容器 (--rm)
--rm 是一个非常有用的参数,它会让容器在退出后自动被删除。这对于执行一次性任务的“工具型”容器非常理想,例如编译代码、运行测试或数据迁移脚本。它能保持你的 Docker 环境干净整洁,避免产生大量无用的已退出容器。
docker run -it --name mycentos4 --rm centos:7 bash
在这个容器中执行一些操作,然后输入 exit 退出。之后,当你执行 docker ps -a 时,会发现这个名为 mycentos4 的容器已经无影无踪了,因为它被自动清理了。
第二章:docker ps — 洞察容器世界的“仪表盘”
如果说 docker run 是创造者,那么 docker ps 就是观察者。它允许我们查看和监控主机上所有容器的状态,是我们管理容器日常工作的核心工具。
其基本语法为:```bash
docker ps [OPTIONS]
### 2.1 默认输出解读不带任何参数执行 `docker ps`,会列出当前所有**正在运行**的容器。```bash
docker ps

上图的输出包含了丰富的信息,让我们逐列解析:
- CONTAINER ID: 容器的唯一标识符(缩写形式)。
- IMAGE: 创建该容器所使用的镜像。
- COMMAND: 容器启动时执行的命令。
- CREATED: 容器的创建时间。
- STATUS: 容器当前的状态,例如 Up(运行中)、Exited(已退出)等。
- PORTS: 端口映射信息。
- NAMES: 容器的名称。
2.2 ps 命令的关键参数详解
docker ps 提供了众多参数,以满足不同的查询和过滤需求。
- 
-a或--all: 显示所有容器,包括已停止运行的。这是最常用的参数之一,对于调试启动失败的容器尤其有用。
- 
-f或--filter: 根据提供的条件进行过滤。这是一个非常强大的功能,可以精确地找到你需要的容器。
 例如,只查找名为mynginx4的容器:docker ps -a -f name=mynginx4 
 其他常用的过滤条件还有status=exited、ancestor=nginx:1.24.0(基于某个镜像创建的所有容器)等。
- 
--format: 使用 Go 模板自定义输出格式。 这对于脚本自动化和生成特定报告非常有用。
 例如,以 JSON 格式输出:docker ps --format json 
 我们还可以创建自定义的表格输出:docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}"
- 
-l或--latest: 显示最近创建的一个容器(无论其状态如何)。docker ps -l 
- 
-n: 显示最近创建的n个容器。docker ps -n 3 # 显示最近创建的3个容器
- 
--no-trunc: 不截断输出。默认情况下,为了保持表格整洁,Docker 会截断过长的信息,如容器 ID 和命令。 使用此参数可以显示完整信息。docker ps --no-trunc 
 可以看到,CONTAINER ID列显示了完整的 ID。
- 
-q或--quiet: 静默模式,只显示容器的数字 ID。 这个参数是脚本编程的利器,常用于将一个命令的输出作为另一个命令的输入。docker ps -q # 只显示运行中容器的ID docker ps -a -q # 显示所有容器的ID 
 一个经典的组合用法是删除所有已停止的容器:docker rm $(docker ps -a -f status=exited -q)
- 
-s或--size: 显示容器的总文件大小。 这对于监控磁盘使用情况很有帮助。docker ps -s 
 这里的size表示容器的可写层大小,而virtual size则是容器总大小(包括镜像的只读层)。
结论
通过本次深度探索,我们不仅复现了笔记中的每一个操作,更深入地理解了 docker run 和 docker ps 这两个基础命令背后丰富的设计哲学和强大的功能。从启动一个简单的交互式 Shell,到配置复杂的网络、资源限制,再到利用高级过滤和格式化来高效地管理和监控容器,这些命令构成了我们与 Docker 引擎交互的基石。
掌握它们,就如同掌握了一门语言的字母和语法,是通往构建、部署和管理复杂容器化应用宏伟蓝图的必经之路。希望这篇详尽的解析能成为您 Docker 学习道路上一块坚实的垫脚石。
