第三章: Docker 容器 (Container) 全生命周期管理

第三章: Docker 容器 (Container) 全生命周期管理

摘要: 静态的“蓝图”(镜像)已经准备就绪,现在是时候注入灵魂,让它们成为一个个鲜活的、提供服务的实体了。本章将彻底改变上一版“命令罗列”的失败模式,我们将围绕一个核心实战任务——“启动、改造、监控并清理一个 Nginx Web 服务器”——来展开。您将不再是被动的信息接收者,而是亲手的操作者。本章结束后,您将获得的不仅是一份命令清单,而是一套能在真实开发场景中自如地创建、进入、调试和管理容器的坚实技能。


在本章,我们的学习路径将与一个真实的运维任务完全同步:

  1. 启动服务: 我们将学习如何用一行命令启动一个后台运行的 Nginx 容器,并从外部访问它。
  2. 临时任务: 我们将学习如何启动一个临时的、交互式的容器来完成一次性的诊断任务,用后即焚。
  3. 在线热更新: 我们将攻克核心技能——在不停止服务的情况下,进入正在运行的 Nginx 容器,亲手修改其欢迎页面。
  4. 实时监控: 我们将学习如何像使用 tail -f 一样,实时查看 Nginx 容器的访问日志。
  5. 固化成果与清理: 我们将把修改后的容器状态保存为一个新镜像,并最终学会如何清理本次操作留下的所有痕迹。

3.1. 启动与管理我们的 Nginx 服务器

承上启下: 理论已经足够,让我们直接开始动手。我们的第一个任务是:启动一个标准的 Nginx Web 服务器,让它在后台持续运行,并能通过我们的主机浏览器访问到。

第一步:启动服务 (docker run)

在您的 WSL2 终端中,执行以下命令:

1
docker run --name my-webserver -p 8080:80 -d nginx:1.25.2

这条命令看起来很长,但它正是容器管理的精髓所在。让我们像拆解代码一样,逐一分析每个参数的意义:

  • docker run: 这是我们告诉 Docker “创建并启动一个容器”的核心指令。
  • --name my-webserver: 我们为这个容器起一个好记的名字 my-webserver。如果没有这个参数,Docker 会分配一个随机的名字(如 sad_einstein)。使用自定义名称能极大地便利后续管理。
  • -p 8080:80: 这是 端口映射-p 参数的格式是 [主机端口]:[容器端口]。这行命令的意思是,将我们主机(在这里指 WSL2 环境)的 8080 端口,映射到容器内部的 80 端口。这是让外部世界能够访问到容器内服务的关键。
  • -d: 即 --detach,意味着 后台运行。执行完命令后,终端会立即返回容器的完整 ID,而容器会在后台默默地提供服务,不会占用你当前的终端会话。
  • nginx:1.25.2: 这是我们用来创建容器的“蓝图”——镜像。

第二步:验证服务 (docker ps 与浏览器)

服务已经启动,我们如何确认它真的在工作?

1
2
# 使用 docker ps 查看当前正在运行的容器
docker ps

输出结果清晰地告诉我们:my-webserver 容器正在运行 (Up 5 seconds),并且端口 8080 已经成功映射到了容器的 80 端口。

现在,打开你 Windows 上的浏览器,访问 http://localhost:8080

恭喜你! 你已经成功启动了你的第一个后台服务容器。这个小小的 Nginx 服务器,连同它的整个运行环境,都被完美地封装在那个容器之中。

第三步:停止与清理 (docker stop & docker rm)

完成实验后,我们需要清理环境。

1
2
3
4
5
6
7
8
9
# 1. 停止服务。stop 命令会优雅地关闭容器
docker stop my-webserver

# 2. 验证容器已停止。直接 docker ps 将看不到它,需加 -a
docker ps -a
# 你会看到 my-webserver 的 STATUS 变成了 Exited (0) ...

# 3. 移除已停止的容器。注意:此操作会删除容器的可写层,其中的修改会丢失
docker rm my-webserver

3.2. 两种工作模式:服务型与任务型

承上启下: 上一节我们启动了一个 服务型 容器 (-d),它会像守护进程一样长期运行。但在开发中,我们还经常需要运行 任务型 容器,它只为了执行一个临时任务,执行完就应该消失。

