Skip to main content

Command Palette

Search for a command to run...

Mastering Docker: Key Concepts and Architecture

Updated
12 min read
Mastering Docker: Key Concepts and Architecture
S
Software Engineer at HTC

1. The "Matrix from Hell" and the Need for Docker

The core problem Docker addresses is the "compatibility matrix from hell" – a significant challenge in traditional application development and deployment. There have been times when difficulties faced when setting up an application stack with various technologies (web server(nodejs), database(mongodb), messaging system(redis),orchestration tool(ansible)) due to:

  • OS Compatibility: Ensuring all services were compatible with the chosen operating system version. (There have been times when certain version of these services were not compatible with the OS).

  • Dependency Conflicts: Services requiring different versions of the same dependent libraries, leading to conflicts.

  • Environmental Inconsistencies: Different development, testing, and production environments, and developers using various operating systems, made it impossible to guarantee consistent application behaviour across all environments. we couldn't guarantee that the application that we were building would run the same way in different environments.

  • Onboarding Challenges: New developers had to run "hundreds of commands" and a complex setup process to get their environments ready, ensuring the correct OS and component(service) versions has been used in the setup

  • Resource underutilisation: Containers are the next step in improving server resource utilisation after physical servers and virtual machines (VMs). Physical servers suffered from heavy underutilisation of CPU and memory. Virtualisation solved this by allowing multiple VMs—with full, isolated operating systems—to run on a single server, improving efficiency and security (e.g., AWS EC2 using hypervisors). However, VMs still waste resources because applications rarely use all allocated capacity. Containers address this inefficiency by being a further advancement over VMs, reducing resource wastage and cost, especially at large scale.

These issues made developing, building, and shipping the application really difficult, driving the search for a solution that offered compatibility, isolation, and flexibility.

2. Introducing Docker and Containers: Isolated Environments

What is a container ?

A container is a bundle of Application, Application libraries required to run your application and the minimum system dependencies.

A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.

Docker emerged as the solution to these challenges. Its fundamental contribution is the concept of containers

  • With docker we can run each component/service in separate container with its own dependencies and libraries

  • Isolated Environments: Containers are logically isolated environments with their own processes, networking, and mounts, enforced using namespaces and cgroups.

  • Shared Kernel: Crucially, unlike virtual machines, containers all share the same OS kernel. Linux Docker host can only run Linux-based containers (though different Linux distributions are fine).

  • Simplicity and Consistency: With Docker, the configuration is built once, and developers can then get started with a simple Docker Run command, irrespective of what the underlying operating system, they are on. This ensures the application is guaranteed to run the same way everywhere.

  • Containers are a lightweight solution to resource inefficiency in VMs. A container packages an application with its libraries and system dependencies, but unlike VMs, it does not include a full operating system. Instead, containers share the host OS kernel while using a minimal base image. This makes them much smaller (MBs vs GBs), faster to ship, and more resource-efficient. Containers provide logical isolation, but it is generally weaker than VMs, which offer stronger isolation due to full OS separation.

  • Containers efficiently utilise resources because stopped containers do not consume kernel resources like CPU or memory (but their metadata and writable layer still exist on disk), allowing dozens of containers to run on a single VM. Unlike VMs, they share the host OS kernel instead of running separate guest operating systems. Containers maintain logical isolation using minimal system dependencies (via namespaces and cgroups) while optionally leveraging host resources such as the filesystem, networking, and system calls. Containers use their own filesystem layers, but can optionally access the host filesystem via bind mounts or volumes.Their lightweight nature makes them dramatically smaller—e.g., Ubuntu container images are tens of MBs, while Ubuntu VM images are several GBs.

3. Docker vs. Virtual Machines: Key Differences

  • Resource Utilisation: VMs are heavier, each requiring its own OS inside it, leading to higher utilisation of underlying resources and consuming higher disk space (gigabytes). Docker containers are light weight (megabytes) because they share the host OS kernel.

  • Boot-up Time: Containers boot up faster, usually in a matter of seconds, compared to VMs, which takes minutes to boot up as it needs to boot up the entire operating system.

  • Isolation: VMs offer complete isolation from each other, each with its own OS and kernel, allowing for diverse OS applications on a single hypervisor. Docker containers have less isolation as more resources are shared between the containers, like the kernel.

  • Purpose: Docker's main purpose is to package and containerise applications and to ship them and to run them anywhere, any times, as many times as you want. VMs are primarily for virtualizing and running different operating systems and kernels on the same hardware.

  • Screenshot 2023-02-07 at 7 18 10 PM

    Importantly, the relationship is not either container or virtual machine, but containers and virtual machines. In large-scale environments, containers are provisioned on virtual docker hosts, combining the advantages of both: VM flexibility for provisioning/decommissioning Docker hosts, and Docker's efficiency for provisioning/scaling applications.

