Introduction
I compared 3 container runtimes previously, which included runsc from gVisor. Since the default is runc, that is the default in Docker Desktop as well. The Kata runtime could not be tested in Docker Desktop, since that would require nested virtualization in the VM of Docker Desktop, so runsc is the only runtime from that comparison we could try in Docker Desktop which isn't already in it.
The only question is how we could copy the runtime binary into Docker Desktop. This could also be asked in general related to any binary, since the root filesystem of Docker Desktop is read-only, but the runtime is executed by Docker so copying that would actually make sense.
Table of contents
- Download runsc into Docker Desktop
- Configure the Docker daemon to use the runtime
- Download and install runsc in one step
- Testing runsc after the installation
- Possible error messages
Download runsc into Docker Desktop
If a runtime can be downloaded directly without using any package manager, you can download it to a location which can be read by the Docker daemon. There is one thing that we know the Docker daemon can read, and we can write, and that is a local volume. So we will need a container that downloads runsc to a local volume.
First we will need to check the official documentation for an installation guide. Despite that the documentation mentions installing specific releases as well, I couldn't figure it out and the link they provide to the releases on GitHub shows that there is no release at all, so we will install the latest version.
I used the script from the documentation, except that I removed the parenthesis and I also needed to remove sudo
from the beginning of the last line. We don't need it, since we will use the root user in the container. I will use the script directly in a compose file, so I had to escape all the dollar characters with a second dollar character. This is the compose file:
services:
runsc-installer:
image: alpine:3.20
volumes:
- type: volume
source: data
target: /usr/local/bin
command:
- sh
- -c
- |
set -e
ARCH=$(uname -m)
URL=https://storage.googleapis.com/gvisor/releases/release/latest/$${ARCH}
wget $${URL}/runsc $${URL}/runsc.sha512 \
$${URL}/containerd-shim-runsc-v1 $${URL}/containerd-shim-runsc-v1.sha512
sha512sum -c runsc.sha512 \
-c containerd-shim-runsc-v1.sha512
rm -f *.sha512
chmod a+rx runsc containerd-shim-runsc-v1
mv runsc containerd-shim-runsc-v1 /usr/local/bin
volumes:
data:
name: runsc-runtime-binaries
The chance of you using runsc-runtime-binaries
as a volume for something else is very low. But if you do have it, make sure you use a different volume name.
Place the file anywhere as compose.yml
and run
docker compose run --rm runsc-installer
You will see the progress which is something like this:
Connecting to storage.googleapis.com (172.217.19.123:443)
saving to 'runsc'
runsc 100% |****************************************************************| 60.2M 0:00:00 ETA
'runsc' saved
Connecting to storage.googleapis.com (172.217.19.123:443)
saving to 'runsc.sha512'
runsc.sha512 100% |****************************************************************| 136 0:00:00 ETA
'runsc.sha512' saved
Connecting to storage.googleapis.com (172.217.19.123:443)
saving to 'containerd-shim-runsc-v1'
containerd-shim-runs 100% |****************************************************************| 27.7M 0:00:00 ETA
'containerd-shim-runsc-v1' saved
Connecting to storage.googleapis.com (172.217.19.123:443)
saving to 'containerd-shim-runsc-v1.sha512'
containerd-shim-runs 100% |****************************************************************| 155 0:00:00 ETA
'containerd-shim-runsc-v1.sha512' saved
runsc: OK
containerd-shim-runsc-v1: OK
Whenever a new version comes out, you can run the command again, and it will replace the old files.
Configure the Docker daemon to use the runtime
As I also mentioned in Everything about Docker volumes, you can inspect a volume and see the mount point
docker volume inspect runsc-runtime-binaries
This is my output:
[
{
"CreatedAt": "2024-10-28T17:21:24Z",
"Driver": "local",
"Labels": {
"com.docker.compose.project": "03-gvisor-in-docker-desktop-data",
"com.docker.compose.version": "2.29.7",
"com.docker.compose.volume": "data"
},
"Mountpoint": "/var/lib/docker/volumes/runsc-runtime-binaries/_data",
"Name": "runsc-runtime-binaries",
"Options": null,
"Scope": "local"
}
]
Normally a mount point would be where you mount something not from where you mounted it, but I guess it is called mount point because of what I described in the linked tutorial, since unless you are using the default local volumes, this is where the data could be mounted to. Now that we know that, the following script can be used to add the runtime to the daemon config:
#!/usr/bin/env bash
volume="runsc-runtime-binaries"
volume_path="/var/lib/docker/volumes/$volume/_data"
docker run -it --rm --privileged --pid host \
--mount "type=bind,source=$HOME/.docker,target=/etc/docker" \
--mount "type=volume,source=$volume,target=$volume_path" \
ubuntu "$volume_path/runsc" install
This script also mounts $HOME/.docker
to /etc/docker
in the container, since it contains the daemon.json
and runsc install
will add the parameters to /etc/docker/daemon.json
by default. If you save the script as runsc-install.sh
, this is how you could run it:
chmod +x ./runsc-install.sh
./runsc-install.sh
Download and install runsc in one step
If we want to make the installer simpler, we can add the install command to the compose file. This means that we have to mount $HOME/.docker
and since runsc will add itself to the config file using its own detected path, we should remove the last line of the original script in the compose file to move the downloaded binaries to a folder that matches the final volume path. So we change the mount definition of the volume too. And finally, we run the installer. So these are the last three lines:
dest="/var/lib/docker/volumes/${RUNSC_VOLUME_NAME:-runsc-runtime-binaries}/_data/"
mv runsc containerd-shim-runsc-v1 $$dest
$$dest/runsc install
Notice that $dest
is escaped with a second dollar character but $RUNSC_VOLUME_NAME
isn't. This is because the volume name will be a compose parameter with a default value so it has to be interpreted by compose. This is the full compose file:
services:
runsc-installer:
image: alpine:3.20
volumes:
- type: volume
source: data
target: /var/lib/docker/volumes/${RUNSC_VOLUME_NAME:-runsc-runtime-binaries}/_data/
- type: bind
source: $HOME/.docker
target: /etc/docker
command:
- sh
- -c
- |
set -e
ARCH=$(uname -m)
URL=https://storage.googleapis.com/gvisor/releases/release/latest/$${ARCH}
wget $${URL}/runsc $${URL}/runsc.sha512 \
$${URL}/containerd-shim-runsc-v1 $${URL}/containerd-shim-runsc-v1.sha512
sha512sum -c runsc.sha512 \
-c containerd-shim-runsc-v1.sha512
rm -f *.sha512
chmod a+rx runsc containerd-shim-runsc-v1
dest="/var/lib/docker/volumes/${RUNSC_VOLUME_NAME:-runsc-runtime-binaries}/_data/"
mv runsc containerd-shim-runsc-v1 $$dest
$$dest/runsc install
volumes:
data:
name: ${RUNSC_VOLUME_NAME:-runsc-runtime-binaries}
This way you can even change the volume name. and run the compose project like this:
RUNSC_VOLUME_NAME="runsc-bin" docker compose run --rm runsc-installer
My previous examples used docker compose run
, but you can use docker compose up
as well. Then the log lines will be prefixed with the container name and the container will be kept after running it.
Testing runsc after the installation
Before you test the runtime, don't change any Docker Desktop configuration, because that will reset your client config on the host, since the VM still doesn't know about it. In order to avoid resetting the config file, "Quit Docker Desktop" and then start it again. DO NOT just "Restart" it in the menu, because that will just restart services in the VM without updating the config.
When the config is ready and Docker Desktop is started again, you can run
docker run --rm --runtime runsc ubuntu uname -a
If everything works, you will see something like this:
Linux 73309f6efa2c 4.4.0 #1 SMP Sun Jan 10 15:06:54 PST 2016 aarch64 aarch64 aarch64 GNU/Linux
For more testing ideas, check out my blog post about the comparison of runtimes.
Possible error messages
If something goes wrong and runsc cannot be found, you can see an error message like below, which I got when I accidentally wrote "volume" instead of "volumes" in the script, so Docker tried to find the runtime using an incorrect path.
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: unable to retrieve OCI runtime error (open /var/run/desktop-containerd/daemon/io.containerd.runtime.v2.task/moby/3a01e11f99939f9fd85151e2ae97f15d5f39ff94e835187357b82807147dcc52/log.json: no such file or directory): fork/exec /var/lib/docker/volume/runsc-runtime-binaries/_data/runsc: no such file or directory: <nil>: unknown.
If you try the runtime too early before activating it in the VM, for example because your config was reset to the previous one after you changed something in Docker Desktop before stopping it, you could get an error about the invalid runtime name:
docker: Error response from daemon: unknown or invalid runtime name: runsc.
See 'docker run --help'.
Conclusion
Changing the runtime in Docker Desktop is not the first thing that Docker Desktop users think. It is probably not even in the top 10, but sometimes, it can be useful if you have only Docker Desktop at the moment. So this post was basically just a way to know more about Docker Desktop, Docker Compose, and how we can change the daemon configuration manually, or automatically.
If you break the daemon configuration, you can fix it, but you have to quit Docker Desktop and start it again.
You could also learn a little bit about volumes, but if you need more, you can read the already mentioned Everything about Docker volumes
Top comments (0)