Learn How Docker Works via Mocker, a Tiny Python Implementation

This article aims at enhancing the basic concepts of containerization and shows how a container can be practically implemented through a few steps in Python.

Learn How Docker Works via Mocker, a Tiny Python Implementation

Introduction

How about creating a container on your own in a few simple steps?
Wait, what is a container? What is its significance?

A container can be described as a small package that holds all the stuff needed to run a program smoothly, no matter where we put it. Containerization has emerged as a key component of modern software development and deployment in the tech industry.

While many developers are comfortable using existing container solutions like Docker, there's immense value in understanding how containers work under the hood.

A container image is like a package containing everything needed to run an application, including code, libraries, and dependencies. It's arranged in layers, with each layer adding or modifying the previous one. These layers are stacked together to create the complete environment needed for the application to run.

Imagine you're baking a cake. Each ingredient you add flour, eggs, sugar, etc represents a layer in the container image. The final cake is like the complete container image, with all the layers combined to create the finished product. So, just as you can mix and match ingredients to create different cakes, you can layer different components in a container image to create various applications.

A container is a lightweight, portable, and self-sufficient environment that encapsulates an application and its dependencies, enabling consistent and reliable deployment across different environments.

So basically, you need a container image for the functioning of a container.

Whereas Docker is a popular containerization platform that simplifies the process of building, managing, and running containers.

Now, let's look into the basic terminologies regarding the container.

Understanding the basics

In Linux, containers rely on core building blocks such as cgroups and namespaces. These components are essential for tasks like managing resources, isolating processes, and controlling access to the file system, all tailored to suit our specific needs.

Let's take a closer look at namespaces

1. Namespaces

"Namespaces lets you see specific parts of a system."

Namespaces are a Linux Kernel feature that helps in isolating various aspects of a process. They help in creating isolated environments so that they don't interfere with other processes or the host system.

2. Control Groups

While coming to Control Groups, known as Cgroups, are created to set specific constraints around them. Say that you need to limit the memory usage or CPU utilization, we directly use cgroups for this purpose.

"Cgroups help in assigning certain resource restrictions that aid in effective process management and resource utilization."

3. Networking

Networking is a crucial aspect to enable communication between services, ensuring isolation and security, and facilitating scalability and flexibility in modern cloud-native applications.

So the networking part of the container aids in creating virtual network interfaces, manipulating the route table, creating network namespaces, and many more.

This will cover the basics for you, now let's kickstart our container coding journey from scratch.

Pulling the image from Repository

First and foremost, we need an image and this can be pulled from any of the available repositories. So we need a function to pull the container image from the repository.

When it comes to the image, there is another term known as manifest. Manifest contains all the related metadata, image layers, image configuration, OS and related architecture, etc.

These are the functions that are done mainly in the pull function:-

  1. We need to authenticate with the Docker Hub registry to pull a Docker image from a specified repository.
  2. After authentication we need to get the manifest from the repository. The manifest is fetched from the repository layer by layer.
  3. Then these layers are saved within a directory as a JSON file and a separate folder containing the layer features and other additional information.

1 powerful reason a day nudging you to read
so that you can read more, and level up in life.

Sent throughout the year. Absolutely FREE.

Secondly, after pulling the image from the repository, we need to ensure that the images are correctly pulled and it's layers are saved in a directory in your system. For that purpose, let's build another function to list out the existing image names and their respective files.

All the image files that are necessary for building up the image are stored in JSON format. So in the image function, using the os. listdir function, we need to compare and list out the files that end with "JSON", and those that match this criterion are returned to the console.

So the output looks like this after listing the images:-

Setting up the Container Environment

Thirdly, we need to create the main function that sets up the container environment and do the necessary process and network configurations. With that, we can wind up the coding part and implement the container.

Run.py is the main function where the whole container setup is established.

  1. We create a new virtual interface with the ipdb python module and provide the bridge networking type to the interface.
  2. We have another Python module called "netns", that helps in creating the network namespace. So with the help of that module, a separate network namespace is created.
  3. Next step is to create the cgroup with the help of the "Cgroup" Python module and set the CPU and memory limits.
  4. After setting the cgroup, we need to create a process and add the process to the cgroup with its corresponding pid.
  5. The created process is started by using a subprocess.Popen() function.
  6. Then a wait function is added so that it waits until the process gets executed.
  7. Finally close the network namespace and remove them from the interface created.

Here, I have run the Nginx webserver in the network namespace that I created. You can see for yourself.

Conclusion

And that's it! We've gone through the world of containerization, building our container from scratch using Python with the help of Mocker.

Breaking down code snippets, we've done the containerization while having some coding fun along the way. But this is just the beginning of our adventure! Whether you're dreaming of orchestrating containers like a maestro or fortifying their security like a digital superhero, there's still so much more to explore and build upon. So, with Mocker in your hand, let's continue exploring more about containers with boundless curiosity and enthusiasm!

For further clarification with the code, please visit:- https://github.com/tonybaloney/mocker

Happy Containerization!

FeedZap: Read 2X Books This Year

FeedZap helps you consume your books through a healthy, snackable feed, so that you can read more with less time, effort and energy.