7.4 Docker Comprehensive Experiment
Prerequisites: Pages 1-3 of this chapter
Estimated time: 30 minutes
Practice environment: Bash, curl 7.71+, Docker Engine 28+,
docker compose, and default bridge/NAT networking; if base images are not available locally, an internet connection is requiredYou are ready to continue when: you can complete the loopback port, image building, and named volume experiments, and clean up only the resources of this chapter
The previous three exercises covered ports, build context, and named volumes separately. Combine them into one reversible experiment, and prove that every resource belongs to this lesson before deleting it.
First, create two empty directories to store the image and Compose files:
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"Security Boundaries
- Images and Compose projects use names generated for this run; the web container is managed only by the ID returned by its startup command;
- Ports are only bound to
127.0.0.1; - Do not run commands such as "stop all containers," "delete all images," or
docker system prune; - If a base image is not locally available, Docker will access the configured registry, and it will fail offline;
- Before cleaning, verify again using
docker ps --filteranddocker volume ls --filter.
Warm-up: Nginx and Random Host Port
(
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"
)Check the Nginx response returned by curl and the logs. The subshell attempts to stop this container on success or failure, after which --rm removes it. Browser inspection must happen before the subshell finishes; the printed address stops working after cleanup.
Challenge 1: Build a Minimal Image
Take the three files from the Dockerfile page and put them back into $lab_workdir/image, then build:
docker build -t "$lab_image" "$lab_workdir/image"
docker run --rm "$lab_image"
docker image inspect "$lab_image"
docker image rm "$lab_image"Acceptance: Output from the image inside message.txt; containers run automatically and are deleted; in the end, only "$lab_image" is deleted.
Challenge 2: Verifying the Lifecycle of Named Volumes
Place the Compose page's compose.yaml into $lab_workdir/compose, and always have -f point to it:
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 --volumesAcceptance: The reader reads the text written by the writer; the volume remains intact after the first down; the volume is removed from this project after down --volumes.
Troubleshooting Table
| Phenomenon | Check First | Common Causes |
|---|---|---|
| Only client version | docker version | Daemon / Docker Desktop not started or insufficient permissions |
port is already allocated | docker ps, ss -ltn or lsof -iTCP | Host port is being used by a container or process |
COPY ... not found | Build command's context, .dockerignore | File is not in context or excluded |
| Container exits immediately | docker logs NAME, docker inspect NAME | Main process ends, parameter error, missing configuration |
| Compose service can't connect to database | docker compose ps, health status and logs | Used localhost, database not ready, incorrect network name |
| Data is lost after deleting container | docker inspect's mounts | Data is written in the container's writable layer, not in a volume |
| Can't pull image | registry name, proxy, DNS, certificate and login status | Network restrictions, tag does not exist, authentication or rate limiting |
When encountering port conflicts, prioritize switching to another port rather than directly killing an unknown process. Image accelerators, proxies, and enterprise certificates are part of the environment configuration. Handle them according to organizational documentation, and do not copy registry configurations from unknown sources.
Acceptance
- [ ] Can distinguish between images, containers, registries, layers, and writable layers;
- [ ] Can explain the difference between
EXPOSEand port publishing; - [ ] Can prove that named volumes remain after a container is deleted;
- [ ] Can use
docker compose configto check the final model; - [ ] Cleanup commands target only the recorded container ID,
$lab_image, and$lab_project.
Confirm that containers, practice images, and named volumes have been cleaned up, then delete the local files:
ls -ld -- "$lab_workdir"
rm -r -- "$lab_workdir"Base images may be reused by other projects, so this experiment does not delete them for you. Once the checks pass and cleanup is complete, the next chapter connects building, testing, artifacts, images, and deployment into a reversible path.