Checkpoint Lab — Installing Docker Engine and Desktop, CLI Basics, Daemon Connectivity, Contexts, and Environment Setup
Prove a disposable Docker environment end to end by capturing platform, distribution source, client/server/API, context/endpoint, data-root/storage baseline, privilege model, immutable test image, container identity, restart persistence, limitations, and exact cleanup in one reviewable evidence packet.
Learning objectives
- Capture platform, installation source, Docker client/server/API, context, plugin, and authorization evidence before creating resources.
- Predict image/container/restart/cleanup state changes and verify each prediction independently.
- Resolve the verification image to an immutable digest and bind it to the exact container object and exit evidence.
- Restart a disposable Engine/Desktop boundary safely and prove which image/container metadata persists.
- Deliver exact cleanup plus an assumptions/limitations note that distinguishes observed facts from platform abstractions.
1. Checkpoint scenario and acceptance criteria
Establish one disposable Docker environment and prove it as if handing it to another engineer. The preferred execution path is a disposable native-Linux Engine host from Lesson 2; Docker Desktop learners may use the Desktop variant and mark host-service/data-root details that are abstracted by the VM as such.
Your evidence packet must answer: What platform is this? How was Docker obtained? Which client and server are in use? Which context/endpoint receives commands? What is the daemon data root/storage model? What privilege model lets this user administer Docker? Which immutable image content was tested? Which container object was created? What survived restart? What was cleaned up?
2. Setup and lab identity
set -eu
LAB_CONTAINER="da-ch02-checkpoint"
LAB_LABEL="devops-academy.lab=chapter02-checkpoint"
LAB_IMAGE_TAG="hello-world:latest"
EVIDENCE_DIR="$HOME/da-ch02-evidence"
mkdir -p "$EVIDENCE_DIR"
printf 'started=%s
' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" | tee "$EVIDENCE_DIR/session.txt"
docker context inspect shows an endpoint you do not
explicitly own for this lab, stop. If unrelated running containers
exist on a disposable VM you thought was empty, investigate before
daemon restart.
3. Capture platform, client, server, context, and privilege preflight
{
echo '=== host ==='
uname -a 2>/dev/null || true
uname -m 2>/dev/null || true
cat /etc/os-release 2>/dev/null || true
echo '=== client/server ==='
docker version
echo '=== context ==='
docker context show
docker context ls
docker context inspect "$(docker context show)"
echo '=== environment overrides ==='
env | grep '^DOCKER_' || true
echo '=== plugins ==='
docker buildx version 2>/dev/null || true
docker compose version 2>/dev/null || true
echo '=== identity ==='
id 2>/dev/null || true
ls -l /var/run/docker.sock 2>/dev/null || true
} | tee "$EVIDENCE_DIR/preflight.txt"
On Windows/Desktop, save wsl --version and the Desktop
version/backend separately. Never invent Linux service/socket
evidence that your Desktop host cannot expose.
4. Capture daemon state, data root, storage, and security baseline
{
docker info
docker info --format 'DockerRootDir={{.DockerRootDir}}'
docker info --format 'Driver={{.Driver}} CgroupVersion={{.CgroupVersion}} CgroupDriver={{.CgroupDriver}}'
docker info --format 'SecurityOptions={{json .SecurityOptions}}'
} | tee "$EVIDENCE_DIR/daemon-baseline.txt"
Record the data root as an identity fact. Do not browse/delete its internals for this checkpoint. If Docker Desktop abstracts this behind the managed VM, record that boundary instead.
5. Write predictions before changing runtime state
| Prediction | Verification |
|---|---|
| Pulling the tag will create/reuse local image content on the selected daemon and resolve to a repository digest. | docker image inspect and RepoDigests. |
| Running the digest will create one named, labeled container that exits successfully. | Exact container ID, label, status, exit code, logs. |
| A daemon/Desktop restart will replace control-plane process state but preserve image and stopped-container metadata. | Same image/container identity remains queryable after restart. |
| Removing the exact lab container will not remove unrelated images/volumes/networks. | Label-filter returns no lab container; broader daemon state remains untouched. |
6. Resolve the image and run the checkpoint container
docker pull "$LAB_IMAGE_TAG" | tee "$EVIDENCE_DIR/pull.txt"
IMAGE_REF="$(docker image inspect "$LAB_IMAGE_TAG" --format '{{index .RepoDigests 0}}')"
IMAGE_ID="$(docker image inspect "$LAB_IMAGE_TAG" --format '{{.Id}}')"
printf 'image_ref=%s
image_id=%s
' "$IMAGE_REF" "$IMAGE_ID" | tee "$EVIDENCE_DIR/image.txt"
docker run --name "$LAB_CONTAINER" --label "$LAB_LABEL" "$IMAGE_REF" | tee "$EVIDENCE_DIR/container-output.txt"
docker inspect "$LAB_CONTAINER" >"$EVIDENCE_DIR/container-inspect.json"
docker inspect "$LAB_CONTAINER" \
--format 'id={{.Id}} image={{.Image}} status={{.State.Status}} exit={{.State.ExitCode}} labels={{json .Config.Labels}}' | tee "$EVIDENCE_DIR/container-summary.txt"
A successful exit is useful evidence, but write explicitly that it does not prove port publication, application health, persistent data, or registry publication.
7. Preflight the restart
docker ps --format 'table {{.ID}} {{.Names}} {{.Status}}'
docker ps -a --filter "label=$LAB_LABEL"
BEFORE_CONTAINER_ID="$(docker inspect "$LAB_CONTAINER" --format '{{.Id}}')"
BEFORE_IMAGE_ID="$(docker image inspect "$IMAGE_REF" --format '{{.Id}}')"
BEFORE_ROOT="$(docker info --format '{{.DockerRootDir}}')"
printf '%s
' "before_container=$BEFORE_CONTAINER_ID" "before_image=$BEFORE_IMAGE_ID" "before_root=$BEFORE_ROOT" | tee "$EVIDENCE_DIR/before-restart.txt"
If this command reveals unrelated running containers on a native Engine host, do not restart that daemon for the course exercise.
8. Restart safely and verify persistence
Native Linux Engine path:
sudo systemctl restart docker
sudo systemctl is-active docker
Docker Desktop path: use Docker Desktop's supported restart control/CLI for your installed release. Do not kill VM processes manually. After Desktop is healthy again, continue with portable Docker CLI checks below.
docker version
docker context show
AFTER_CONTAINER_ID="$(docker inspect "$LAB_CONTAINER" --format '{{.Id}}')"
AFTER_IMAGE_ID="$(docker image inspect "$IMAGE_REF" --format '{{.Id}}')"
AFTER_ROOT="$(docker info --format '{{.DockerRootDir}}')"
printf '%s
' "after_container=$AFTER_CONTAINER_ID" "after_image=$AFTER_IMAGE_ID" "after_root=$AFTER_ROOT" | tee "$EVIDENCE_DIR/after-restart.txt"
test "$BEFORE_CONTAINER_ID" = "$AFTER_CONTAINER_ID"
test "$BEFORE_IMAGE_ID" = "$AFTER_IMAGE_ID"
The checkpoint is about evidence, not forcing every platform into identical internals. A Desktop learner can prove Docker object persistence without claiming access to the managed VM's systemd process state.
9. Document how this user is authorized to Docker
Choose the statement that matches your environment and attach evidence:
| Observed mode | Evidence | Security interpretation |
|---|---|---|
| Explicit sudo |
Non-sudo denied or unused;
sudo docker version succeeds.
|
Elevation is explicit per command. |
| docker-group socket access | id, group membership, socket ownership. |
User effectively has root-level daemon control; document as privileged access. |
| Rootless |
docker info security options/context/socket
plus subordinate-ID readiness.
|
Daemon itself runs unprivileged; different endpoint/data paths and limitations apply. |
| Desktop-managed user access | Desktop/context/host permission model. | Daemon lives behind Desktop's managed VM/backend and permission mediation. |
10. Required evidence packet
OS/release, architecture, kernel or Desktop backend prerequisites.
Docker repository/Desktop release/manual path and exact package/application versions.
Docker CLI, Engine server, negotiated API, Buildx/Compose versions.
Context name and endpoint; any DOCKER_* overrides.
Data root, storage driver/image store evidence, image ID/digest.
Container ID, status/exit, logs, labels, before/after restart identity.
sudo, docker group, rootless, or Desktop-mediated access with limitations.
What was not observed, what the hello-world check does not prove, and any platform abstraction.
11. Exact cleanup and rollback
docker inspect "$LAB_CONTAINER" --format 'name={{.Name}} labels={{json .Config.Labels}}'
docker rm "$LAB_CONTAINER"
docker ps -a --filter "label=$LAB_LABEL"
printf 'finished=%s
' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" | tee -a "$EVIDENCE_DIR/session.txt"
Do not uninstall Docker or delete the data root unless the entire VM itself is the disposable lab artifact and you intentionally destroy/rebuild the VM. The evidence directory is intentionally outside the Docker data root so it survives container cleanup.
12. Explain every successful state precisely
| Observed success | What it proves | What it does not prove |
|---|---|---|
docker version has Client and Server |
Selected client can reach an Engine and negotiate an API. | Correct context for your intended environment unless endpoint was verified. |
| Image has repository digest | Registry content identity was resolved and is locally known. | Image is vulnerability-free or trusted for production. |
| Container exited 0 | Main process ran and returned success on that daemon. | Application readiness, network exposure, persistent data, or external system health. |
| Same container/image ID after restart | Persistent Docker metadata/content survived control-plane restart. | Every running workload would survive or resume automatically. |
| Cleanup label filter empty | No container with the lab ownership label remains. | No unrelated Docker resources were changed; preserve command history/evidence for that claim. |
Knowledge check
Why must the checkpoint record the active context even on a “local” developer machine?
Because Docker CLI targeting is independent of the shell host. A named or environment-overridden context can send commands to another daemon.
Why is a repository digest stronger checkpoint evidence than
only hello-world:latest?
The tag can move. The digest identifies the exact registry content resolved for this run.
What does unchanged container ID after daemon restart demonstrate?
The container object metadata persisted across daemon process restart. It does not prove that all running processes or external application state persist.
If the evidence packet says “docker group access,” what security note is mandatory?
Docker documents that docker-group membership grants root-level privileges through the rootful daemon, so it must be treated as privileged authorization.
Why is “Desktop VM internals not directly observed” acceptable evidence on Docker Desktop?
Because evidence should respect the supported platform boundary. Portable Docker client/server/context/object evidence is valid; inventing inaccessible host-service details is not.
13. Chapter 02 operational review
You can now install and verify Docker without collapsing software source, client, daemon, endpoint, Desktop VM, persistent data, privilege, and workload state into one checkbox. You can show where the packages or Desktop application came from, which server a client controls, how state survives restart, and why convenience access can expand privilege.
Chapter 03 moves inside the Engine boundary: dockerd, containerd, runc, BuildKit, APIs, and the container lifecycle. The version/context/data-root baseline you created here becomes the evidence foundation for understanding those components without guessing at implementation details.
Official references and version notes
Version-sensitive statements in this chapter were rechecked against primary documentation on 2026-09-20. Installation support, package names, Desktop requirements, component versions, context behavior, rootless prerequisites, and security guidance evolve. Always record the versions and platform facts actually reported by the environment you are operating.
- Install Docker Engine — supported distribution paths, release channels, package-source boundaries, and installation methods.
- Install Docker Engine on Ubuntu — current official apt-repository procedure, package names, verification, and convenience-script caveats.
-
Linux post-installation steps
— service startup and the warning that membership in the
dockergroup grants root-level privileges. - Rootless mode — current prerequisites, subordinate UID/GID requirements, user-service behavior, and limitations.
- Docker contexts — endpoint identity, switching contexts, and portable client configuration.
-
Docker CLI reference
— global flags and environment-variable precedence including
DOCKER_CONTEXTandDOCKER_HOST. - Docker daemon configuration overview — daemon configuration paths, preferred JSON configuration, data root, and validation.
-
dockerd reference
— daemon sockets,
--validate, configuration conflicts, data-root, and runtime options. - Install Docker Desktop on Windows — current WSL 2/Hyper-V/VMM installation requirements, modes, and Windows support boundaries.
- Install Docker Desktop on Mac — current supported macOS window, architecture downloads, and Desktop subscription terms.
-
Install Docker Desktop on Linux
— VM-backed Desktop behavior and the dedicated
desktop-linuxcontext. - Docker Desktop release notes — Docker Desktop 4.91.0 was released 2026-09-14.
- Docker Engine 29 release notes — Docker Engine 29.8.1 was released 2026-09-15.
- Buildx releases — Buildx v0.37.1 was released 2026-09-11.
- BuildKit releases — BuildKit v0.33.0 was released 2026-09-02.
- Compose releases — Docker Compose v5.5.1 was released 2026-09-03.
At this chapter's verification date, Docker Engine 29.8.1 and
Docker Desktop 4.91.0 are current releases, while Buildx 0.37.1,
BuildKit 0.33.0, and Compose 5.5.1 are current upstream releases.
Bundled component versions can differ by Engine/Desktop/package
source. Use docker version, docker info,
docker buildx version, and
docker compose version as execution evidence rather
than assuming those upstream versions are installed.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.