第三章: Docker 容器 (Container) 全生命周期管理
第三章: Docker 容器 (Container) 全生命周期管理
Prorise第三章: Docker 容器 (Container) 全生命周期管理
摘要: 静态的“蓝图”(镜像)已经准备就绪,现在是时候注入灵魂,让它们成为一个个鲜活的、提供服务的实体了。本章将彻底改变上一版“命令罗列”的失败模式,我们将围绕一个核心实战任务——“启动、改造、监控并清理一个 Nginx Web 服务器”——来展开。您将不再是被动的信息接收者,而是亲手的操作者。本章结束后,您将获得的不仅是一份命令清单,而是一套能在真实开发场景中自如地创建、进入、调试和管理容器的坚实技能。
在本章,我们的学习路径将与一个真实的运维任务完全同步:
- 启动服务: 我们将学习如何用一行命令启动一个后台运行的 Nginx 容器,并从外部访问它。
- 临时任务: 我们将学习如何启动一个临时的、交互式的容器来完成一次性的诊断任务,用后即焚。
- 在线热更新: 我们将攻克核心技能——在不停止服务的情况下,进入正在运行的 Nginx 容器,亲手修改其欢迎页面。
- 实时监控: 我们将学习如何像使用
tail -f
一样,实时查看 Nginx 容器的访问日志。 - 固化成果与清理: 我们将把修改后的容器状态保存为一个新镜像,并最终学会如何清理本次操作留下的所有痕迹。
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 | # 使用 docker ps 查看当前正在运行的容器 |
1
2
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e622eeeded6 nginx:1.25.2 "/docker-entrypoint.…" 6 seconds ago Up 5 seconds 0.0.0.0:8080->80/tcp my-webserver
输出结果清晰地告诉我们:my-webserver
容器正在运行 (Up 5 seconds
),并且端口 8080
已经成功映射到了容器的 80
端口。
现在,打开你 Windows 上的浏览器,访问 http://localhost:8080
。
恭喜你! 你已经成功启动了你的第一个后台服务容器。这个小小的 Nginx 服务器,连同它的整个运行环境,都被完美地封装在那个容器之中。
第三步:停止与清理 (docker stop
& docker rm
)
完成实验后,我们需要清理环境。
1 | # 1. 停止服务。stop 命令会优雅地关闭容器 |
3.2. 两种工作模式:服务型与任务型
承上启下: 上一节我们启动了一个 服务型 容器 (-d
),它会像守护进程一样长期运行。但在开发中,我们还经常需要运行 任务型 容器,它只为了执行一个临时任务,执行完就应该消失。
场景:我需要一个纯净的 Linux 环境来测试网络连通性
这种“用完即走”的需求,正是 前台交互式 容器的用武之地。
1 | # 运行一个 alpine 容器,并启动它的 sh 命令行程序 |
让我们再次拆解这组新的参数:
-it
: 这是-i
和-t
的合并写法。-i
确保容器的标准输入
保持打开,-t
则为容器分配一个伪终端
。两者结合,就为我们提供了一个可以交互的 shell 环境。--rm
: 这是一个极其有用的“自毁”开关。它告诉 Docker,当这个容器的主进程退出时,自动删除该容器。这避免了系统中残留大量无用的一次性容器。alpine:3.18
: 我们选用了一个极度轻量(仅约 7MB)的 Linux 发行版镜像。sh
: 这是我们希望在容器启动后执行的命令。sh
是 Alpine 系统默认的 shell。
执行命令后,你会发现你的终端提示符发生了变化:/ #
这表明你已经 身处 Alpine 容器的内部 了。现在,你可以像操作一台真实的 Linux 机器一样执行命令:
1 | # 在容器内部执行 |
当你输入 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 | # 在 my-webserver 容器内,额外启动一个 bash 进程,并与之交互 |
docker exec
: 告诉 Docker 我们要在指定容器内 执行一个新命令。-it
: 同样,我们需要一个交互式的终端。my-webserver
: 目标容器的名称。bash
: 我们希望在容器内启动的新进程。
命令执行后,你的提示符会变为 root@c123...:/#
。你现在拥有了 my-webserver
容器内部的“上帝视角”,而 Nginx 服务依然在后台安然无恙地运行着。
第三步:定位并修改网页文件
根据 Nginx 的知识,我们知道默认网页文件位于 /usr/share/nginx/html
。
1 | # ---- 以下命令均在容器内部执行 ---- |
第四步:见证奇迹
回到你 Windows 的浏览器,刷新 http://localhost:8080
页面。
你成功了!在完全不中断服务的情况下,你完成了对容器内部文件的在线修改。这就是 docker exec
的强大之处,它是在开发和运维中进行快速诊断和修复的利器。
3.4. 实时监控:查看 Nginx 访问日志
承上启下: 我们已经修改了页面,现在想看看谁访问了我们的新页面。我们需要实时地监控 Nginx 的访问日志。
1 | # 使用 docker logs 命令,并附带 -f 参数来持续跟踪 |
-f
(--follow
): 这个参数与你熟知的 Linux 命令tail -f
作用完全相同,它会“盯住”容器的日志输出,并实时打印到你的终端上。
现在,回到浏览器,多次刷新 http://localhost:8080
。每刷新一次,你都会看到终端里立即出现一条新的访问记录。
1
2
3
172.17.0.1 - - [19/Sep/2025:01:45:10 +0000] "GET / HTTP/1.1" 200 52 "-" "Mozilla/5.0 ..." "-"
172.17.0.1 - - [19/Sep/2025:01:45:11 +0000] "GET / HTTP/1.1" 200 52 "-" "Mozilla/5.0 ..." "-"
172.17.0.1 - - [19/Sep/2025:01:45:12 +0000] "GET / HTTP/1.1" 200 52 "-" "Mozilla/5.0 ..." "-"
按 Ctrl+C
可以停止跟踪。
3.5. 固化成果:将修改保存为新镜像
承上启下: 我们对容器的在线修改是临时的。如果容器被删除,这些修改就会丢失。如果我们希望将这个“被改造过”的状态保存下来,制作成一个新的、可重复使用的“蓝图”,该怎么办?
这时,docker commit
就派上用场了。
1 | # 语法: docker commit [OPTIONS] CONTAINER [REPOSITORY[: TAG]] |
执行后,docker images
列表里就会出现这个崭新的镜像。我们可以用它启动一个完全一样的、已包含修改后页面的新服务器:
1 | # 从新镜像启动一个新容器,注意主机端口要换一个,避免冲突 |
docker commit
是一个强大的快速快照工具,非常适合用于调试和实验。但在正规的生产流程中,我们 强烈推荐 使用 Dockerfile
来构建镜像。因为 Dockerfile
是一个记录了所有构建步骤的“代码”,它透明、可复现、易于版本控制,而 commit
产生的镜像是“黑盒”,不利于维护和团队协作。我们将在下一章深入 Dockerfile
的世界。
3.6. 离线文件归档:容器文件系统导出 (export
)
承上启下: 我们已经学会了使用 docker commit
将容器的 完整状态(包括分层历史和配置)保存为一个新的 镜像。但有时,我们的需求可能更纯粹:我不需要一个新的 Docker 镜像,我只想要容器里 所有文件的一份简单、扁平的 .tar
归档。比如,用于数据备份、迁移到非 Docker 系统,或者提交给安全团队进行审计。
这正是 docker export
的用武之地。
export
与 commit
的核心区别:
commit
: 产物是 镜像。保留了 Docker 的“血统”(分层、元数据),可以被docker run
。export
: 产物是 文件归档。丢弃了所有 Docker 的历史和配置,只是文件系统的快照,不能被docker run
。
动手实践:导出我们的 Nginx 文件系统
让我们继续使用之前运行的 my-webserver
容器。
1 | # 语法: docker export -o [输出文件名] [容器名] |
命令执行后,你的当前目录下就会出现一个 my-webserver-fs.tar
文件。我们可以用 tar
命令来验证一下它的内容:
1 | # 使用 tar 命令查看归档文件的内容列表(只看前几行) |
1
2
3
4
5
.dockerenv
dev/
dev/console
dev/core
dev/fd/
如你所见,这就是一个标准的 Linux 根文件系统归档,你可以用任何标准的归档工具来处理它。
docker export
的配对命令是 docker import
,它可以将一个文件系统归档导入为一个新的 Docker 镜像。这在从零开始制作自定义的基础镜像时非常有用。例如:cat my-webserver-fs.tar | docker import - my-base-image:1.0
最后一步:彻底清理
我们的实验全部完成,现在执行清理操作,释放所有资源。
1 | # 停止并删除所有容器 (如果它们还在运行) |