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.
unshare --uts --pid --net --mount --ipc --fork
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 isproc
. Theproc
filesystem is a virtual filesystem that provides access to kernel and process information. -
none
is used here since theproc
filesystem does not correspond to a physical device. -
./ubuntu-rootfs/proc
is the directory where theproc
filesystem will be mounted. It is the/proc
directory within your chroot environment.
This command mounts the
proc
filesystem into yourchroot
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 thesysfs
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 sincesysfs
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