Homelab Academy / Modules
Guided practice + break/fix + lab gate.
Module: Docker, Storage & Permissions
Activity type: Lab (Practice)
Lab risk: low
Objective: Explain the responsibilities of the Docker CLI, Docker daemon, containerd, and OCI runtime
Inventory and Safely Stage a Docker Daemon Configuration
Every command that writes data targets /opt/lab-classroom/class27/. Do not install packages, start or stop services, launch dockerd, edit system daemon configuration, or change Docker's active data directory during this lab.
1
Create the isolated workspace
install -d /opt/lab-classroom/class27/runtime /opt/lab-classroom/class27/docker-data /opt/lab-classroom/class27/docker-exec
These directories hold all generated class files and staged runtime paths.
2
Capture a read-only host inventory
{ printf '%s\n' 'Class 27 host inventory'; printf 'Kernel: '; uname -srmo; printf 'Architecture: '; uname -m; printf 'docker CLI: '; command -v docker || printf '%s\n' 'not installed'; printf 'dockerd: '; command -v dockerd || printf '%s\n' 'not installed'; printf 'containerd: '; command -v containerd || printf '%s\n' 'not installed'; } > /opt/lab-classroom/class27/host-inventory.txt
cat /opt/lab-classroom/class27/host-inventory.txt
The discovery commands read host information, while their output is written only inside the permitted workspace.
3
Create an installation decision record
printf '%s\n' 'Installation source: official instructions for the detected operating system' 'Repository provenance must be verified before use: yes' 'Target architecture must match host inventory: yes' 'Maintenance window required: yes' 'Package and service changes executed in this lab: no' 'Rollback must be documented before installation: yes' > /opt/lab-classroom/class27/installation-plan.txt
cat /opt/lab-classroom/class27/installation-plan.txt
The record separates installation planning from execution and prevents an unreviewed system change.
4
Stage a daemon configuration
printf '%s\n' '{' ' "data-root": "/opt/lab-classroom/class27/docker-data",' ' "exec-root": "/opt/lab-classroom/class27/docker-exec",' ' "pidfile": "/opt/lab-classroom/class27/runtime/docker.pid",' ' "hosts": ["unix:///opt/lab-classroom/class27/runtime/docker.sock"],' ' "log-driver": "local",' ' "log-opts": {' ' "max-size": "10m",' ' "max-file": "3"' ' },' ' "live-restore": true' '}' > /opt/lab-classroom/class27/daemon.json
cat /opt/lab-classroom/class27/daemon.json
This inactive configuration demonstrates persistent daemon options. Every filesystem path remains under the class workspace.
5
Validate JSON syntax
if command -v jq >/dev/null 2>&1; then jq empty /opt/lab-classroom/class27/daemon.json && printf '%s\n' 'JSON syntax: valid'; elif command -v python3 >/dev/null 2>&1; then python3 -m json.tool /opt/lab-classroom/class27/daemon.json >/dev/null && printf '%s\n' 'JSON syntax: valid'; else printf '%s\n' 'SKIP: neither jq nor python3 is available'; fi
JSON parsing detects commas, quotation, braces, and structural errors before daemon-specific validation.
6
Perform daemon-specific validation when supported
if command -v dockerd >/dev/null 2>&1; then dockerd --validate --config-file /opt/lab-classroom/class27/daemon.json; else printf '%s\n' 'SKIP: dockerd is not installed'; fi
The validation mode reads the staged file but does not start a daemon. If the installed release does not support a directive or validation mode, record the exact error instead of launching dockerd.
7
Confirm the lab boundary
find /opt/lab-classroom/class27/ -maxdepth 2 -printf '%y %p\n' | sort
The listing provides an auditable view of the workspace created by the lab.
| Symptom | Likely cause | Fix |
|---|---|---|
| Creating /opt/lab-classroom/class27/ fails with permission denied. | The current user does not have permission to create directories under /opt/lab-classroom. | Have an administrator pre-create /opt/lab-classroom/class27/ and assign appropriate ownership for the learner. Do not redirect the lab to unrelated system paths. |
| The JSON parser reports an error. | A quote, comma, brace, or value was changed while creating daemon.json. | Compare the file with the staged configuration in the lab, correct only /opt/lab-classroom/class27/daemon.json, and rerun syntax validation. |
| dockerd reports that --validate is unknown. | The installed Docker daemon is older or packaged without the expected validation behavior. | Record the installed version, retain the successful generic JSON validation, and consult the documentation matching that exact release. Do not start a second daemon as a substitute. |
| dockerd validation reports a duplicated hosts option. | The active service definition may already pass a hosts argument, and the daemon rejects settings supplied through both startup arguments and configuration. | For a future approved deployment, choose one authoritative location for the hosts setting and test the change in a maintenance window. Do not alter the active service during this lab. |
| The Docker CLI exists but reports that it cannot connect to the daemon. | The daemon may be absent, stopped, using a different context or socket, or inaccessible to the user. | Inspect the selected Docker context, expected endpoint, daemon service status, and user authorization. Do not assume that reinstalling the client will repair a daemon connectivity problem. |
| Docker commands return permission denied for the API socket. | The current user is not authorized to access the rootful daemon socket. | Use the organization's approved administrative workflow. Treat daemon access as privileged and do not broaden socket permissions as a shortcut. |
| A real daemon fails after a configuration change. | The file may contain unsupported settings, conflicting startup arguments, inaccessible paths, or storage configuration incompatible with the host. | Review the earliest daemon log error, restore the last known-good configuration using the prepared rollback procedure, validate it, and then restart only within the approved change window. |
| Images or containers appear missing after changing data-root. | The daemon is reading a different storage location rather than the original Docker state. | Stop further changes, identify the previous data root, and follow a tested migration or rollback plan. Do not copy active Docker state while the daemon is writing to it. |
Treat control of a rootful Docker daemon as administrative control of the host.
Grant local daemon access only to identities that are authorized for host-level administration.
Do not expose an unauthenticated or unencrypted daemon API to a network.
Verify repository provenance, signing configuration, operating-system support, and package architecture before installation.
Pin or otherwise control versions when reproducible deployments are required.
Use bounded logging and monitor both the Docker data filesystem and the host log filesystem.
Prefer minimal container privileges, read-only filesystems where practical, explicit mounts, and narrowly scoped capabilities.
Review third-party images, use trusted registries, and track image digests or approved tags according to policy.
Keep secrets out of daemon configuration, image layers, command history, and ordinary environment files.
Back up application data according to the storage system's consistency requirements; image caches are not substitutes for backups.
Possession of the Docker API socket can allow an operator or process to create highly privileged containers, mount host filesystems, and control workloads. Filesystem permissions around the socket are a security boundary, not a convenience setting.
Rootless mode can reduce exposure to a privileged system daemon, but it does not eliminate container security risks and may have networking, storage, resource-management, or port-binding differences.
Remove only the class workspace through the classroom's approved cleanup process. The lab does not provide a destructive cleanup command because preserving the files may be useful for review and no system configuration was changed.
Record current package versions, service state, active daemon configuration, Docker data root, and storage driver before making changes.
Back up configuration files and application data using methods appropriate to the workload.
Keep the previously approved package version available when organizational policy and repository retention permit.
If a new daemon configuration prevents startup, restore the last known-good configuration, validate it, and restart the service in the maintenance window.
Do not delete the Docker data root as an uninstall shortcut; it may contain persistent application volumes and other required state.
Verify daemon health, expected containers, networks, volumes, logs, and application functionality after rollback.
Rollback is complete only when the intended daemon version and configuration are restored, the daemon is healthy, expected workloads and persistent data are available, and monitoring shows no continuing storage or connectivity errors.