Docker Basics
Docker Architecture — Images, Containers, Daemon
Docker architecture leverages kernel-level isolation to provide portable, consistent environments across development and production infrastructures. By separating the static definition of an application from its active runtime instance, it eliminates environment drift and deployment friction. This architecture is the foundation for modern distributed systems, essential for orchestrating reliable services at scale.
The Docker Daemon: The Orchestration Engine
The Docker Daemon acts as the central control plane, a persistent background process responsible for managing all objects on the host system. It listens for requests from the client interface, translates these commands into system-level operations, and coordinates the lifecycle of images and containers. When you issue a command, the daemon verifies authentication, interacts with storage drivers, and manages the network stack to ensure that resources are allocated securely. It serves as the bridge between your high-level intent and the low-level kernel features that provide isolation. By decoupling the command-line interface from the background service, the architecture allows for remote management and persistent operation, meaning that if your terminal connection drops, the service-level operations initiated by the daemon continue uninterrupted. Understanding the daemon is vital because it explains why local environmental configuration is often isolated from the system shell environment, ensuring consistency.
# Check if the daemon is running and active
sudo systemctl status dockerDocker Images: Static Blueprints for Execution
A Docker Image is an immutable, read-only template that contains the entire filesystem necessary to run an application. It is constructed as a series of layered filesystems, where each layer represents a specific instruction in the build definition. This layering mechanism is a core architectural efficiency; it allows for deduplication, where common base layers (such as a slim distribution of an operating system) are shared across multiple images to save storage and optimize network transmission. Because images are immutable, they provide a cryptographic guarantee that the environment inside is identical regardless of where the image is deployed. When you build an image, you are essentially capturing a frozen state of your application's dependencies and configuration. By treating images as artifacts, you can version them, roll back deployments instantly, and move them through a pipeline with the certainty that the production environment will match the staging environment perfectly.
# Build an image from a Dockerfile in the current directory
docker build -t web-app:v1.0 .Docker Containers: Ephemeral Runtime Instances
A Docker Container is a runnable instance of an image that exists in an isolated user-space. Unlike a virtual machine which virtualizes hardware, a container shares the host's kernel but uses kernel primitives like namespaces to isolate processes, networks, and mount points. This architectural choice makes containers exceptionally lightweight and near-instantaneous to start or stop. When a container starts, the daemon adds a thin, read-write layer on top of the immutable image layers; all changes made during the container's lifecycle, such as temporary files or configuration tweaks, happen in this specific writable layer. This design is critical for stability: because the underlying image remains unchanged, you can discard a container and recreate it from the original image at any time. This ephemerality forces developers to externalize state and configuration, which is the cornerstone of building modern, resilient, and horizontally scalable services.
# Start a container in detached mode using the built image
docker run -d --name my-app-instance -p 8080:80 web-app:v1.0Interaction and Storage Drivers
The storage driver is the architectural component that handles how image layers are assembled into a single, unified filesystem. It uses a Copy-on-Write strategy, which means that files are only copied to the container's writable layer when a modification is actually requested. This is incredibly efficient, as it minimizes disk usage and maximizes performance when multiple containers share the same underlying image. The interaction between the daemon and these drivers is what makes Docker so fast; you can spin up fifty containers from the same image without duplicating the bulk of the underlying filesystem. Understanding this enables you to reason about data persistence. Since the writable layer is tied to the lifecycle of the container, data written there vanishes when the container is deleted. To persist data across container lifecycles, you must explicitly use volumes, which bypass the storage driver's union filesystem layer to store data directly on the host.
# Inspect the current storage driver in use by the daemon
docker info | grep 'Storage Driver'Managing Lifecycle and Resource Constraints
Once containers are running, the Docker daemon serves as the supervisor, monitoring the health of the processes and enforcing resource constraints defined at runtime. You can explicitly limit CPU and memory usage for a container, ensuring that a single faulty process does not consume the host's total resources and starve other services. This supervision is performed via cgroups, which the daemon configures upon container initialization. By observing the container's exit codes and status transitions, the daemon can perform automatic restarts if a process crashes, contributing to a self-healing infrastructure. This lifecycle management makes it easy to maintain predictable performance in multi-tenant environments. Because the daemon tracks these resources centrally, it provides a comprehensive view of system utilization, allowing you to debug bottlenecks effectively by querying the runtime metrics of specific isolated containers rather than the host operating system at large.
# Run a container with limited memory and CPU resources
docker run -d --memory="512m" --cpus="1.0" web-app:v1.0Key points
- The Docker daemon is a persistent background service that acts as the primary coordinator for all container operations.
- Docker images function as immutable, layered blueprints that ensure environment consistency across different systems.
- Containers are lightweight, isolated execution environments that share the host kernel instead of virtualizing hardware.
- The Copy-on-Write storage mechanism allows multiple containers to share common image layers for optimized storage and performance.
- Containers are ephemeral by nature, necessitating the use of external volumes for data that must persist beyond the container's life.
- Kernel namespaces provide the isolation needed to prevent processes in one container from seeing or interacting with others.
- Cgroups allow the daemon to enforce strict resource limits, preventing any single container from exhausting host resources.
- The separation of static images from dynamic containers enables reliable rollbacks and predictable deployments in complex environments.
Common mistakes
- Mistake: Thinking a container is a lightweight virtual machine. Why it's wrong: VMs include a full guest OS, whereas containers share the host kernel. Fix: View containers as isolated processes on the host.
- Mistake: Assuming Docker images are static files. Why it's wrong: Images are read-only templates composed of layered filesystems. Fix: Understand that images are built via layers defined in a Dockerfile.
- Mistake: Running everything inside the container as the root user. Why it's wrong: This increases security vulnerabilities if the process escapes. Fix: Define a specific user in your Dockerfile using the USER instruction.
- Mistake: Storing persistent data inside the container's writable layer. Why it's wrong: Data is lost when the container is deleted. Fix: Use Docker Volumes or Bind Mounts for persistent storage.
- Mistake: Misunderstanding the daemon's role in API requests. Why it's wrong: The CLI is just a client; the Docker Daemon does all the heavy lifting of building and running. Fix: Recognize that the Docker Daemon manages the objects, not the CLI.
Interview questions
What is the fundamental difference between a Docker image and a Docker container?
A Docker image is a read-only, immutable template that contains the source code, libraries, dependencies, and configuration files required to run an application. Think of it as a snapshot or a blueprint. Conversely, a Docker container is a runnable instance of that image. When you execute a command like 'docker run', you create a thin writable layer on top of the image, allowing the container to process data and maintain state. The image provides the structural requirements, while the container provides the active execution environment.
What role does the Docker Daemon (dockerd) play in the overall Docker architecture?
The Docker Daemon, known as 'dockerd', is the central background process that manages all Docker objects. It listens for requests from the Docker API, which are usually sent via the Docker CLI. The daemon is responsible for pulling images from registries, building new images, managing container lifecycles—such as starting, stopping, and restarting—and handling network and volume storage configurations. Without the daemon, the system would have no engine to execute the instructions provided by the user or the orchestrator.
How does the layered architecture of a Docker image improve performance and storage efficiency?
Docker images are built using a series of read-only layers, where each layer represents an instruction in the Dockerfile, such as 'RUN' or 'COPY'. This layered approach uses a union file system to stack changes efficiently. If two images share the same base layers, Docker only stores those files once on the host disk. Furthermore, during a build, if one layer changes, Docker only needs to rebuild that specific layer and its descendants, significantly speeding up the build process and reducing the amount of data transferred across networks.
Compare using 'docker commit' to create images versus using a 'Dockerfile'. Why is the latter preferred in production?
While 'docker commit' allows you to save the state of a container as a new image, it is generally discouraged for production environments because it lacks reproducibility and transparency. Using a 'Dockerfile' is preferred because it treats infrastructure as code. A Dockerfile provides a documented, automated, and repeatable process for building an image. It makes tracking dependencies easy, enables version control, and ensures that the image build process is consistent across different developer environments, which is critical for maintaining stability in complex Docker and Kubernetes deployments.
Explain the interaction between the Docker client, the Docker Daemon, and the Docker Registry.
The interaction follows a client-server architecture. The Docker client is the primary interface; when you type a command like 'docker pull nginx', the client sends that request to the Docker Daemon via the REST API. The daemon then checks its local cache to see if the image exists. If it does not, the daemon communicates with the Docker Registry—a remote storage system like Docker Hub—to download the required image layers. Once retrieved, the daemon manages the creation of the container, completing the full lifecycle request initiated by the user.
How do Docker containers interact with the host kernel, and why does this make them more lightweight than virtual machines?
Docker containers utilize operating system-level virtualization, meaning they share the host system's kernel rather than having their own guest OS. In a virtual machine, each instance requires a full-blown guest operating system and virtualized hardware, which consumes massive amounts of RAM and CPU. In contrast, Docker uses features like Linux namespaces to isolate the process environment and cgroups to manage resource allocation. Because containers do not duplicate the kernel or hardware abstraction layers, they boot in milliseconds and require significantly less overhead, making them ideal for high-density microservices within a Kubernetes cluster.
Check yourself
1. When you execute 'docker run', what is the specific role of the Docker Daemon?
- A.It acts as a graphical user interface for managing images.
- B.It receives instructions from the CLI, pulls images if missing, and manages container lifecycles.
- C.It translates the container code into machine-readable kernel bytecode.
- D.It provides a persistent database for storing container metadata outside of the host OS.
Show answer
B. It receives instructions from the CLI, pulls images if missing, and manages container lifecycles.
The Daemon acts as the server-side API handler. Option 0 is wrong because the daemon is headless. Option 2 is wrong because Docker uses native host features. Option 3 is wrong because Docker manages its own local storage for metadata.
2. What happens to the changes made to the filesystem during the execution of a container?
- A.They are permanently saved to the original image.
- B.They are discarded immediately when the container process stops.
- C.They are stored in a thin writable layer on top of the image layers.
- D.They are synced automatically to a central registry.
Show answer
C. They are stored in a thin writable layer on top of the image layers.
The writable layer is the defining feature of a running container. Option 0 is wrong because images are immutable. Option 1 is wrong because data persists until the container is removed. Option 3 is wrong because synchronization is a manual 'docker push' process.
3. Why does a Docker container usually start much faster than a Virtual Machine?
- A.Containers use a specialized faster programming language for execution.
- B.Containers do not need to boot a full guest operating system kernel.
- C.The Docker Daemon pre-allocates RAM for every possible container.
- D.Containers bypass the host network stack entirely.
Show answer
B. Containers do not need to boot a full guest operating system kernel.
Containers share the host kernel, skipping the 'hardware initialization' phase of a VM boot. Option 0 is irrelevant. Option 2 is false as resources are allocated on demand. Option 3 is false as containers typically use virtualized network interfaces.
4. How are Docker image layers utilized during the build process?
- A.Each command in a Dockerfile creates a new read-only layer cached for future builds.
- B.Layers are merged into a single compressed binary file once the build is finished.
- C.Layers are only used to separate the application code from the operating system.
- D.Layers are random segments of the image used to increase download speeds.
Show answer
A. Each command in a Dockerfile creates a new read-only layer cached for future builds.
Docker uses a union filesystem where each instruction adds a layer. Option 1 is wrong because layers remain separate entities. Option 2 is wrong as layer separation is granular. Option 3 is wrong as layers are not random.
5. If you need to persist a database's data beyond the container's lifecycle, what is the best practice?
- A.Copy the data to the image using the COPY instruction.
- B.Mount a volume or bind mount to map a host directory to the container path.
- C.Enable the 'persistent' flag in the Docker Daemon configuration.
- D.Save the container state as a new image using 'docker commit'.
Show answer
B. Mount a volume or bind mount to map a host directory to the container path.
Volumes bypass the container's ephemeral writable layer. Option 0 is wrong as image layers are read-only. Option 2 is wrong as no such flag exists. Option 3 is bad practice as it creates large, unmanageable images.