Containers are simply processes that use Linux concepts of namespace and cgroups. In this post, we look at the technicalities of container images and also explore Docker, the most widely used platform for container technology.
Containers are like lunchboxes.....
"pack your food in a lunchbox and take it anywhere."
"pack your application in containers and deploy anywhere"
Thats what we told you in our series introduction.
Tell that to people with zero technical background and they'll buy it. No questions asked!
Tell it to a bunch of technical chaps and they are they're bound to say "Okay! Fine! But you gotta tell me more". Honestly, that's what we said!
And we're guessing you too may have said that too! Wondered about how containers work? No wait! What in the world are containers ?~ ( talking computer science wise, of course)
That's what we're exploring in this post. But first, a little Linux OS lesson.
Namespaces + Cgroups = Containers!
Now there's this little concept in Linux called namespaces and cgroups. We won't go in to the entire details but just look at the overall concept.
Picture this. You are standing in a big open space that offers a breathtaking view of mountains. You build a small cabin in this place. Its fully enclosed but there's exactly one window to look out. From inside the cabin you'll only be able to see a selective part of the view, not the entire thing. Thats how namespaces are. The entire view is the Linux system with a number of processes running on it. By creating a namespace, you sort of restrict a group of processes to only view a part of the system (just like the window). So, for example, a process in a namespace will only be able to see selective network interfaces, file systems etc.
Now, let's say while building your cabin, there a few limits depending on the costs and resources available. You have a limited amount of raw materials, equipments and a fixed number of people to help you out. That's what crgoups do. They limit the number of system resources a group of processes can use. You can control memory, CPU, network and IO quotas for the processes.
Now some geniuses out there used both these concepts of namespaces and cgroups and created the concept containers. In essence, a container is just a Linux process that runs in isolation on a host system without affecting any other process. (Its the namespaces and cgroups at play here)
The Container Dictionary
Ok... See you'll get a thousand references to tell how to create and start containers. But we feel, you need to know a few terms before that. For clarity of course!
Container Image and Container
You don't say "I'll create a container", rather you say "I'll create a container image" and then you say "I'll start a container using the image". So what's with this distinction?
A container image is just a file or a set of files stored in a particular format on the system. These files are then used to start a Linux process or the container. If you see it in another light, a container image is a container in the rest state. Or, a container is a running instance of an image.
When you create an image, (remember its just a bunch of files), you can store it in a centralised file server so that its available for others to use. Or you can pull an image from the registry and start containers on your local system. This central file server is called the Registry.
Container Runtime and Container Engine
If containers are processes, they are bound to have a process lifecycle. And Container Runtimes step in to handle the container lifetime i.e. creating containers, running them and monitoring and managing containers and destroying them.
The runtime will first unpack the image and create a container by setting up the cgroups and namespace. Then it will start a process for the container using a local filesystem mount point. Similarly, when the container is removed, the runtime is responsible for all the cleanup activities.
Runtime is just one component in a larger suite called the Container Engine. The engine usually contains features like CLI or APIs interface to accept user inputs , image sharing capabilities (pushing/pulling images from registry), managing container instances. The engine usually delegates work to the underlying runtime for creating and running containers.
Get these terms right. Because we are about to look at the "big shot" in container technology.....
All this while we have refrained from explicitly mentioning Docker. But we can't anymore. For so many out there, Docker is synonymous with everything containers. Well...Not really....Let's get a few things sorted out.
If you had to put it in one bucket ...you could say Docker is a runtime. But we find that a bit ambiguous. It was a runtime, once upon time. But over the years, it split up into multiple components, and now we'd rather call it a "platform" or a "stack".
Usually, runtimes are categorised as either low level or high level. Low level runtimes actually start and run the containers while high level runtimes have added features like pushing or pulling images, handling storage and network etc.
Guess what! Docker uses both! The high level runtime is called "containerd" while "runc" is the low level runtime. Let's see how it fits in
Docker overall follows a simple client-server paradigm. There are four main components:
- docker client
The docker client is just an interface through which user inputs are sent to the docker daemon. Users can either use the REST interface or interact with the docker daemon through a CLI .
- docker daemon (dockerd)
The daemon accepts all the inputs from the client interface and then delegates the it to the runtimes (containerd and runc)
containerd is used as a high level runtime and is mostly responsible for all the container management tasks. It usually pulls the images, unpacks them and then passes over the mantle to runc.
runc is the low level runtime which is responsible for actually starting running the container by creating the appropriate resources.
Docker today has now become the de facto technology for deploying containerised applications. In fact, it was one the primary forces behind the cloud boom.
But are you wondering why we are talking about docker in Go Chronicles? Thats because, the entire source code for Docker (including containerd and runc) is written in Go. Yep! we aren't kidding there. Checkout their GitHub repositories and you'll know. That's why we say don't underestimate Go!
Enough of this rambling about containers and Docker! Get to point...tell me how do I containerise my application. Well calm down...we have the entire next post dedicated to just creating containers using docker. We didn't want to overwhelm you with so much information in one post! Now that you have the basics cleared out, our next post is going be a docker deep dive.... Get ready!