Introduction
Afterlight is a small community exhibition. Visitors leave thoughts on its guestbook wall; replacing the application must not erase their contributions. You will first try a disposable copy, then reconnect the real guestbook's existing data and keep new messages through an application replacement.
Basic terminal familiarity is enough. Docker, Compose, data paths, editing and HTTP are explained when needed. The application and tools are prepared; you do not write database code. All visitor details are synthetic.
Use Workstation for commands, Exhibition for the real guestbook, and Practice Copy only for the deliberate data-loss experiment. The two websites use different containers and ports. Each unit starts independently; the website, labels and output remain in English.
Give Visitor Data Its Own Home
In this step, you will try the exhibition, observe disposable data loss, and connect the real guestbook to its existing records. Start in Practice Copy. This is a separate, deliberately disposable exhibition with no real visitors.
Try the Normal Visitor Journey
Open About the exhibition, read the opening hours, then select The wall. Select Leave a contribution, enter Visitor under Your name and A small practice note. under Your message, then select Add to the wall. The detail page shows your contribution. Select Back to the wall to see its card. The details and form are the normal business you must preserve.
Observe What a Container Does Not Keep
Switch to Workstation. It starts in /home/labex/project/afterlight. A path identifies a file or directory; this absolute path starts at the filesystem root /. pwd prints the current directory:
pwd
Docker runs the application in a container, a process with its own filesystem view. An image is its prepared application package. The image afterlight:1 contains the program and design, but not later visitor contributions. Data written only into a container's writable layer disappears when that container is removed.
Remove only the disposable practice container. docker rm removes it; -f stops it first if needed:
docker rm -f afterlight-scratch
docker run creates a new container from the saved image. -d leaves it running in the background; --name names it. A port identifies a network service: -p 8082:8081 forwards the lab's port 8082 to application port 8081 inside this container.
docker run -d --name afterlight-scratch -p 8082:8081 afterlight:1
The long result is a new container ID. Switch to Practice Copy, select The wall and reload. Your practice card is gone. Do not keep refreshing its old detail URL: that entry no longer exists. This loss is limited to the disposable copy.
Attach the Existing Guestbook Data
Switch to Exhibition. Its empty wall has the same application but is currently missing its data attachment. The original visitor Iris's record is safely held in a prepared Docker volume named afterlight_messages. Your main task is to reconnect that data and preserve later submissions through an application replacement.
A named volume is storage managed by Docker outside a particular container. A mount connects that storage to a path inside the application. This application writes its SQLite database file at /data/wall.sqlite3. SQLite keeps records in a file; you do not need SQL or application code here.
Switch to Workstation. cat displays a file:
cat compose.yaml
Compose reads this YAML configuration to create the service. YAML uses indentation with spaces to express nesting. services groups applications; wall is this service. image, container_name, and ports describe its package, name and network mapping. environment supplies application settings. RELEASE selects a presentation edition; both editions use the same data format.
You will add a mount and a volume declaration. messages:/data connects the logical volume messages to the container directory /data; the top-level declaration gives it the existing Docker name afterlight_messages. external: true tells Compose to reuse that prepared volume rather than create a new one. A wrong name produces a missing-volume error: correct the name; do not delete the original volume or create an empty substitute. Declaring storage without attaching it to the service would not protect data.
cat > compose.yaml replaces this configuration. The quoted YAML starts a here-document: paste the whole block, including the final YAML on its own line. Quoting keeps its contents literal; use spaces exactly as shown.
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 validates the configuration quietly. No output means it parsed successfully; an error means you should correct the indentation or spelling and retry before applying it.
docker compose config -q
docker compose up -d creates or replaces the service to match the file, in the background. It keeps named volumes. Wait for the command to finish:
docker compose up -d
Switch to Exhibition, return to The wall, and reload. Iris's A beautiful place to pause. must now appear. Open Iris's card, then return. This is an existing record reconnected from its real database, not a new sample generated at every start.
Write a New Contribution and Identify Its Storage
In this step, you will add a real contribution and connect the visible result to the actual mount. Begin in Exhibition. Keep Iris's original card.
Select Leave a contribution. Enter Mira under Your name and exactly The light stays with us. under Your message. Select Add to the wall. The detail page must show both values. Select Back to the wall; both Iris and Mira should be present.
Switch to Workstation. docker inspect reads the actual container configuration. --format selects a field; the single quotes keep the braces literal. This template displays the mount list as JSON:
docker inspect afterlight-wall --format '{{json .Mounts}}'
Find "Type":"volume", "Name":"afterlight_messages", "Destination":"/data", and "RW":true. RW means the mount permits reads and writes. A name in a configuration file is only intent; this is the running container's actual connection.
docker volume ls lists the available volumes:
docker volume ls
Other platform volumes may exist; leave them alone. If an external volume name is mistyped, Compose stops with a missing-volume error. Correct the name in the file and apply again; do not create an empty replacement. If you accidentally attach a different existing empty volume, an empty wall does not prove the original records were deleted. Keep the original volume, restore the name afterlight_messages in compose.yaml, validate, and apply again. Do not use volume deletion as a troubleshooting shortcut. docker compose down -v removes Compose-managed volumes and their data, but leaves volumes declared external: true alone. That protection does not make manually deleting an external volume safe.
Account for Every Kind of Data
One business entry may depend on more than one directory. This guestbook stores text in /data. A photo wall additionally stores uploaded image bytes in /photos; its database holds each caption and the associated filename. Preserving only the caption can leave a broken picture.
| Container path | Content | Keep across replacement? |
|---|---|---|
/data |
Visitor records and photo-to-caption relationships | Yes |
/photos in the photo wall |
Uploaded photographs | Yes, separately from the database |
/app |
Prepared program, design, and training samples in the image | Recreated from the supplied image |
Multiple data directories use the same mount syntax: one service list entry and one volume declaration for each. Do not mount a blank volume over /app; it would hide the program. Cached or image-supplied files are not automatically visitor data.
The independent challenge uses a photo upload form. Its River and Garden links download supplied PNG training pictures to your computer. Save the requested picture, choose it in Photograph (PNG), fill in the name and caption, and submit Add to the wall. The browser sends the selected bytes; this does not require a command-line upload tool.
Replace the Application and Keep the Exhibition Alive
In this step, you will replace the application with edition 2, retain both contributions, and accept a new one. Begin in Workstation.
nano is a terminal text editor. Open the configuration:
nano compose.yaml
Use the arrow keys to change only RELEASE: "1" to RELEASE: "2". Keep the mounts, image and ports. Save with Ctrl+O, Enter, then exit with Ctrl+X. Read the saved configuration and validate it:
cat compose.yaml
docker compose config -q
docker compose ps -q wall prints the current container ID. Record it mentally or keep the terminal output for comparison; no report is required:
docker compose ps -q wall
Apply the edition change. --force-recreate requests a new container even when the other configuration is unchanged:
docker compose up -d --force-recreate
docker compose ps -q wall
The ID must differ. This is a replacement, not just a restart. If startup fails, docker compose logs wall displays application messages; correct the configuration, validate, and repeat up -d. Keep the original volumes. Do not remove other containers.
Switch to Exhibition, select The wall and reload. The footer should say Edition 2. Iris and Mira must remain. Open each card, then return. Enter Leon and exactly Back for another look. in the contribution form and submit. Return to the wall: three contributions now work in the replacement application.
Check the Service as Well as the Data
Switch to Workstation. HTTP is the browser's request-and-response protocol. Status 200 means a successful response; 404 means the requested resource was not found. A connection failure means no server response arrived.
curl sends a request. -sS hides progress but shows connection errors; -o /dev/null discards the body. -w prints the quoted format: %{http_code} is the status, and \n ends the line. 127.0.0.1 means this lab instance when used in Workstation; port 8081 is Exhibition. Run:
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8081/about
Expect 200. In Exhibition, open About the exhibition, confirm the hours still appear, then select The wall. A successful status alone would not prove the right content or preserved submissions.
Your volume protects against this container's replacement. It is not an independent backup and does not protect against deleting the volume or losing the host. Keep application files reproducible and visitor data separately stored.
Summary
You distinguished disposable container files from persistent visitor data, attached the existing named volume, and retained original and new messages across replacement. A new contribution and the exhibition pages still work. Next, apply the same method to captions and separately stored photographs.



