3.3 KiB
Exercise — Build a container from scratch
Our goal will be to execute a container running a simple web server.
(Example: NGINX, or https://github.com/jpetazzo/color.)
We want the web server to be isolated:
-
it shouldn't be able to access the outside world,
-
but we should be able to connect to it from our machine.
Make sure to automate / script things as much as possible!
Steps
-
Prepare the filesystem
-
Run it with chroot
-
Isolation with namespaces
-
Network configuration
-
Cgroups
-
Non-root
Prepare the filesystem
-
Obtain a root filesystem with one of the following methods:
-
download an Alpine mini root fs
-
export an Alpine or NGINX container image with Docker
-
download and convert a container image with Skopeo
-
make it from scratch with busybox + a static jpetazzo/color
-
...anything you want! (Nix, anyone?)
-
-
Enter the root filesystem with
chroot
Help, network does not work!
-
Check that you have external connectivity from the chroot:
ping 1.1.1.1(that should work; if it doesn't, we have a serious problem!)
-
Check that DNS resolution works:
ping enix.io -
If you're having a DNS resolution error, configure DNS in the container:
echo nameserver 1.1.1.1 > /etc/resolv.conf
Running a web server
Here are a few possibilities...
-
Install the NGINX package and run it with
nginx(note: by default it will start in the background)
-
Run NGINX in the foreground with
nginx -g "daemon off;" -
Install the package Caddy and run
caddy file-server -ab(it will remain in the foreground and show logs; RECOMMENDED)
-
Download and/or build https://github.com/jpetazzo/color
(if you're familiar with the Go ecosystem!)
Run with chroot
-
Start the web server from within the chroot
-
Confirm that you can connect to it from outside
-
Write a script to start our "proto-container"
Isolation with namespaces
-
Now, enter the root filesystem with
unshare(enable all the namespaces you want; maybe not
useryet, though!) -
Start the web server
(you might need to configure at least the loopback network interface!)
-
Confirm that we cannot connect from outside
-
Update the our start script to use unshare
-
Automate network configuration
(pay attention to the fact that network tools may not exist in the container)
Network configuration
-
While our "container" is running, create a
vethpair -
Move one
vethto the container -
Assign addresses to both
veth -
Confirm that we can connect to the web server from outside
(using the address assigned to the container's
veth) -
Update our start script to automate the setup of the
vethpair -
Bonus points: update the script to that it can start multiple containers
Cgroups
-
Create a cgroup for our container
-
Move the container to the cgroup
-
Set a very low CPU limit and confirm that it slows down the server
(but doesn't affect the rest of the system)
-
Update the script to automate this
Non-root
-
Switch to a non-privileged user when starting the container
-
Adjust the web server configuration so that it starts
(non-privileged users cannot bind to ports below 1024)