DEV Community

Ákos Takács
Ákos Takács

Posted on

Using gVisor's container runtime in Docker Desktop

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

» Back to table of contents «

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

» Back to table of contents «

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
Enter fullscreen mode Exit fullscreen mode

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"
    }
]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Download and install runsc in one step

» Back to table of contents «

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
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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

» Back to table of contents «

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

For more testing ideas, check out my blog post about the comparison of runtimes.

Possible error messages

» Back to table of contents «

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'.
Enter fullscreen mode Exit fullscreen mode

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)