The main difficulty I found to convince people to consider using scratch containers is the fear to not have the good tools in case of. In fact, it is possible to deploy what you want and this is how.
As a container build out of cgroups, namespaces, and capabilities, it is possible to reuse namespaces of containers when creating others:
Let’s start a webserver in a scratch container:
$ docker run --rm -ti --name whoami emilevauge/whoami
We can use the network namespace of our container
whoami in an other container. Thus the two containers have the same network stack and the same loopback address:
$ docker run --rm -ti --name curl --net container:whoami --name curl appropriate/curl curl 127.0.0.1:80
There are many namespaces: net, pid, user, …
Sidekicks: namespaces and capabilities
There’s a tone of resources on Internet to explain this. To make it short, our container named
curl is a sidekick: it shares some namespace(s) of a previous container.
What is important is that if you share some namespaces, you still have an other container with different possibilities. For example, I can
strace the webserver with this:
$ docker run --rm -ti --pid container:whoami --cap-add SYS_PTRACE debian # apt update && apt install -qy strace # strace -p 1
One of the limits of the docker containers is that you can’t share the full filesystem of the container. You can only share a directory which has already been precut as a volume.
But there is a workaround:
/proc. This pseudo-filesystem can provide you all the information you need about a process:
/proc/PID/environmentfor the environment variables (not updated BTW)
/proc/PID/statusfor some stats
/proc/PID/cmdlinefor the command line used to start the process
/proc/PID/nsfor the list of the namespace
- … see
/proc/PID/rootfor the filesystem as viewed by the process.
To view the filesystem in the container, first find the pid of the process:
$ docker top whoami UID PID ... root 22001 ...
So the filesystem of our scratch container can be visited:
# cd /proc/22001/root # ls dev etc proc sys whoamI
Injecting an OS
To deploy alpine:
- Download the alpine packet manager name
apkto install the basics
- Configure the repo
All the steps are in this script so you just have to run it.
$ wget --quiet https://gist.githubusercontent.com/cell/c2771582f28bf9413b5bd81426338a1d/raw/7c910b4f20203f80888e8fd511f4a7d5824336a0/inject-alpine.sh $ chmod a+x inject-alpine.sh $ sudo -s # PID=22001 ./inject-alpine.sh ... You can now enter your formerly scratch container with: docker exec -ti container-name sh
Now we can:
$ docker exec -ti whoami sh / #
If you need any tool, just install it:
/ # apk --update --clean add curl
Sidekicks vs OS-injection
Both solutions have pros and cons.
Deploying an OS help to feel in a more traditional environment. It’s easier to just
docker exec and you are in a normal container even if you inherit the limitation of standard containers. On the other hand, sidekicks fill stranger and stretch be you can do nearly everything . You could even deploy the OS from a sidekick :)