Understanding Docker

Understanding Docker is no longer optional. As a backend developer, I find myself needing to deploy services to the cloud, a task that Docker greatly simplifies, especially when working with microservices. I have a passion for deep learning about the technologies I aim to master. This means grasping the foundations—understanding why something was created, the needs it addresses, and how it has evolved over time. In this blog, I will explore Docker to a depth that enables to use it effectively as a tool, rather than aiming to become a developer of the technology itself, since my current focus is on backend development. Let’s start by exploring the origins of Docker

Docker Timeline

I have organized the timeline according to technological advancements, aiming to concisely illustrate the increasing necessity of Docker in software deployment. Key milestones include:

  • The introduction of virtual machines to the x86 architecture.
  • The development of containers as an emerging and specialized technology.
  • The simplification and optimization of container technology by Docker.

Docker Engine

The Docker Engine is powered by two major and complex components: the Docker Daemon, often referred to as Dockerd, and the Docker Runtime.

  • Docker Daemon (Dockerd): This component implements the API that facilitates communication between the Docker Engine and its clients, such as the Docker CLI. It serves as the primary interface through which users interact with the Docker Engine.

  • Containerd: It receives commands from Dockerd and manages the lifecycle of containers. Additionally, it communicates with Runc to execute these tasks. It also handles image management, a responsibility that was transferred to it from Dockerd in September 2022.

  • Runc: Responsible for the actual creation of containers, Runc operates at a lower level. It can be used as a standalone unit, offering core functionalities without the full suite of features provided by the Docker Engine. It adheres to the Open Container Initiative (OCI) standards, ensuring compatibility and standardization.

Images

An image is a package that contains everything it need to run an containerized app, including few and enough OS files, and it can be used to start various containers, this is useful because it ensure scalability, flexible deployment (we can start de same containerized app in dev, QA and prod environments) and others benefits.

Each container started is fully dependent on the image it comes from. This means you can’t remove the image before removing all its containers.

In order to manage docker images, there are many official and unofficial images repositories, the biggest official repository is Docker Hub, and we can pull images from it using the command ‘docker pull [image]:[tag]’. The default tag is ‘latest’ but you can tag your image however you want.

Docker repositories supports a manifest list, which contains the list of architectures available and points to the architecture wanted. it is selected automatically when pulling an image depending on the host architecture.

You can easy remove an image killing their containers and using the command ‘docker rmi [image]:[tag]’ or ‘docker rmi [image_id]’ or listing the images: ‘docker rmi $(docker images -q) -f’

Layers

An image is a group of layers, where each layer is composed of one or more files and is tagged with an ID and a digest. Layers can be shared by many images, so when you pull an image that uses a layer already downloaded, it doesn’t download the same layer again, only the new layers.

The digest is a cryptographic hash ID. When you make any modification to the image, it generates another unique digest, so you can be sure that you are pulling exactly the image you want by using its digest.

Leave a Comment

Your email address will not be published. Required fields are marked *