Skip to content

What is RunC ?

RunC is a CLI tool for spawning and running containers according to the OCI specification. The Open Container Initiative (OCI) is a standardized format for creating a container. It defines a container as a pair of rootfs folder & configuration file in JSON format.

Setup in Buildroot/Lithosphere

  1. Make sure kernel has all the futures needed for containerization. The easiest way to enable them is to use raspberrypi3_wpe_ml_container_defconfig.

  2. Enable containers support in Thunder

    Thunder -> Extensions -> Process Containers
    

  3. Select RunC as the backend engine for containers.

    Thunder -> Extensions -> Process Containers -> Containers Backend -> runc
    

  4. (optional) Enable containers plugin for info about running containers

    Thunder -> Plugins -> ProcessContainers
    

Setting Up runc Container

For demo purposes, we will use the OCDM plugin. To run a containerized ThunderNanoService you will need to create rootfs with all of the dependencies of the nanoservice and ThunderPlugin as executable. For this tutorial rootfs.tar generated by buildroot/lithosphere/yocto will be used as reference roots.

  1. On target platform, create /usr/share/Thunder/<Nanoservice Name>/Container. This will be a directory containing all files defining a container.

    mkdir <SD_CARD>/usr/share/Thunder/OCDM/Container
    

  2. Extract rootfs.tar generated eg. by buildroot into /usr/share/Thunder/<Nanoservice Name>/Container/rootfs.

  3. Create a reference configuration. You can either use a reference config file presented later in the instructions or use runc cmdline tool to do it for you, by navigating to /usr/share/Thunder/<Nanoservice Name>/Container and calling runc spec. Be careful - if you do it on the host platform, the "platform" section in config will have to be modified to match the target platform.

Adjusting Configuration for Thunder

Default config obtained by runc spec gives you a nice starting point, that you can tailor as you wish. However, there are a few things that need to be set up right to work with Thunder:

  1. The most important thing is to mount /tmp/communicator pipe inside the container to allow for communication between ThunderPlugin inside a container namespace and Thunder. OCDM plugin that is used in the example also creates another pipe inside /tmp folder, so for tutorial whole /tmp folder is mounted
    "mounts": [
            {
                "source": "/tmp",
                "destination": "/tmp",
                "options": ["rw", "bind"]
            },
                    [...]
    ]
    
  2. Set terminal to false
    "process": {
            "terminal": false,
                    [...]
    }
    
  3. By design, all of the configurations should be passed to Nanoservice by arguments/runtime. However, at the moment, there are some env variables that need to be set. This is considered a temporal solution and won't be needed in future releases.
    "env": [
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
        "TERM=xterm",
        "COMMUNICATOR_CONNECTOR=$COMMUNICATOR_CONNECTOR",
            "MESSAGE_DISPATCHER_CONFIG=$MESSAGE_DISPATCHER_CONFIG"
        ],
    
  4. Launched process will always be a Nanoservice, so container's args will be overided. You don't acctually need to do anything here, however it's good to have in mind that this option will have no effect.
    "args": [
        "sh",
    ]
    

is used so we will mount the whole tmp For now, you also need to set up some env variables as presented in the config, however, in future versions, this will no longer be needed.

Configure plugin to run as a containerized process

In plugin configuration (eg. /etc/Thunder/plugin/OCDM.json for OCDM) change "mode": Local to "mode": "Container"

If everything works fine, you should see OCDM working just lie an ordinary OOP plugin

Example configuration

This is an example of config generated by runc spec with the following changes: 1. /tmp folder mounted inside the container 2. Env variables set inside the container 3. terminal was set to false

{
    "ociVersion": "1.0.2-dev",
    "process": {
        "terminal": false,
        "user": {
            "uid": 0,
            "gid": 0
        },
        "args": [
            "sh"
        ],
        "env": [
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "TERM=xterm",
            "TRACE_FILENAME=/tmp/tracebuffer",
            "TRACE_DOORBELL=/tmp/tracebuffer.doorbell",
            "COMMUNICATOR_CONNECTOR=/tmp/communicator"
        ],
        "cwd": "/",
        "capabilities": {
            "bounding": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE"
            ],
            "effective": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE"
            ],
            "permitted": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE"
            ],
            "ambient": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE"
            ]
        },
        "rlimits": [
            {
                "type": "RLIMIT_NOFILE",
                "hard": 1024,
                "soft": 1024
            }
        ],
        "noNewPrivileges": true
    },
    "root": {
        "path": "rootfs",
        "readonly": true
    },
    "hostname": "runc",
    "mounts": [
        {
            "source": "/tmp",
            "destination": "/tmp",
            "options": ["rw", "bind"]
        },
        {
            "destination": "/proc",
            "type": "proc",
            "source": "proc"
        },
        {
            "destination": "/dev",
            "type": "tmpfs",
            "source": "tmpfs",
            "options": [
                "nosuid",
                "strictatime",
                "mode=755",
                "size=65536k"
            ]
        },
        {
            "destination": "/dev/pts",
            "type": "devpts",
            "source": "devpts",
            "options": [
                "nosuid",
                "noexec",
                "newinstance",
                "ptmxmode=0666",
                "mode=0620",
                "gid=5"
            ]
        },
        {
            "destination": "/dev/shm",
            "type": "tmpfs",
            "source": "shm",
            "options": [
                "nosuid",
                "noexec",
                "nodev",
                "mode=1777",
                "size=65536k"
            ]
        },
        {
            "destination": "/dev/mqueue",
            "type": "mqueue",
            "source": "mqueue",
            "options": [
                "nosuid",
                "noexec",
                "nodev"
            ]
        },
        {
            "destination": "/sys",
            "type": "sysfs",
            "source": "sysfs",
            "options": [
                "nosuid",
                "noexec",
                "nodev",
                "ro"
            ]
        },
        {
            "destination": "/sys/fs/cgroup",
            "type": "cgroup",
            "source": "cgroup",
            "options": [
                "nosuid",
                "noexec",
                "nodev",
                "relatime",
                "ro"
            ]
        }
    ],
    "linux": {
        "resources": {
            "devices": [
                {
                    "allow": false,
                    "access": "rwm"
                }
            ]
        },
        "namespaces": [
            {
                "type": "pid"
            },
            {
                "type": "network"
            },
            {
                "type": "ipc"
            },
            {
                "type": "uts"
            },
            {
                "type": "mount"
            }
        ],
        "maskedPaths": [
            "/proc/acpi",
            "/proc/asound",
            "/proc/kcore",
            "/proc/keys",
            "/proc/latency_stats",
            "/proc/timer_list",
            "/proc/timer_stats",
            "/proc/sched_debug",
            "/sys/firmware",
            "/proc/scsi"
        ],
        "readonlyPaths": [
            "/proc/bus",
            "/proc/fs",
            "/proc/irq",
            "/proc/sys",
            "/proc/sysrq-trigger"
        ]
    }
}