Docker is one of the most used container services available. But getting your head around the basics of Docker could be a bit cumbersome.
But once understood, they will stay with you forever and can make your life very easy.
So, let’s get started into knowing about the very low-level essentials of Docker.
But first of all, why is Docker used? Why should you even know about it?
Docker has many use cases, and the most important one of them, is that it removes the common dev/prod error dilemma.
It must have happened with you that an application runs just fine in dev environment, but when deployed in production, it breaks!
That’s because both the environments are not same. Maybe dev environment is updated or prod environment is updated, or they have some different utilities or any other configuration changes. These changes, may cause errors that can become serious headache.
Docker comes to aid here. It is a very simple way of transferring the entire environment from dev to prod and vice-versa.
Moreover, it is very lightweight. So what about having many containers running simultaneously in a virtual machine on a server. Well that improves your infrastructure’s scalability.
But don’t limit yourself. That’s just the beginning of the wonders of Docker and container services.
And now that we know why we should be learning Docker, let’s have a deep dive into it.
Just like any other technology or tool, docker has some basic objects that we need to understand in order to proceed.
We’ll not be going into each one of them, but only containers and images.
An image is what begins the whole story. Think of it as a template.
Image is a predefined set of instructions or rules, that builds the most basic of you environment.
For instance, your environment needs to consist of CentOS 7 server with Apache installed. All you need to do is make an image for the same and pass it on. Now everyone in the organisation has the same platform with same configurations.
Almost all the images are derived from some other images. Like the one above was derived from a CentOS 7 image. These are mostly the official images.
All the instructions that need to create an image are stored in a Dockerfile.
Images in docker are read only and you cannot alter an image.
To get a basic understanding, if you know OOPs then image is a class, and if you use AWS, then images resembles AMIs.
If images are templates, then containers are their implementations.
Containers can be considered as runnable images and are completely isolated form other containers or the host. Almost till you don’t do something to reduce the level of isolation.
What happens is that whenever you install an image and create a container, a new layer is added on top of the image.
So if you create 10 layers, you have 10 top layers, but one image.
No doubt it’s a piece of art and lightweight.
Any change that you make, you make to these container layers. And when you delete a container, you are essentially just removing these layers.
But the best part is, that a container can be packed into an image.
Going with our example above, we created a container of a CentOS 7 image. Once created, we installed Apache server on it.
This added a new layer on top of the previous image. Next we created a DockerFile and packed the layers together to form our new image. And this image is now having 2 layers.
Further modifications and new images created will have an increasing number of layers added to the new image.
Building Blocks Of Docker
Docker engine, or the Docker application, or whatever you wish to call it, has in basic, the following essential blocks, or parts.
I know that the names are not that intuitive, except first two. But, they represent excellent art and architecture in the way that they work.
This is what we can call the client. Using this command line utility a client, or more appropriately put, you will interact with the docker.
CLI enables you to give instructions as to what you want to do. Anything and everything that you come in interaction with, while using docker, is CLI.
Daemon or dockerd, is the heart of docker. This is the place where all the dirty work takes place. It’s the core docker engine.
It handles building, running and distributing containers and images.
When you work with CLI, this is where all your commands and instructions go. They usually communicate with each other using UNIX sockets or network interface.
Daemon is always listening and waiting eagerly for you to give any command and it will make it come true.
Any and every Docker object, images, containers, network, etc, is managed by Daemon
Containerd manages containers. That’s nice 😉
What happens is that any command that you pass on to Daemon related to containers, daemon simply passes it over to containerd.
It was added as a layer after the OCI layers stuff. That’s boring and irrelevant.
In short, containerd manages the life cycle of all the containers.
Although containerd manages the lifecycle of a container, but it does not create one. Whenever it needs to create a container, it calls runc.
All the dirty work involved in creating a container is done by runc.
Once a container is created, runc simply moves out of the picture and in comes shim.
Shim is responsible for the containers once created.
Now, as an overview of these boring nutty-grutty details:-
When you type any command, you are using the CLI. The CLI makes an API call to the Daemon. Daemon is who rules it all. If the command has anything to do with a container’s lifecycle actions, it is passed on to containerd. But containerd don’t do the dirty work. It has shim and runc to do it. Runc creates a container and hands it over to shim, which manages the container in a daemonless way.
Note:- Shim implements daemonless containers, i.e., it isolates them and manages them on it’s own without requiring a new daemon for each container. Because of this, we can run multiple containers simultaneously.