DEV Community

Cover image for Containers from scratch in 18 lines of code
Nicola Apicella
Nicola Apicella

Posted on

Containers from scratch in 18 lines of code

Ever wondered what a container is?
One of the best way to answer this question is by building a container from scratch.

Container

A container is an abstraction primarly made of three things:

  • cgroups: control what you can use in a container
  • namespaces: control what you can see in a container. For example the list of processes running in the containers, pid, hostname, etc.
  • networking: manage who you can communicate with in a container

How does that look like in practice?
The best way to see it is by writing some code.

So let's do this. Let's create a small program which opens a bash in a new process.
We want the process to have a new namespace.
How can we test it if this works? We can type in the bash opened by our program hostname newhostname and see what the hostname is after we exit the program.

Let's see it in action. In the following example the program is called namespace.
You can find the code at the end of the article.

console1
Before running the command my hostname is: nicola.
Then we run sudo ./namespace which starts the container.
Then we change the hostname in the container to container.
When we exit the program the host hostname is nicola again.
The container had its own namespace, nice!
You can also see that the pid in the container is 1.

Do it yourself

Give it a try. Copy the following code in a file named namespace.c for example.

#define _GNU_SOURCE 
#include <sched.h>

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int child(void *args)
{
    printf("pid as seen in the child: %d\n", getpid());
    system("bash");

}

int main()
{
    int namespaces = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS|CLONE_NEWNET;
    pid_t p = clone(child, malloc(4096) + 4096, SIGCHLD|namespaces, NULL);
    if (p == -1) {
        perror("clone");
        exit(1);
    }
    printf("child pid: %d./na   \n", p);
    waitpid(p, NULL, 0);
    return 0;
}
Enter fullscreen mode Exit fullscreen mode
gcc namespace.c -o namespace
chmod +x namespace
sudo namespace

Enter fullscreen mode Exit fullscreen mode

Conclusion!

Admittedly this is a super simple container, but it should get you on the way to understand the container abstraction!

Thanks!

Follow me on twitter

Top comments (2)

Collapse
 
gbafana25 profile image
Gareth M.

Great article! I'm currently looking at some Go code on Github that also is a "container from scratch". It's a little bit longer, but both this and the Go variation are very helpful in learning about containers

Collapse
 
napicella profile image
Nicola Apicella

Thank you! Glad it helped