Monday, August 11, 2025

Introduction to Docker

1 Introduction to Containers
2 How to Containerization
3 Images
4 Containers
5 Registries
6 Docker Architecture
7 Containers for Microservices


1 Intro to Containers

The problem containers are meant to solve

Applications work in different environments, such as many development environments, testing environments and production environments.
An application relies on various dependencies to function correctly. These may include: programming libraries (e.g., Apache Commons for Java, React for JavaScript), frameworks (e.g., Spring and Struts for Java, Angular for JavaScript), runtime environments (e.g., Node.js, Java JDK), external APIs or services (e.g., Amazon S3, Google APIs), and operating system packages.
A common problem with application deployment is that an application may work in one environment but fail in another; this is often due to different environments having different versions of the application's dependencies.
Containers fix this problem, because they create an way to package applications along with their dependencies, so you deploy to production the same things you have developed.

Definitions:

Term Definition
Docker image A Docker image is the standard Docker package for distributing and running applications.
Docker container A Docker container is a running instance of a Docker image, or the Docker standard unit of execution.
Docker engine The Docker engine is the full Docker platform you install on your machine or server. It includes the Docker Daemon (dockerd), Docker CLI (docker), the REST API and other components to build and run containers, such as container runtime (runc), image builder, storage drivers and networking layer. The Docker engine runs natively on Linux, whereas on macOS/Windows it runs inside a Linux virtual machine.
Open Container Initiative The Open Container Initiative (OCI) is an organization created in 2015 by Docker and other industry leaders. It defines the official specifications for containers. These specifications allow container tools built by different vendors to work well together. Example container tools include Docker (by Docker Inc.), containerd (by CNCF), Podman (by Red Hat), CRI-O (also Red Hat) and Kubernetes (by CNCF).

2 How to Containerization

Containers Features

  • Containers are becoming the preferred way to package, deploy and run applications
  • Containers are smaller in size, faster to start up and using less resources than virtual machines

The two steps to run an application in a container

  • package the app as an image
  • run the image as a container

What is Containerization

    It is the process of packaging an application as a image. You take the source code of the application with its dependencies and build it as image. Then, you can use docker (or another tool) to run the image as a container.

What is a Container

  • a container is an isolated execution environment within a single operating system
  • a container is made specifically to run one single app
  • the figure shows a single OS running five containers
  • when multiple containers run on the same OS, each container is a isolated environment of the OS (with its own processes, file system and network) and they don’t see or affect each other.
Linux Host Shared Kernel
Linux Host Shared Kernel
MULTIPLE CONTAINERS
MULTIPLE CONTAINERS
Docker Engine
Docker Engine
App
App
App
App
App
App
App
App
App
App

Figure 1. Isolated execution environments.

Docker Workflow for Containerizing an App

  1. Build a Docker image to package your app and dependencies into an image
  2. Push the image to a container registry (optional for sharing/deploying)
  3. Create and start a container that executes your app (informally, run the image as a container)
App
Deps
OS
Image
BUILD
Registry
Image
PUSH
Container
Image
RUN

Figure 2. Containerizing an application.

3 Images

How is a Docker image structured?

  • A Docker image is made up of multiple layers, each created from an instructions in the Dockerfile.
  • These layers typically include: a minimal operating system, the application code and its dependencies.
  • when these layers are combined, they form an image that can be used to run the application as a container.
  • Note: The minimal OS is not a full OS, it does not have a kernel, but it behaves like a full OS inside the container.
OS
<App>
Deps
Image
Layers
Image

Figure 3. Image layers.

Building an image

  • to build a Docker image, you use a Dockerfile and the docker build command.
  • a Dockerfile is a text file that contains a list of instructions for building the image.
  • the docker build is a command used with the Docker CLI client to tell the Docker deamon to read the Dockerfile and build an image from it.

Example Project Structure

my-java-app/
├── Dockerfile
├── target/
│   └── myapp.jar
├── lib/
│   ├── dependency1.jar
│   └── dependency2.jar
└── config/
    └── application.properties

Example Docker File

Dockerfile

FROM openjdk:17-jdk-slim                       # Official OpenJDK runtime as a base OS
WORKDIR /app                              # Set the working directory in the container
COPY target/myapp.jar app.jar                              # Copy app in the container
COPY lib/ lib/                                    # Copy dependencies in the container
COPY config/ config/                              # Copy config file in the container
EXPOSE 8080          # Expose the port your app runs on, optional, depends on your app
ENTRYPOINT ["java", "-cp", "app.jar:lib/*", "com.example.Main"] # How to start the app

The docker build command

$ docker build -t my-image . -f Dockerfile
  • docker build
    This is the Docker command used to create (or “build”) a Docker image.

  • -t my-image
    The -t flag lets you name (or tag) the image. Here, the image will be named my-image.

  • . (dot)
    This is the build context, which is the directory whose files will be available to the Docker build process. In this case, . means “the current directory”.

  • -f Dockerfile
    The -f flag specifies which Dockerfile to use. By default, Docker looks for a file literally named Dockerfile in the current directory, but if you want to use a different one, you can specify it here. This example names the Dockerfile name, which is the default, so it’s a bit redundant.

The build process

  • Docker reads the Dockerfile line by line
  • Docker executes each instruction in the DockerFile to build a Docker image
  • Each instruction creates a new layer in the image.