Files and Folders comparison:

To provide a better picture of files and folders that containers base images have and files and folders that containers use from host operating system (not 100 percent accurate -> varies from base image to base image). Refer below.

Files and Folders in containers base images

    /bin: contains binary executable files, such as the ls, cp, and ps commands.

    /sbin: contains system binary executable files, such as the init and shutdown commands.

    /etc: contains configuration files for various system services.

    /lib: contains library files that are used by the binary executables.

    /usr: contains user-related files and utilities, such as applications, libraries, and documentation.

    /var: contains variable data, such as log files, spool files, and temporary files.

    /root: is the home directory of the root user.

Files and Folders that containers use from host operating system

    The host's file system: Docker containers can access the host file system using bind mounts, which allow the container to read and write files in the host file system.

    Networking stack: The host's networking stack is used to provide network connectivity to the container. Docker containers can be connected to the host's network directly or through a virtual network.

    System calls: The host's kernel handles system calls from the container, which is how the container accesses the host's resources, such as CPU, memory, and I/O.

    Namespaces: Docker containers use Linux namespaces to create isolated environments for the container's processes. Namespaces provide isolation for resources such as the file system, process ID, and network.

    Control groups (cgroups): Docker containers use cgroups to limit and control the amount of resources, such as CPU, memory, and I/O, that a container can access.

It's important to note that while a container uses resources from the host operating system, it is still isolated from the host and other containers, so changes to the container do not affect the host or other containers

4. Docker Container vs Docker image

In the simplest terms, a Docker image is a blueprint or template, while a Docker container is a running instance of that blueprint. Think of it like this:

  • A Docker Image is a class definition in programming. It's a static, read-only file that contains all the instructions needed to create a container. This includes the application's code, runtime, system tools, libraries, and configurations. Images are built from a Dockerfile and are stored in a registry like Docker Hub for sharing. They are immutable—you can't change an image once it's created.

  • A Docker Container is an object or instance of that class. It's a live, running environment that is created from a Docker image. When you run an image, Docker creates a container with a writable layer on top of the immutable image layers. Any changes you make inside the running container (e.g., adding a new file) are saved to this writable layer, but the original image remains untouched. Containers can be started, stopped, moved, and deleted.

  • image

Life Cycle of Docker:

  1. Docker File: A Docker file (similar to a script file) is written to define the container's environment and application.

  2. Docker Engine: The Docker file is submitted to the Docker engine using Docker commands.

  3. Docker Image: The Docker engine converts the Docker file into a Docker image (or container image).

  4. Container: The Docker image is then used to create a container.

Key Differences

FeatureDocker ImageDocker Container
NatureTemplate/BlueprintLive, running instance
StateStatic and read-onlyDynamic and writable
CreationBuilt from a Dockerfile using the docker build command.Created from an image using the docker run or docker create command.
StorageStored on disk or in a registry like Docker Hub.Exists in the Docker Engine's runtime environment.
MutabilityImmutable. To change an image, you must create a new one.Mutable. You can make changes to a running container.
PurposeTo package an application and its dependencies for distribution and consistency.To run the application in an isolated, portable environment.

In short, you build an image and then run that image to create a container.You can create multiple containers from a single image, with each container operating in its own isolated environment.

5. Docker's Impact on Development and Operations (DevOps)

Docker significantly streamlines the software development lifecycle and fosters a DevOps culture:

  • Improved Developer Experience: Developers no longer face complex manual environment setups. With Docker installed, a simple command brings up the required environment, ensuring consistency across the team.

  • Seamless Deployment: The compatibility matrix from hell is resolved. Developers and operations teams collaborate to create a Dockerfile – a guide for building the application image. This image can now run on any host with Docker installed on it, and it is guaranteed to run the same way everywhere.

  • Build Once, Run Anywhere: This principle is central. Since the image is built and tested by developers and then used directly by operations without modification, it continues to work the same way when deployed in production.

  • Fostering DevOps: With docker, developers and operations team work together to transform the guide into a Docker file with both of their requirements

