Linux Containers Internals: chroot

Search for a command to run...

No comments yet. Be the first to comment.
This series goes through the ins and outs of how containers work on Linux.
In our last post of the series #lci-series, we scratched the surface of what chroot does. It was great to get some feedback on how this lit some light bulbs. We can now agree on the definition that a container is a set of 1 or more processes isolated...
Introducing the series and machine setup

At this point of our #lci-series, we have seen how to hack around and create containers. In this post, we will introduce some order and standardization. We aimed to demonstrate what goes on under the hood, just one abstraction layer below -- a scratc...

This post marks the fourth entry in the #lci-series. In our last post, we achieved namespace isolation for the processes running in our container. However, these processes have access to all the available physical resources. For instance, a long-runn...

In our last post of the series #lci-series, we ran a container using chroot and a complete filesystem. We managed to isolate ls and bash within our container-intro directory. However, ps aux lists all the processes on the host environment because we ...

In our last post of the series #lci-series, we scratched the surface of what chroot does. It was great to get some feedback on how this lit some light bulbs. We can now agree on the definition that a container is a set of 1 or more processes isolated...

By the end of this post, we will appreciate the idea of a container, within the Linux context. For most people, when you mention containers, the first thing that comes to mind is Docker. What if I told you that containers have nothing to do with Docker; instead it is the other way round.
Actually, this series will introduce Linux container internals without ever using Docker, just to pass the point across.
ℹ️ NOTE: all the examples below are based on
Ubuntu 22.04.1 LTSrunning on Windows Subsystem for Linux (WSL2). However, you can still run this on any Linux distro (VM or machine).
chrootCreate a directory, e.g. container_intro:
mkdir container_intro
Add a simple file to the directory:
echo "CONTAINER" > container_intro/CONTAINER_ROOT
Let's try to chroot into the directory:
sudo chroot container_intro
You will get this error: chroot: failed to run command ‘/bin/bash’: No such file or directory. This means that we can get into this directory and use it as our root /, when we try to execute bash which should be in /bin/bash, it is not found.
Let's copy /bin/bash (and one more command ls, that we will run afterwards) from the current system to our directory:
mkdir container_intro/bin
cp /bin/bash /bin/ls container_intro/bin
Now back to chroot:
sudo chroot container_into
Still not working! This is because bash has dependency on other libraries. Let's view them:
ldd /bin/bash
linux-vdso.so.1 (0x00007ffe20ff5000)
libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007fdbf1438000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdbf1210000)
/lib64/ld-linux-x86-64.so.2 (0x00007fdbf15d2000)
Let's go ahead and copy them into our directory:
mkdir container_intro/lib{,64} # creates both lib and lib64
cp /lib/x86_64-linux-gnu/libtinfo.so.6 /lib/x86_64-linux-gnu/libc.so.6 \
container_intro/lib
cp /lib64/ld-linux-x86-64.so.2 container_intro/lib64
Let's do the same for ls:
ldd /bin/ls
linux-vdso.so.1 (0x00007ffcccf2f000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f932a5fc000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f932a3d4000)
libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007f932a33d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f932a653000)
cp /lib/x86_64-linux-gnu/libselinux.so.1 /lib/x86_64-linux-gnu/libc.so.6 \
/lib/x86_64-linux-gnu/libpcre2-8.so.0 container_intro/lib
cp /lib64/ld-linux-x86-64.so.2 container_intro/lib64
Finally, back to our chroot:
sudo chroot container_intro
And we are in! We should see the prompt:
bash-5.1#
Let's run ls:
bash-5.1# ls
CONTAINER_ROOT bin lib lib64
bash-5.1#
Now, essentially, we are contained within that directory as our whole world (file system). As far as we are concerned, we can't jump out of it.
We have looked at a hacky solution for getting only two processes: bash and ls up and running. In the next episode, we will look at setting up a full filesystem. For the eager learners, you can check out debootstrap. See you next!
Thanks for reading this far. If you followed this walkthrough hands-on, here is a small gift for you! 😀
Footnote / Further Reading: