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 version | daemon / Docker Desktop 未启动或权限不足 |
port is already allocated | docker 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"基础镜像可能被其他项目复用,本实验不替你删除它们。确认所有检查通过并完成清理后,下一章把构建、测试、制品、镜像和部署连成一条可回滚的路径。