Skip to content

What is LXC ?

LXC (Linux Containers) is a lightweight virtualization method that provides an environment similar to a complete Linux system but without the overhead of a full virtual machine. It uses a combination of Linux kernel features like namespaces and cgroups to isolate processes and manage resource allocation..

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 -> LXC
    

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

    Thunder -> Plugins -> ProcessContainers
    

Setting Up LXC 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) Before running the system, create a folder named 'Container' under /rootfs/usr/share/Thunder/OCDM/

2) Create another folder named 'rootfs' under /rootfs/usr/share/Thunder/OCDM/Container

3) Copy the whole rootfs of the sdcard into /rootfs/usr/share/Thunder/OCDM/Container/rootfs

Adjusting Configuration for Thunder

  1. Create a file named 'config' under /rootfs/usr/share/Thunder/OCDM/Container and place the below content in it.

    # Template used to create this container: /usr/share/lxc/templates/lxc-download
    # Parameters passed to the template: --no-validate
    # Template script checksum (SHA-1): 273c51343604eb85f7e294c8da0a5eb769d648f3
    # For additional config options, please look at lxc.container.conf(5)
    
    # Uncomment the following line to support nesting containers:
    #lxc.include = /usr/share/lxc/config/nesting.conf
    # (Be aware this has security implications)
    
    lxc.mount.entry = /tmp tmp none bind,optional 0 0
    
    # Distribution configuration
    lxc.include = /usr/share/lxc/config/common.conf
    lxc.include = /usr/share/lxc/config/userns.conf
    lxc.arch = linux32
    
    # Container specific configuration
    # if you see access related issue, disable user/group id settings below
    lxc.idmap = u 0 100000 65536
    lxc.idmap = g 0 100000 65536
    lxc.rootfs.path = dir:/usr/share/Thunder/OCDM/Container/rootfs
    lxc.uts.name = OCDM
    
    # Inherit envionment needed by Thunder nanoservices
    lxc.environment = PATH
    lxc.environment = MESSAGE_DISPATCHER_CONFIG
    
    # Network configuration
    lxc.net.0.type = empty
    #lxc.net.0.type = veth
    #lxc.net.0.link = lxcbr0
    #lxc.net.0.flags = up
    #lxc.net.0.hwaddr = 00:16:XX:XX:XX:XX
    

  2. Comment out below line in /usr/share/lxc/config/common.conf:

    # lxc.seccomp.profile = /usr/share/lxc/config/common.seccomp
    

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

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

Mounting a shared directory between host and LXC container

Most often, we may need to securely share files between the host machine and a container.

Example : File logging from a container to a logging system folder located at the host machine.

  1. Create a directory in host.
    mkdir /testshare && chmod 7770 /testshare
    
  2. Create a directory in lxc container (eg: OCDM container)
    mkdir /usr/share/Thunder/OCDM/Container/rootfs/TestLogging && chmod 7770 /usr/share/Thunder/OCDM/Container/rootfs/TestLogging
    
  3. Edit container config file (eg: /usr/share/Thunder/OCDM/Container/config)
    lxc.mount.entry = /testshare TestLogging none bind,rw 0 0
    
  4. UID/GID mapping
    # Container specific configuration
    #lxc.idmap = u 0 100000 65536
    #lxc.idmap = g 0 100000 65536
    
    # Container's UID/GID 0-65535 are mapped to host's 100000-165535,
    # but UID/GID 1000 on the container is mapped to host's UID/GID 1000.
    lxc.idmap = u 0 100000 1000
    lxc.idmap = g 0 100000 1000
    lxc.idmap = u 1000 1000 1
    lxc.idmap = g 1000 1000 1
    lxc.idmap = u 1001 101001 64535
    lxc.idmap = g 1001 101001 64535
    
  5. Accessing contents from a shared folder and permissions .

    Use case 1 : Host has created a domain socket within the shared folder. Container running in non-privileged mode (not root mode), trying to write to this domain socket.
    In this use case, the write operation will fail, if there is NO write permission for "other" user (eg: 775 instead of 777). So make sure that the domain socket has been created with the required access right.

Good To Know

  • lxc API to kill a container is blocking, not guarenteed to work and therefore not used
  • If ifconfig is not available in the container use the ip command (e.g. "ip address" to get IP address info for the device)