Documentation Index
Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
Use this file to discover all available pages before exploring further.
Docker Fundamentals
Master the core concepts of Docker containerization and understand how containers revolutionized software deployment.What is Docker?
Docker is a platform for developing, shipping, and running applications in containers. Containers package your application with all its dependencies, ensuring it runs consistently across different environments.Lightweight
Portable
Fast
Isolated
Images vs Containers
Understanding the difference is crucial — confusing these two is the most common beginner mistake.Docker Images
- Blueprint for containers (like a class in OOP, or a recipe in cooking)
- Read-only template — once built, an image never changes
- Contains application code, runtime, libraries, dependencies — everything needed to run
- Stored in registries (Docker Hub, private registries like AWS ECR or Google GCR)
- Built from a Dockerfile using
docker build
Docker Containers
- Running instance of an image (like an object in OOP, or a cake baked from a recipe)
- Writable layer on top of the read-only image layers
- Isolated process with its own filesystem, network, and process tree
- Can be started, stopped, restarted, and deleted
- You can run multiple containers from the same image — each is independent
Docker Architecture
Docker uses a client-server architecture:Components
Docker Client (docker):
- Command-line interface
- Sends commands to Docker daemon
- Can communicate with remote daemons
dockerd):
- Background service
- Builds, runs, manages containers
- Listens for Docker API requests
- Stores Docker images
- Docker Hub (public)
- Private registries (AWS ECR, Google GCR, Azure ACR)
Installing Docker
- Windows
- macOS
- Linux (Ubuntu)
Essential Docker Commands
Working with Images
Working with Containers
Container Interaction
Practical Examples
Example 1: Running Nginx Web Server
Example 2: Running a Database
Example 3: Interactive Container
Container Lifecycle
Common Flags and Options
Environment Variables
Environment variables are the standard way to pass configuration into containers. This follows the 12-Factor App methodology — configuration lives outside the code, making the same image deployable to dev, staging, and production.Docker System Commands
Docker accumulates a surprising amount of disk space over time — stopped containers, unused images, build cache layers. On a developer machine it is not unusual to reclaim 20-50GB after a cleanup.Best Practices
Use Specific Image Tags
Use Specific Image Tags
Name Your Containers
Name Your Containers
Clean Up Regularly
Clean Up Regularly
Use --rm for Temporary Containers
Use --rm for Temporary Containers
Troubleshooting
Container Won’t Start
Permission Denied
Container Keeps Restarting
Key Takeaways
- Docker containers are lightweight, portable, and fast
- Images are blueprints, containers are running instances
- Use
docker runto create and start containers - Use
docker psto list containers - Use
docker logsto debug - Clean up regularly with
docker system prune
Container Internals (Critical for Interviews!)
Understanding what makes containers work under the hood is essential for senior roles.Linux Namespaces
Namespaces provide isolation. Each container gets its own view of:| Namespace | Isolates |
|---|---|
| PID | Process IDs (container sees itself as PID 1) |
| NET | Network stack (own IP, ports, routing) |
| MNT | Filesystem mounts |
| UTS | Hostname and domain name |
| IPC | Inter-process communication |
| USER | User and group IDs |
Control Groups (cgroups)
Cgroups provide resource limiting:Union Filesystem (OverlayFS)
Docker images use layered filesystems:OCI (Open Container Initiative)
The industry standard for container formats and runtimes.OCI Standards
| Standard | Description |
|---|---|
| Image Spec | How container images are built and distributed |
| Runtime Spec | How containers are executed |
| Distribution Spec | How images are pushed/pulled from registries |
Container Runtimes
| Runtime | Description | Use Case |
|---|---|---|
| containerd | Industry standard, used by Docker/K8s | Production |
| CRI-O | Lightweight, Kubernetes-native | Kubernetes |
| runc | Low-level runtime (OCI reference) | Building runtimes |
| gVisor | Sandboxed (user-space kernel) | Security-critical |
| Kata Containers | VM-based isolation | Multi-tenancy |
Docker Security Best Practices
1. Run as Non-Root
2. Read-Only Filesystem
3. Drop Capabilities
4. Security Scanning
Interview Questions & Answers
What is the difference between a container and a VM?
What is the difference between a container and a VM?
| Aspect | Container | Virtual Machine |
|---|---|---|
| Isolation | Process-level (namespaces) | Hardware-level (hypervisor) |
| Kernel | Shares host kernel | Has own kernel |
| Size | MBs | GBs |
| Startup | Seconds | Minutes |
| Resource Usage | Low overhead | High overhead |
| Security | Weaker isolation | Stronger isolation |
What are namespaces and cgroups?
What are namespaces and cgroups?
- PID namespace: Own process tree
- NET namespace: Own network stack
- MNT namespace: Own filesystem view
- CPU limits
- Memory limits
- I/O bandwidth
What happens when you run 'docker run nginx'?
What happens when you run 'docker run nginx'?
- Docker CLI sends request to Docker daemon
- Daemon checks if image exists locally
- If not, pulls from registry (Docker Hub)
- Creates a new container from image layers
- Allocates a read-write layer on top
- Creates network interface and assigns IP
- Starts the container process with namespaces and cgroups
- Executes the CMD/ENTRYPOINT
What is the difference between CMD and ENTRYPOINT?
What is the difference between CMD and ENTRYPOINT?
| Instruction | Behavior | Overridable |
|---|---|---|
| CMD | Default command/arguments | Yes, with docker run args |
| ENTRYPOINT | Main executable | Only with —entrypoint |
How do you debug a container that keeps crashing?
How do you debug a container that keeps crashing?
- Check logs:
docker logs container_name - Inspect:
docker inspect container_name - Run interactively:
docker run -it image sh - Override entrypoint:
docker run --entrypoint sh image - Check events:
docker events - Resource issues:
docker stats
What is Docker BuildKit?
What is Docker BuildKit?
- Parallel builds: Build independent stages concurrently
- Better caching: Cache mounts for package managers
- Secret mounting: Don’t bake secrets into layers
- SSH forwarding: Clone private repos during build
DOCKER_BUILDKIT=1 docker build .Common Pitfalls
Interview Deep-Dive
A container is running but the application inside is not responding to requests. docker ps shows it as 'Up.' Walk me through your debugging process from start to finish.
A container is running but the application inside is not responding to requests. docker ps shows it as 'Up.' Walk me through your debugging process from start to finish.
- First, I check the application logs:
docker logs --tail 200 container_name. Most issues surface here — unhandled exceptions, configuration errors, or “listening on wrong address” messages. I look for any error or panic in the last few hundred lines. - If logs look normal, I check resource constraints:
docker stats container_name. The container might be CPU-throttled (showing high CPU percentage near its limit) or memory-constrained. I also checkdocker inspect --format='{{.State.OOMKilled}}' container_name— if the application was OOM-killed and restarted, it might be in a crash loop where it starts, allocates memory, gets killed, restarts, and the cycle repeats. - Next, I try to exec into the container:
docker exec -it container_name sh. If the shell opens, I check if the process is actually running (ps aux), what ports it is listening on (netstat -tlnporss -tlnp), and whether it can reach its dependencies (e.g.,nc -zv db 5432for a database). - If the process is listening on
127.0.0.1instead of0.0.0.0, that is the bug — the application is only accepting connections from inside the container, not from the Docker bridge network. This is extremely common with Node.js, Python Flask, and Go HTTP servers where the default bind address is localhost. - If I cannot exec in (distroless image, no shell), I use a debug sidecar:
docker run --net container:target_container nicolaka/netshootgives me network tools in the target container’s network namespace. - Finally, I check if the port mapping is correct:
docker port container_nameshould show the expected host-to-container mapping. A mismatch here means traffic is not reaching the container at all.
sudo iptables -t nat -L -n | grep 3000 to verify the DNAT rule exists. On macOS/Windows, Docker Desktop runs inside a VM, so “host” means the VM, not the laptop — and Docker Desktop’s network layer can occasionally need a restart. I would also check if another process on the host already has that port bound: lsof -i :3000 (Linux/macOS) or netstat -an | findstr 3000 (Windows).Explain what happens at the Linux kernel level when you run 'docker run -d -p 8080:80 --memory=512m nginx'. Be as specific as you can.
Explain what happens at the Linux kernel level when you run 'docker run -d -p 8080:80 --memory=512m nginx'. Be as specific as you can.
- The Docker CLI sends a POST to the Docker daemon at
/var/run/docker.sock. The daemon delegates to containerd via gRPC, which in turn invokes runc — the low-level OCI runtime that does the actual kernel work. - Namespace creation: runc creates a new set of Linux namespaces using the
clone()syscall with flags likeCLONE_NEWPID(process isolation),CLONE_NEWNET(network isolation),CLONE_NEWNS(mount isolation),CLONE_NEWUTS(hostname isolation), andCLONE_NEWIPC(IPC isolation). The nginx process believes it is PID 1 in its own world. - Cgroup setup: runc writes to
/sys/fs/cgroup/memory/docker/<container_id>/memory.limit_in_bytesto set the 512MB memory limit. It also configures the memory cgroup’s OOM killer behavior. If nginx exceeds 512MB, the kernel OOM killer terminates the process — no graceful shutdown, just gone. - Filesystem setup: runc mounts the image layers using OverlayFS. The read-only image layers become the “lower” directories, and a fresh writable layer becomes the “upper” directory. The unified mount point becomes the container’s root filesystem. This is copy-on-write: reads come from lower layers, writes go to the upper layer.
- Networking: Docker creates a virtual ethernet pair (veth). One end goes into the container’s network namespace (visible as
eth0inside the container), the other connects to thedocker0bridge on the host. Docker then inserts an iptables DNAT rule that forwards TCP traffic arriving at the host on port 8080 to the container’s IP on port 80. - Process execution: runc executes the nginx entrypoint. runc itself exits after setup — it is not a long-running daemon. containerd monitors the running process via its shim.
You are reviewing a teammate's Dockerfile and see 'FROM node:latest'. They say it is fine because 'latest just means the most recent stable version.' Convince them otherwise with a concrete production scenario.
You are reviewing a teammate's Dockerfile and see 'FROM node:latest'. They say it is fine because 'latest just means the most recent stable version.' Convince them otherwise with a concrete production scenario.
latestis not a version — it is a moving pointer. Docker Hub maintainers update thelatesttag whenever they push a new image. There is no guarantee about whatlatestpointed to yesterday versus today.- Concrete scenario: On Monday, your CI/CD pipeline builds and deploys successfully.
node:latestresolves to Node 18.19.0. On Wednesday, the Node.js team pushes Node 20.11.0 and updates thelatesttag. On Thursday, your pipeline runs again, pulls Node 20, and now your application breaks because a dependency is incompatible with the new V8 engine. You have changed zero lines of code, yet your build is broken. - Worse: this failure is non-deterministic. The exact same Dockerfile produces different images on different days. You cannot reproduce the Monday build because
latestno longer points to Node 18. Your Docker layer cache may mask this locally (you still have the old image cached), but CI runners typically start fresh. - The fix: always pin to a specific version and variant:
node:18.19.0-alpine3.19. This guarantees byte-identical builds across time and environments. Update the version intentionally, not accidentally, by changing the tag in the Dockerfile and testing the upgrade. - For extra safety in regulated environments, pin to the image digest:
node@sha256:abc123.... This is immutable — even if someone retags the image, the digest never changes.
Next: Building Docker Images →