跳到内容

第 0 卷 / 第 7 章 / 第 4 课

7.4 Docker 综合实验 ​

前置知识:本章前三页

预计时间:30 分钟

练习环境:Bash、curl 7.71+、Docker Engine 28+ 与 docker compose,默认 bridge/NAT 网络;基础镜像不在本机时需要联网

完成标志:完成回环端口、镜像构建和命名卷实验,并只清理本章资源

前面三次练习分别处理了端口、构建上下文和命名卷。现在把它们连成一次可逆实验,并在每次删除前证明资源属于本章。

先创建两个空目录,分别保存镜像与 Compose 文件:

bash
lab_workdir=$(mktemp -d)
lab_project="workshop-ch07-${RANDOM}-${RANDOM}"
lab_image="workshop-ch07-message:${RANDOM}-${RANDOM}"
mkdir -p "$lab_workdir/image" "$lab_workdir/compose"

安全边界 ​

  • 镜像与 Compose 项目使用本次生成的名称,Web 容器只按本次返回的 ID 操作;
  • 端口只绑定 127.0.0.1;
  • 不运行“停止所有容器”“删除所有镜像”或 docker system prune;
  • 基础镜像若本地没有,Docker 会访问配置的 registry,离线时会失败;
  • 清理前用 docker ps --filter 和 docker volume ls --filter 再核对一次。

热身:Nginx 与随机主机端口 ​

bash
(
set -e
container_id=$(docker run --detach --rm \
  --publish 127.0.0.1::80 nginx:latest)
trap 'docker stop "$container_id" >/dev/null 2>&1 || true' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
published=$(docker port "$container_id" 80/tcp)
printf 'published=%s\n' "$published"
host_port=${published##*:}
curl --fail --silent --show-error --retry 10 --retry-all-errors \
  --retry-delay 1 --max-time 2 "http://127.0.0.1:$host_port/"
docker logs "$container_id"
)

检查 curl 返回的 Nginx 页面和日志。代码在子 Shell 中运行,成功或失败退出时都会尝试停止本次容器;--rm 随后删除容器。若要用浏览器观察,在子 Shell 结束前请求打印的地址,不能等清理后再访问。

挑战一:构建最小镜像 ​

把 Dockerfile 页的三个文件重新放进 $lab_workdir/image,再构建:

bash
docker build -t "$lab_image" "$lab_workdir/image"
docker run --rm "$lab_image"
docker image inspect "$lab_image"
docker image rm "$lab_image"

验收:输出来自镜像内的 message.txt;运行容器自动删除;最后只删除 "$lab_image"。

挑战二:验证命名卷生命周期 ​

把 Compose 页的 compose.yaml 放进 $lab_workdir/compose,然后始终用 -f 指向它:

bash
docker compose -p "$lab_project" -f "$lab_workdir/compose/compose.yaml" config --quiet
docker compose -p "$lab_project" -f "$lab_workdir/compose/compose.yaml" run --rm reader
docker compose -p "$lab_project" -f "$lab_workdir/compose/compose.yaml" down
docker volume ls --filter "label=com.docker.compose.project=$lab_project"
docker compose -p "$lab_project" -f "$lab_workdir/compose/compose.yaml" down --volumes

验收:reader 读到 writer 写入的文本;第一次 down 后卷仍在;down --volumes 后本项目卷被移除。

排障表 ​

现象先查常见原因
只有 client 版本docker versiondaemon / Docker Desktop 未启动或权限不足
port is already allocateddocker ps、ss -ltn 或 lsof -iTCP主机端口已被容器或进程使用
COPY ... not found构建命令末尾的 context、.dockerignore文件不在 context 或被排除
容器立即退出docker logs NAME、docker inspect NAME主进程结束、参数错误、缺配置
Compose 服务连不上数据库docker compose ps、健康状态和日志使用了 localhost、数据库尚未就绪、网络名错误
删除容器后数据没了docker inspect 的 mounts数据写在容器可写层,未挂卷
无法拉取镜像registry 名称、代理、DNS、证书和登录状态网络受限、标签不存在、认证或限流

遇到端口占用时优先换练习端口,不要直接杀掉未知进程。镜像加速器、代理和企业证书属于环境配置,按组织文档处理,不要复制来源不明的 registry 配置。

验收 ​

  • [ ] 能区分镜像、容器、registry、层和可写层;
  • [ ] 能解释 EXPOSE 与端口发布的差别;
  • [ ] 能证明容器删除后命名卷仍在;
  • [ ] 能用 docker compose config 检查最终模型;
  • [ ] 清理命令只命中本次记录的容器 ID、$lab_image 和 $lab_project。

确认容器、练习镜像和命名卷都已清理后,删除本地文件:

bash
ls -ld -- "$lab_workdir"
rm -r -- "$lab_workdir"

基础镜像可能被其他项目复用,本实验不替你删除它们。确认所有检查通过并完成清理后,下一章把构建、测试、制品、镜像和部署连成一条可回滚的路径。

→ 下一步:从代码到运行

Built with VitePress | Software Systems Atlas