Create “Container” without Docker

Rmag Breaking News

Note: I am not a Container anatomy specialist or a Linux expert. This is my experiment with containers in order to understand them.

I am on a learning path to understand how containers work internally. Well, the answer is Namespaces, Cgroups, chroot and of course a filesystem.

Namespaces

Linux namespaces are a feature of the Linux kernel that allows the isolation and virtualisation of system resources between different processes. This means that processes within different namespaces can have their own independent view of the system’s resources, such as process IDs, network interfaces, file systems, and other system resources

Cgroups

Cgroups are a fundamental technology in Linux containerization, allowing the isolation and management of resources among containers. For example, when a Docker container is created, it is assigned its own cgroup, and resources are allocated according to the limits set by the container configuration.

Chroot

chroot is a Unix and Linux system call and command-line tool that changes the root directory of a running process and its children to a new location in the filesystem. This effectively creates an isolated filesystem environment for that process, separate from the main filesystem hierarchy.

So basically Containers are chroot on steroids

Let’s try creating our own.

Create Namespaces:

unshare –uts –pid –net –mount –ipc –fork

Setup Cgroups:

mkdir /sys/fs/cgroup/Example/
echo “200000 1000000” > /sys/fs/cgroup/Example/tasks/cpu.max
echo “$$” > /sys/fs/cgroup/Example/tasks/cgroup.procs

First line creates a new cgroup, second one assigns cpu quota
Third line attaches current shell to the cgroup of container

Setup container’s root filesystem:

debootstrap focal ./ubuntu-rootfs http://archive.ubuntu.com/ubuntu/

This installs a basic Debian or Ubuntu base system into a directory on an existing and running system.

Mount and chroot into container’s filesystem:

mount -t proc none ./ubuntu-rootfs/proc
mount -t sysfs none ./ubuntu-rootfs/sys
mount -o bind /dev ./ubuntu-rootfs/dev
chroot ./ubuntu-rootfs /bin/bash

These commands are used to set up a chroot environment, where you can operate within the directory ./ubuntu-rootfs as if it were the root of the filesystem. They mount various virtual filesystems and device files that a typical Linux system requires for normal operation. Here’s what each command does:

mount -t proc none ./ubuntu-rootfs/proc

mount is the command used to mount filesystems.

-t proc specifies the type of filesystem to mount, which in this case is proc. The proc filesystem is a virtual filesystem that provides access to kernel and process information.

none is used here since the proc filesystem does not correspond to a physical device.

./ubuntu-rootfs/proc is the directory where the proc filesystem will be mounted. It is the /proc directory within your chroot environment.

This command mounts the proc filesystem into your chroot environment, which is necessary for processes within the chroot to get information about the system and running processes.

mount -t sysfs none ./ubuntu-rootfs/sys

-t sysfs specifies that the sysfs filesystem type is to be mounted. sysfs is a virtual filesystem that provides a hierarchy of system and hardware information.

none is used here as well since sysfs is also virtual.

./ubuntu-rootfs/sys is the mount point within the chroot.

This command is similar to the previous but mounts the sysfs filesystem, which is necessary for interacting with system and hardware information.

mount -o bind /dev ./ubuntu-rootfs/dev

-o bind is an option to perform a bind mount. A bind mount creates a mirror of a directory or mount point to some other location.

/dev is the source directory that contains device nodes and interfaces that the kernel provides.

./ubuntu-rootfs/dev is the target directory where the device interfaces will be available within the chroot.

This command mounts the /dev directory into the chroot environment’s /dev directory, allowing access to the device files from within the chroot. Device files are needed, for example, to access hard drives, input devices, etc.

chroot ./ubuntu-rootfs /bin/bash

chroot changes the root directory for the session, or for the command specified, to a new location.

./ubuntu-rootfs is the new root directory where the chroot environment has been prepared.

/bin/bash is the command to run in the chroot environment, in this case, the Bash shell.

This command enters the chroot environment. Once within the chroot, the user will be operating as if ./ubuntu-rootfs were the root (/) of the filesystem, and will start an interactive Bash shell.

Well, we are done, you can run any commands that you want to run as we are now inside the “Container” and the environment is entirely isolated and processes inside it don’t interact with the processes outside chroot

To get out of chroot, just press Ctrl + d and you will be out of it

References

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/managing_monitoring_and_updating_the_kernel/using-cgroups-v2-to-control-distribution-of-cpu-time-for-applications_managing-monitoring-and-updating-the-kernel#preparing-the-cgroup-for-distribution-of-cpu-time_using-cgroups-v2-to-control-distribution-of-cpu-time-for-applications
https://akashrajpurohit.com/blog/build-your-own-docker-with-linux-namespaces-cgroups-and-chroot-handson-guide/
The series by DataDog –> https://securitylabs.datadoghq.com/articles/container-security-fundamentals-part-1/
https://securitylabs.datadoghq.com/articles/container-security-fundamentals-part-2/
https://securitylabs.datadoghq.com/articles/container-security-fundamentals-part-3/
https://securitylabs.datadoghq.com/articles/container-security-fundamentals-part-4/

Leave a Reply

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