From your first container to production-grade Swarm clusters. This course walks you through every domain on the DCA exam — images, networking, volumes, orchestration, and security — with hands-on commands and real-world scenarios.
Understand what containers are, how they differ from VMs, and the components that make Docker work. This is the foundation everything else builds on.
VMs virtualize hardware and each runs a full OS kernel. Containers share the host kernel and isolate at the process level using Linux namespaces and cgroups — they are faster to start, use less memory, and are more portable.
docker command, communicates with dockerd via REST API over the Unix socket or TCP# Run a container interactively
docker run -it ubuntu bash
# Run detached with name and port mapping
docker run -d --name webserver -p 8080:80 nginx
# List running containers
docker ps
# List all containers (including stopped)
docker ps -a
# Stop and remove
docker stop webserver && docker rm webserver
# Pull image without running
docker pull alpine:3.19
# Show image layers
docker history nginx:latest
docker run = docker create + docker start. Understanding this distinction matters — containers can exist in stopped state without consuming CPU or RAM, but still use disk space for their writable layer.
docker stop (sends SIGTERM, waits 10s, then SIGKILL) and docker kill (sends SIGKILL immediately). Also know that docker rm -f force-removes a running container.
Building images is a core DCA domain. Master Dockerfile instructions, layer caching, multi-stage builds, and image management from pull to push to registry.
&& to minimize layers--build-arg; not available at runtime (unlike ENV)docker runENTRYPOINT ["nginx"] + CMD ["-g", "daemon off;"] — running docker run myimage -t replaces CMD but keeps ENTRYPOINT.
Multi-stage builds drastically reduce final image size by using intermediate build stages that are discarded:
# Stage 1: build
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .
# Stage 2: minimal runtime image
FROM alpine:3.19
WORKDIR /app
COPY --from=builder /app/myapp .
USER nobody
CMD ["./myapp"]
COPY package.json . → RUN npm install → COPY . ..dockerignore to exclude node_modules, .git, test files from the build context--no-cache flag to force a clean rebuild: docker build --no-cache .# Build with tag
docker build -t myapp:1.0 .
# Tag an existing image
docker tag myapp:1.0 registry.example.com/myapp:1.0
# Push to registry
docker push registry.example.com/myapp:1.0
# Inspect image layers
docker inspect myapp:1.0
# Remove dangling images (untagged)
docker image prune
# Remove all unused images
docker image prune -a
# Save image to tar archive
docker save myapp:1.0 | gzip > myapp.tar.gz
# Load image from tar
docker load < myapp.tar.gz
docker save preserves image history and layers (use for image migration). docker export exports a container's filesystem as a flat tar (loses history). docker import creates a new image from a tar but without layer history.
Containers are ephemeral — any data written inside is lost when the container is removed. Storage drivers and mount types solve this problem for different scenarios.
/var/lib/docker/volumes/; best for persistent data, shareable between containers, portable# Named volume (--mount syntax, preferred)
docker run -d \
--mount type=volume,src=mydata,dst=/app/data \
postgres:16
# Bind mount
docker run -d \
--mount type=bind,src=/home/user/config,dst=/app/config,readonly \
myapp
# tmpfs mount (Linux only)
docker run -d \
--mount type=tmpfs,dst=/tmp \
myapp
# Volume operations
docker volume create mydata
docker volume ls
docker volume inspect mydata
docker volume rm mydata
docker volume prune # removes all unused volumes
-v flag syntax and the new --mount flag syntax. The --mount flag is explicit, self-documenting, and preferred. A key difference: -v creates the host path if it doesn't exist; --mount type=bind requires the path to already exist.
Docker uses storage drivers to manage the image layers and writable container layer on the host. Common drivers:
Docker networking isolates and connects containers. Understanding each driver's use case and behavior is tested heavily on the DCA exam.
bridge network, containers cannot communicate by name — only by IP. On a custom bridge network, Docker's embedded DNS server resolves container names automatically. Always use custom bridge networks for production compose setups.
# Create a custom bridge network
docker network create --driver bridge mynet
# Run containers on the same network
docker run -d --name db --network mynet postgres:16
docker run -d --name app --network mynet myapp
# app can reach db at hostname "db"
# Inspect a network
docker network inspect mynet
# Connect a running container to a network
docker network connect mynet existing_container
# List networks
docker network ls
# Remove unused networks
docker network prune
-p 8080:80 — maps host port 8080 to container port 80 (TCP)-p 127.0.0.1:8080:80 — binds to localhost only (more secure)-p 8080:80/udp — UDP port mapping-P — publishes all EXPOSE'd ports to random host portsdocker network create --driver overlay myoverlay), Swarm automatically manages the VXLAN tunnels between nodes. Services on the same overlay network can reach each other by service name, and Swarm handles load balancing across replicas.
Docker Swarm is Docker's native clustering and orchestration system. The DCA exam allocates 25% of its questions to Swarm — it's the heaviest domain.
# Initialize Swarm on the first manager
docker swarm init --advertise-addr 192.168.1.10
# Get join tokens
docker swarm join-token worker
docker swarm join-token manager
# Join as worker (run on worker node)
docker swarm join --token SWMTKN-1-xxx 192.168.1.10:2377
# List nodes
docker node ls
# Promote worker to manager
docker node promote node2
# Drain a node before maintenance
docker node update --availability drain node3
# Create a replicated service
docker service create \
--name webapp \
--replicas 3 \
--publish published=80,target=8080 \
--mount type=volume,src=appdata,dst=/data \
myapp:1.0
# Scale a service
docker service scale webapp=5
# Update image with rolling update
docker service update \
--image myapp:2.0 \
--update-parallelism 1 \
--update-delay 10s \
--update-failure-action rollback \
webapp
# Inspect service tasks
docker service ps webapp
# Remove a service
docker service rm webapp
docker service create --mode global .../run/secrets/<secret_name># Create a secret from stdin
echo "mysecretpassword" | docker secret create db_password -
# Use secret in a service
docker service create \
--name mydb \
--secret db_password \
--env DB_PASSWORD_FILE=/run/secrets/db_password \
postgres:16
# List secrets
docker secret ls
Docker Swarm's routing mesh allows any node in the cluster to accept requests on a published port, even if that node isn't running a service task. Incoming traffic is load-balanced across all healthy replicas using the ingress overlay network and IPVS.
mode=host in --publish bypasses the mesh and maps directly to the host port — only the node running the task can receive the traffic. Useful for performance-sensitive services that don't need load balancing.
Security is 15% of the DCA exam. Master Linux capabilities, content trust, seccomp, namespaces, and image scanning to build a defense-in-depth container security posture.
--memory 512m --cpus 1.5 prevents a single container from starving the host--cap-add NET_ADMIN; Drop: --cap-drop ALL. Never use --privileged in production.--security-opt seccomp=profile.json.docker-default) on supported systemsDCT uses Notary (TUF — The Update Framework) to cryptographically sign and verify images. When enabled, Docker refuses to pull unsigned images.
# Enable DCT for the current shell session
export DOCKER_CONTENT_TRUST=1
# Sign an image when pushing (requires keys to be set up)
docker push myregistry.com/myapp:1.0
# Inspect image signature
docker trust inspect --pretty myapp:1.0
# Run as non-root user
docker run --user 1000:1000 myapp
# Read-only root filesystem
docker run --read-only myapp
# Drop all capabilities, add only what's needed
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp
# No new privileges (prevents privilege escalation)
docker run --security-opt no-new-privileges myapp
# Resource limits
docker run --memory 512m --cpus 1 myapp
docker scout or TrivyUSER in Dockerfile)nginx@sha256:abc123...userns-remap in /etc/docker/daemon.json. Even if a container breakout occurs, the attacker gets an unprivileged shell on the host. High-security environments should enable this.
Take the 60-question DCA practice exam — Swarm, security, networking, and images. Free, no signup, instant scoring with explanations.