Docker Architecture

The architecture highlights the interaction between the user, Docker client, and Docker daemon.

  • Docker Client (CLI): As a user, you interact with Docker via the Docker CLI to execute some Docker commands.

  • Docker Daemon (dockerd): This is the heart of Docker. It's a process that you are going to install when you install Docker. The Docker daemon listens to your Docker request from the CLI and executes commands to create Docker images, create Docker containers, and push your Docker images to your Docker registry.

  • Importance of Docker Daemon: If Docker demon goes down that means technically your Docker will stop functioning or your containers will stop working.

  • Security Concern: The Docker daemon runs with the root user by default, which is highlighted as a drawback of Docker as it could allow a hacker to hack your entire system.

Understanding the terminology (Inspired from Docker Docs)

Docker daemon

The Docker daemon (dockerd) listens for Docker API requests and manages Docker objects such as images, containers, networks, and volumes. A daemon can also communicate with other daemons to manage Docker services.

Docker Client: The command-line interface (CLI) or other tools used to interact with the Docker daemon.

Docker Registry: A place where you store your Docker images for sharing.

Docker Hub: A popular public registry where users can share images. Organisations can also use private registries or create private repositories inside this Docker Hub

Hands-on Docker: Installation and First Container

Practical demonstration of installing Docker and running a first application.

First create EC2 instance on AWS and ssh into the instance

Installation of docker on EC2 Instance (Ubuntu):

  1. Update repositories: sudo apt update

  2. Install Docker: Refer official docs and install https://docs.docker.com/engine/install/ubuntu/

  3. Verify Docker status: sudo systemctl status docker (should show active). (It shows a live log view of the Docker service and keeps updating, so it looks like the terminal is stuck.press q (quit) to return to the normal terminal prompt)

  • Common Installation Mistake & Resolution:Permission Denied: After installation, running docker run hello-world often results in a permission denied error because Docker has to be installed using root user only. Also Docker daemon executes using the root user. Docker is running as root by default the user (ubuntu user in Ubuntu EC2) will not have access to the docker

    Solution:

  • First you need to check docker group exists on the server cat /etc/group

  • Add the current user(ubuntu user in Ubuntu EC2) to the docker group: sudo usermod -aG docker <your_username>.

  • After this, it's crucial to log out and login back for the changes to take effect because your user profile is not activated as soon as you add your user to any other group. Now you can run docker commands.

  • When you add yourself to the docker group with usermod -aG docker $USER, that change only applies after you log out and back in (because your shell loads groups at login).

  • newgrp docker forces your current shell to re-evaluate group membership and start a subshell with the new group.

    Note: It spawns a new shell. If you exit (Ctrl+D), you’ll return to your old one.

Creating a Dockerfile (Example: Python Hello World):

FROM ubuntu:latest

# Set the working directory in the image
WORKDIR /app

# Copy the files from the host file system to the image file system
COPY . /app

# Install the necessary packages
RUN apt-get update && apt-get install -y python3 python3-pip

# Set environment variables
ENV NAME World

# Run a command to start the application
CMD ["python3", "app.py"]

Building a Docker Image:

  • docker build -t your_docker_username/my_first_docker_image:latest .

  • -t : Tags the image with a name and optional version. The format username_of_docker/repository:tag is used for sharing.

  • . : Indicates the Dockerfile is in the current directory.

Running a Docker Container:

  • docker run -it your_docker_username/my_first_docker_image:latest

  • -it : Runs the container in interactive mode.

  • The output "hello world" is displayed.

Pushing an Image to Docker Hub:

Before pushing, you should have created docker account

Docker Login: Run docker login command (requires Docker Hub username and password).

Docker Push: docker push your_docker_username/my_first_docker_image:latest

  • This command uploads the image to the specified Docker Hub repository, making it publicly available (unless the repository is private).

Pulling and Running a Shared Image:

Anyone can pull the image using

docker pull your_docker_username/my_first_docker_image:latest and then run it.


Thank you for reading. I hope you found this blog useful and insightful. Feel free to share your thoughts or questions in the comments.

Let’s connect on LinkedIn: https://www.linkedin.com/in/sruthipalle

Happy coding! 🙂

More from this blog

Sruthi Palle's blog

22 posts