介绍
Afterlight 是一场小型社区展览。访客在留言墙上留下感想;替换应用时不能擦掉这些投稿。你将先体验可丢弃的副本,再为真实访客簿接回原有数据,让新增留言也能跨越应用替换保留。
具有基本终端操作能力即可。Docker、Compose、数据路径、编辑和 HTTP 都会在需要时解释。应用和工具已准备好,不需编写数据库代码。所有访客信息都是合成数据。
命令在 Workstation 中执行,真实访客簿位于 Exhibition,Practice Copy 只用于有意观察数据丢失。这两个网站使用不同的容器和端口。各单元独立开始;网站、标签和输出保持英文。
为访客数据安一个独立的家
本步骤将带你体验展览、观察可丢弃数据的丢失,并把真实访客簿接回原有记录。先打开 Practice Copy。这是单独的、可有意丢弃的展览,没有真实访客。
体验正常的访客流程
打开 About the exhibition,阅读开放时间,再选择 The wall。选择 Leave a contribution,在 Your name 中输入 Visitor,在 Your message 中输入 A small practice note.,再选择 Add to the wall。详情页会显示投稿。选择 Back to the wall 查看卡片。详情和表单都是必须保留的正常业务功能。
观察容器不会保留什么
切换到 Workstation。终端起始目录为 /home/labex/project/afterlight。路径标识文件或目录;这个绝对路径从文件系统根目录 / 开始。pwd 显示当前目录:
pwd
Docker 在容器中运行应用;容器是具有独立文件系统视图的进程。镜像是准备好的应用包。afterlight:1 镜像包含程序与设计,却不包含后来由访客提交的内容。只写入容器可写层的数据,会在删除该容器时消失。
只删除可丢弃的练习容器。docker rm 删除容器;需要时,-f 会先停止它:
docker rm -f afterlight-scratch
docker run 使用保存的镜像创建新容器。-d 让它在后台运行,--name 设置名称。端口标识网络服务:-p 8082:8081 将实验环境的端口 8082 转发到容器内应用端口 8081。
docker run -d --name afterlight-scratch -p 8082:8081 afterlight:1
较长的输出是新容器 ID。切换到 Practice Copy,选择 The wall 并重新加载。练习卡片已经消失。不要一直刷新旧的详情 URL:那条记录已不存在。本次丢失仅发生在可丢弃副本中。
接回现有访客簿数据
切换到 Exhibition。空白留言墙使用同一应用,但当前缺少数据挂载。原访客 Iris 的记录安全保存在预置 Docker 卷 afterlight_messages 中。你的主要任务是重新接入这些数据,并让后续投稿在应用替换后保留。
命名卷是 Docker 管理的存储,独立于某一个容器。挂载把该存储连接到应用内的路径。本应用把 SQLite 数据库写入 /data/wall.sqlite3。SQLite 在文件中保存记录;这里不要求 SQL 或应用编程知识。
切换到 Workstation。cat 显示文件内容:
cat compose.yaml
Compose 读取此 YAML 配置来创建服务。YAML 使用空格缩进表示嵌套。services 组织应用;wall 是本服务。image、container_name 和 ports 描述应用包、名称和网络映射。environment 提供应用设置。RELEASE 选择展示版本;两个版本使用相同的数据格式。
你将添加挂载和卷声明。messages:/data 将逻辑卷 messages 连接到容器目录 /data;顶层声明将其对应到现有 Docker 名称 afterlight_messages。external: true 告诉 Compose 复用预置卷,而不是创建新卷。名称错误时会报告卷不存在:应修正名称,不要删除原卷或创建空卷替代。 只声明存储而不挂载到服务,不能保护数据。
cat > compose.yaml 替换此配置。带引号的 YAML 开始一个 here-document:粘贴完整代码块,包含最后独占一行的 YAML。引号让内容按原样保留;空格请与示例一致。
cat > compose.yaml <<'YAML'
name: afterlight
services:
wall:
image: afterlight:1
container_name: afterlight-wall
ports:
- "8081:8081"
environment:
MODE: guestbook
RELEASE: "1"
volumes:
- messages:/data
volumes:
messages:
name: afterlight_messages
external: true
YAML
docker compose config -q 静默校验配置。没有输出表示解析成功;如果报错,先修正缩进或拼写并重试,再应用配置。
docker compose config -q
docker compose up -d 在后台创建或替换服务,使其符合文件中的配置,并保留命名卷。等待命令结束:
docker compose up -d
切换到 Exhibition,回到 The wall 并重新加载。现在应看到 Iris 的 **A beautiful place to pause.**。打开 Iris 的卡片,再返回。这是从真实数据库接回的现有记录,并非每次启动时重新生成的示例。
写入新留言并识别其存储位置
本步骤将添加真实投稿,并将页面结果与实际挂载对应起来。先打开 Exhibition,保留 Iris 的原卡片。
选择 Leave a contribution。在 Your name 中输入 Mira,在 Your message 中准确输入 The light stays with us.,再选择 Add to the wall。详情页应显示这两个值。选择 Back to the wall,Iris 和 Mira 都应存在。
切换到 Workstation。docker inspect 读取容器的实际配置。--format 选择字段;单引号让花括号按原样传递。此模板以 JSON 显示挂载列表:
docker inspect afterlight-wall --format '{{json .Mounts}}'
找到 "Type":"volume"、"Name":"afterlight_messages"、"Destination":"/data" 和 "RW":true。RW 表示挂载允许读写。配置文件中的名称只是意图;这里显示的是运行容器实际连接的位置。
docker volume ls 列出可用卷:
docker volume ls
可能还有平台的其他卷,请勿操作。外部卷名称拼错时,Compose 会报告卷不存在并停止。应修正文件中的名称再应用,不要新建空卷替代。 如果误接了一个新的空卷,空白留言墙并不能证明原记录已删除。保留原卷,将 compose.yaml 中的名称恢复为 afterlight_messages,校验并重新应用。不要用删除卷作为排错捷径。docker compose down -v 会删除 Compose 管理的卷及其数据,但不会删除声明为 external: true 的卷。这不代表手动删除外部卷是安全的。
考虑每一种数据
一条业务投稿可能依赖多个目录。访客簿把文本保存在 /data。照片墙还把上传的图片字节保存在 /photos;数据库记录每条说明及其关联文件名。只保留说明可能留下损坏的图片。
| 容器路径 | 内容 | 替换后需要保留吗? |
|---|---|---|
/data |
访客记录及照片与说明之间的关联 | 需要 |
照片墙的 /photos |
上传的照片 | 需要,独立于数据库保存 |
/app |
镜像中预置的程序、设计和训练样本 | 从提供的镜像重建 |
多个数据目录使用相同的挂载语法:每个目录分别添加一条服务挂载和一个卷声明。不要把空卷挂载到 /app,否则会遮住程序。缓存文件或镜像自带的文件并不自动属于访客数据。
独立挑战会使用照片上传表单。River 和 Garden 链接将提供的 PNG 训练图片下载到你的电脑。保存所需图片,在 Photograph (PNG) 中选择该文件,填写姓名与说明,再提交 Add to the wall。浏览器会发送所选文件的字节,不需要命令行上传工具。
替换应用并保持展览可用
本步骤将应用替换为 edition 2,保留两条投稿,并接收一条新投稿。先打开 Workstation。
nano 是终端文本编辑器。打开配置:
nano compose.yaml
使用方向键,仅将 RELEASE: "1" 改为 RELEASE: "2"。保留挂载、镜像和端口。按 Ctrl+O、Enter 保存,再按 Ctrl+X 退出。查看保存后的配置并校验:
cat compose.yaml
docker compose config -q
docker compose ps -q wall 显示当前容器 ID。记住它或保留终端输出以便比较;不要求提交报告:
docker compose ps -q wall
应用版本更改。即使其他配置未变,--force-recreate 也会要求创建新容器:
docker compose up -d --force-recreate
docker compose ps -q wall
ID 应与原先不同。这是替换,而不只是重启。如果启动失败,docker compose logs wall 会显示应用消息;修正配置、校验后重新执行 up -d。保留原有卷,不要删除其他容器。
切换到 Exhibition,选择 The wall 并重新加载。页脚应显示 Edition 2。Iris 和 Mira 必须仍在。分别打开两张卡片,再返回。在投稿表单中输入 Leon 和准确的 Back for another look.,然后提交。返回留言墙:替换后的应用现在应能正常展示三条投稿。
同时检查服务与数据
切换到 Workstation。HTTP 是浏览器使用的请求与响应协议。状态 200 表示响应成功;404 表示请求的资源不存在。连接失败则表示没有收到服务器响应。
curl 发送请求。-sS 隐藏进度但显示连接错误;-o /dev/null 丢弃响应正文。-w 输出引号中的格式:%{http_code} 是状态码,\n 结束该行。在 Workstation 中使用时,127.0.0.1 指本实验实例,端口 8081 对应 Exhibition。运行:
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8081/about
预期为 200。在 Exhibition 中打开 About the exhibition,确认开放时间仍显示,再选择 The wall。只有成功状态码,并不能证明内容正确或投稿得到保留。
卷能保护数据免受本次容器替换的影响,但它不是独立备份,无法防止删除卷或宿主丢失。让应用文件可重建,将访客数据单独保存。
总结
你区分了可丢弃的容器文件与持久访客数据,接回现有命名卷,并在替换后保留原有和新增留言。新的投稿与展览页面仍然可用。接下来,把同一方法用于说明和单独存放的照片。