Examination of Each instruction of the Dockerfile

Step Dockerfile Instruction Explanation
1. Download the base OS FROM openjdk:17-jdk-slim This tells Docker to pull the official OpenJDK 17 base image from Docker Hub. This image includes a minimal Linux OS + Java JDK 17.
2. Copy in the app and list of dependencies WORKDIR /app
COPY target/myapp.jar app.jar
COPY lib/ lib/
COPY config/ config/
WORKDIR /app sets the working directory inside the container. Then, the next three COPY commands: copy your application JAR to /app/app.jar, your dependency JARs into /app/lib/ inside the container and the entire config/ folder into /app/config/ inside the container.
3. Set the command to run the app. ENTRYPOINT ["java", "-cp", "app.jar:lib/*", "com.example.Main"] This sets the default command that runs when a container is started from this image. Here, it's telling Docker to run: java -cp app.jar:lib/* com.example.Main, which starts your app's Main class using the app JAR and all libraries in lib/.

4 Containers

You can start one or more containers from a single image.

  • You can start one or multiple containers from one image.
  • The figure below shows that two identical containers are created from the same image.
  • You can think images as classes an containers as objects, where you create containers from images at the same way as you create objects from classes.
Image

Figure: a single image starts two containers.

  • The following example commands create an image named my-image and then starts a new container called my-app from the image.
$ docker build -t my-image . -f Dockerfile  # Creates an image called "my-image"
$ docker run --name my-app my-image  # Runs a container named "my-app" from the image named "my-image"

5 Registries

Container Registry

  • A container registry is an online storage service where developers can store and rerieve images.
  • Container registry are sometimes called Docker registries or OCI registries.
  • Storing an image to a registry is said pushing an image, retrieving an image from a registry is said pulling an image.
Registry
Image
$ docker push
$ docker pull
Image
Image
$ docker pull
Image
Image
Image

Figure: pushing an image to a registry and pulling an image from a registry.

Registry's Repository

  • A Registry contains Repositories, each repository contains images (with different tags).
  • A Registry usually has many Repositories.
Registry
├── Repository: myapp
│   ├── Image: myapp:v1
│   └── Image: myapp:v2
├── Repository: nginx
│   ├── Image: nginx:1.21
│   └── Image: nginx:1.22

6 Docker Architecture

Docker uses the client-server model architecture

  • Clients: Tools that interact with the Docker Daemon via the Docker API. This includes the Docker CLI, Docker Desktop, and any other application that uses the Docker API (e.g., IDE plugins, Portainer).
  • Server (Daemon): The Docker Daemon (dockerd), running on the Docker Host, which manages Docker objects such as images, containers, networks, and volumes.
Client–Server Communication
  • The Docker client and daemon may run on the same machine, or a client can connect to a remote daemon.
  • Communication happens through REST API requests over UNIX sockets (default on Linux) or TCP/IP.
<<CLIENT >>
<<SERVER >>
Docker CLI 
or
Docker Desktop
Docker Host
docker
<< tool >>
<< tool >>
docker compose
<< daemon process >>
Docker Registry
Containers
Images
NGiNX
Ubuntu
Redis
Python
<<SERVER >>
REST req
Docker Daemon
(dockerd)
REST req
Networks
Unix socket / TCP
Volumes
JDK
Postgre

Figure: Docker Architecture diagram

Docker Daemon
  • The Docker Daemon (dockerd) listens for API requests from clients.
  • It is responsible for creating and managing Docker objects (containers, images, networks, volumes).
Docker CLI
  • The Docker CLI includes two main tools:
  • docker — the main command-line tool for interacting with the daemon.
  • docker compose — a subcommand for managing multi-container applications (replacing the older docker-compose tool).
  • When a user runs a command, the CLI sends it to the daemon via the Docker API, and the daemon executes it.
Docker Desktop
  • Docker Desktop is an application that bundles a complete Docker environment with a graphical dashboard.
  • Available primarily for macOS and Windows (a Linux version exists but Linux users can install Docker Engine directly).
  • Includes:
    • Docker Engine and CLI (so you can run terminal commands).
    • A Dashboard for managing containers, images, volumes, and builds.
    • Integration with Docker Hub, Docker Scout (for vulnerability scanning) and optional Kubernetes support.

7 Containers for Microservices

Monolithic applications VS Microservice Applications

Before containers, developers built monolithic applications, where all features were developed as a single software component and deployed as one large, complicated application. Microservices allow developers to build applications in which each feature is developed and deployed as a separate, independent service.

Example Monolithic Ecommerce Application

  • in this application, the main features would be: 1) User Accounts & Authentication, 2) Shopping Cart & Checkout System, 3) Order Management, 4) Payment Gateway Integration, 5) Product Catalog Management, 6) Notification Service, 7) Inventory Service.
  • each service is designed as a single object within the monolithic application
  • if you want to scale a single feature of the application, you have scale the whole application by deploying it on a more powerful server

Example Microservice Ecommerce Application

  • using the microservice architecture, the features are built as seven separate small applications
  • each microservice has its own image and deployed as its own container
  • each microservice is loosly coupled with other microservices through IP protocol
  • each microservice can scale independently, without affecting the rest of the system, by adding containers

No comments:

Post a Comment