场景:我需要一个纯净的 Linux 环境来测试网络连通性

这种“用完即走”的需求,正是 前台交互式 容器的用武之地。

1
2
# 运行一个 alpine 容器,并启动它的 sh 命令行程序
docker run --rm -it alpine:3.18 sh

让我们再次拆解这组新的参数:

  • -it: 这是 -i-t 的合并写法。-i 确保容器的 标准输入 保持打开,-t 则为容器分配一个 伪终端。两者结合,就为我们提供了一个可以交互的 shell 环境。
  • --rm: 这是一个极其有用的“自毁”开关。它告诉 Docker,当这个容器的主进程退出时,自动删除该容器。这避免了系统中残留大量无用的一次性容器。
  • alpine:3.18: 我们选用了一个极度轻量(仅约 7MB)的 Linux 发行版镜像。
  • sh: 这是我们希望在容器启动后执行的命令。sh 是 Alpine 系统默认的 shell。

执行命令后,你会发现你的终端提示符发生了变化:
/ #

这表明你已经 身处 Alpine 容器的内部 了。现在,你可以像操作一台真实的 Linux 机器一样执行命令:

1
2
3
4
5
6
# 在容器内部执行
/ # ping -c 3 google.com
PING google.com (142.251.42.238): 56 data bytes
64 bytes from 142.251.42.238: seq=0 ttl=111 time=10.511 ms
...
/ # exit

当你输入 exit 后,容器的 sh 进程结束,由于我们设置了 --rm,容器会被立刻、自动地删除。执行 docker ps -a 你将找不到它的任何痕迹。
核心模式总结:

  • docker run -d ...: 用于需要长期运行的 服务,如 Web 服务器、数据库。
  • docker run -it --rm ...: 用于需要交互的 临时任务,如环境测试、运行工具、代码编译。

3.3. 在线热更新:进入运行中的 Nginx 容器

承上启下: 这是本章最核心、最实用的技能。我们的 my-webserver 正在后台运行,但我们不满足于默认的欢迎页面,我们想在 不停止服务 的情况下,进去修改它!

第一步:重新启动我们的服务器
如果刚才你已经清理了环境,请重新运行它:

1
docker run --name my-webserver -p 8080:80 -d nginx:1.25.2

第二步:进入容器 (docker exec)
我们需要一个通往容器内部的 shell,但又要避免干扰正在运行的 Nginx 主进程。这正是 docker exec 的完美应用场景。

1
2
# 在 my-webserver 容器内,额外启动一个 bash 进程,并与之交互
docker exec -it my-webserver bash
  • docker exec: 告诉 Docker 我们要在指定容器内 执行一个新命令
  • -it: 同样,我们需要一个交互式的终端。
  • my-webserver: 目标容器的名称。
  • bash: 我们希望在容器内启动的新进程。

命令执行后,你的提示符会变为 root@c123...:/#。你现在拥有了 my-webserver 容器内部的“上帝视角”,而 Nginx 服务依然在后台安然无恙地运行着。

第三步:定位并修改网页文件
根据 Nginx 的知识,我们知道默认网页文件位于 /usr/share/nginx/html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ---- 以下命令均在容器内部执行 ----

# 1. 进入目标目录
root@...:/# cd /usr/share/nginx/html

# 2. 查看当前目录下的文件
root@...:/# ls -l
total 4
-rw-r--r-- 1 root root 615 Apr 25 12:28 index.html

# 3. 用 echo 命令直接覆盖掉原有的欢迎页面内容
root@...:/# echo '<h1> Prorise Docker Guide - Live Update! </h1>' > index.html

# 4. 确认修改成功
root@...:/# cat index.html
<h1>Prorise Docker Guide - Live Update!</h1>

# 5. 完成修改,退出容器的 shell
root@...:/# exit

第四步:见证奇迹
回到你 Windows 的浏览器,刷新 http://localhost:8080 页面。

你成功了!在完全不中断服务的情况下,你完成了对容器内部文件的在线修改。这就是 docker exec 的强大之处,它是在开发和运维中进行快速诊断和修复的利器。


3.4. 实时监控:查看 Nginx 访问日志

承上启下: 我们已经修改了页面,现在想看看谁访问了我们的新页面。我们需要实时地监控 Nginx 的访问日志。

1
2
# 使用 docker logs 命令,并附带 -f 参数来持续跟踪
docker logs -f my-webserver
  • -f (--follow): 这个参数与你熟知的 Linux 命令 tail -f 作用完全相同,它会“盯住”容器的日志输出,并实时打印到你的终端上。

现在,回到浏览器,多次刷新 http://localhost:8080。每刷新一次,你都会看到终端里立即出现一条新的访问记录。

Ctrl+C 可以停止跟踪。


3.5. 固化成果:将修改保存为新镜像

承上启下: 我们对容器的在线修改是临时的。如果容器被删除,这些修改就会丢失。如果我们希望将这个“被改造过”的状态保存下来,制作成一个新的、可重复使用的“蓝图”,该怎么办?

这时,docker commit 就派上用场了。

1
2
3
# 语法: docker commit [OPTIONS] CONTAINER [REPOSITORY[: TAG]]
# 将 my-webserver 容器的当前状态,提交为一个名为 my-nginx-custom: 1.0 的新镜像
docker commit my-webserver my-nginx-custom:1.0

执行后,docker images 列表里就会出现这个崭新的镜像。我们可以用它启动一个完全一样的、已包含修改后页面的新服务器:

1
2
3
4
# 从新镜像启动一个新容器,注意主机端口要换一个,避免冲突
docker run --name new-server -p 8081:80 -d my-nginx-custom:1.0

# 访问 http://localhost: 8081,你会发现它直接就是我们修改后的页面!

docker commit 是一个强大的快速快照工具,非常适合用于调试和实验。但在正规的生产流程中,我们 强烈推荐 使用 Dockerfile 来构建镜像。因为 Dockerfile 是一个记录了所有构建步骤的“代码”,它透明、可复现、易于版本控制,而 commit 产生的镜像是“黑盒”,不利于维护和团队协作。我们将在下一章深入 Dockerfile 的世界。


3.6. 离线文件归档:容器文件系统导出 (export)

承上启下: 我们已经学会了使用 docker commit 将容器的 完整状态(包括分层历史和配置)保存为一个新的 镜像。但有时,我们的需求可能更纯粹:我不需要一个新的 Docker 镜像,我只想要容器里 所有文件的一份简单、扁平的 .tar 归档。比如,用于数据备份、迁移到非 Docker 系统,或者提交给安全团队进行审计。

这正是 docker export 的用武之地。

exportcommit 的核心区别:

  • commit: 产物是 镜像。保留了 Docker 的“血统”(分层、元数据),可以被 docker run
  • export: 产物是 文件归档。丢弃了所有 Docker 的历史和配置,只是文件系统的快照,不能被 docker run

动手实践:导出我们的 Nginx 文件系统

让我们继续使用之前运行的 my-webserver 容器。

1
2
3
# 语法: docker export -o [输出文件名] [容器名]
# 将 my-webserver 容器的整个文件系统,打包成一个名为 my-webserver-fs.tar 的文件
docker export -o my-webserver-fs.tar my-webserver

命令执行后,你的当前目录下就会出现一个 my-webserver-fs.tar 文件。我们可以用 tar 命令来验证一下它的内容:

1
2
# 使用 tar 命令查看归档文件的内容列表(只看前几行)
tar -tf my-webserver-fs.tar | head -n 5

如你所见,这就是一个标准的 Linux 根文件系统归档,你可以用任何标准的归档工具来处理它。

docker export 的配对命令是 docker import,它可以将一个文件系统归档导入为一个新的 Docker 镜像。这在从零开始制作自定义的基础镜像时非常有用。例如:cat my-webserver-fs.tar | docker import - my-base-image:1.0

最后一步:彻底清理
我们的实验全部完成,现在执行清理操作,释放所有资源。

1
2
3
4
5
6
7
# 停止并删除所有容器 (如果它们还在运行)
docker stop my-webserver new-server
docker rm my-webserver new-server

# 删除我们创建的自定义镜像和下载的 Nginx 镜像
docker rmi my-nginx-custom:1.0
docker rmi nginx:1.25.2