Container Runtimes - OCI and LXC

Container Runtimes - OCI and LXC

Overview

OCI and LXC provide similar features for describing and constructing a container runtime.

In each case, a container is represented as a configuration file and a rootfs directory (usually together in the same directory).

Both configuration specifications are comprehensive in their support for fine grained linux container configuration.

OCI

Runtime spec release: https://github.com/opencontainers/runtime-spec/releases/tag/v1.2.1

An “OCI bundle” is a directory with a config.json file and a rootfs directory containing a root filesystem.

From a bundle, the container can be started with one of the runtime agent commands like crun or runc. The runc command is particularly lightweight while being essentially identical to crun (runc is written in C instead of Go).

config.json property overview

  • root: defines path to rootfs, and whether its read-only

  • mounts: array of mount points, with options

    • uidMappings, gidMappings options, implemented with mount_setattr(MOUNT_ATTR_IDMAP)

  • process:

    • terminal: true to attach a pseudo terminal to the container process’s standard streams

    • consoleSize: if terminal is set, specified width and height

    • cwd: working directory for the executable

    • env: environment variables

    • args: argv-like array of strings

  • process (posix):

    • rlimits: resource limits on the process

      • type: see getrlimit(2)

      • soft: rlim.rlim_cur

      • hard: rlim.rlim_max

  • process (linux):

    • apparmorProfile: name of the AppArmor profile for the process https://wiki.ubuntu.com/AppArmor

    • capabilities: object containing arrays that specify sets of capabilities

    • noNewPrivileges: prevents the process from gaining additional privileges
      The no_new_privs article in the kernel documentation has information on
      how this is achieved using a prctl system call on Linux

    • oomScoreAdj: adjusts the oom-killer score in [pid]/oom_score_adj

    • scheduler: object, describing the scheduler properties for the process

      • policy, nice, priority, runtime, deadline, period

    • selinuxLabel: specifies the SELinux label for the process

    • ioPriority: object. configures the I/O priority settings for the container’s processes within the process group

      • class, priority

    • execCPUAffinity: object. specifies CPU affinity used to execute the process.

    • user: user the process runs as

      • uid: user ID in container namespace

      • gid: group ID in container namespace

      • umask: umask of user

      • additionalGids: array of ints specifying additional group IDs

  • hostname, domainname: hostname and domainname in uts namespace

  • linux (platform-specific configuration) - many configurable properties

  • hooks: custom actions related to lifecycle

LXC

Documentation:

LXC provides templates as an option for creating a container. The “download” template is commonly used for downloading and creating a container from a set of common linux distributions. There are also some interesting templates for trying out simple container environments:

  • lxc-busybox: a minimal busybox environment, with busybox init for /sbin/init

  • lxc-oci: Create application containers from OCI images

  • lxc-sshd: a container that just runs sshd, no OS

  • lxc-local: create a container from a tarball

A container can also be created manually by populating a rootfs tree and a config file (much like an OCI bundle). The host rootfs, or portions thereof, can also be used as the container’s rootfs.

The container is started with the lxc-start or lxc-execute command.

config property overview

Some lxc example configuration settings (documented in lxc.container.conf(5)):

  • lxc.hook.*: hooks allow for actions to be performed at different stages of the container lifecycle

  • lxc.rootfs.path: a directory to use as the container's rootfs

    • If not specified, the host's rootfs is used.

  • lxc.environment: Specify an environment variable to pass into the container

  • lxc.idmap: for privilege separation (unprivileged containers with user namepaces)

  • lxc.init.cmd: default command to run when using lxc-start. defaults to /sbin/init

  • lxc.execute.cmd: default command to run when using lxc-execute

  • lxc.init.cwd: Absolute path inside the container to use as the working directory

  • lxc.init.uid: User ID (inside container) to use for init

  • lxc.init.gid: Group ID (inside container) to use for init

  • lxc.net: specify network interfaces (implies network namespace)

  • lxc.uts.name: hostname

  • lxc.cap.drop: drop capabilities

  • lxc.mount.entry: add mount points

  • lxc.mount.auto: specify which standard kernel file systems should be automatically mounted. Provides convenient options for specifying how to automatically mount proc, sys, and cgroup filesystems.

  • lxc.cgroup2.*: cgroup configuration

  • lxc.prlimit.[name]: Specify the resource limit to be set

  • lxc.proc.[proc file name]: Specify the proc file name to be set. E.g. lxc.proc.oom_score_adj = 10

  • lxc.sysctl.[kernel parameters name]: Specify the kernel parameters to be set

  • lxc.apparmor.profile: Specify the apparmor profile

  • lxc.selinux.context: Specify the SELinux context

  • lxc.seccomp.profile: Specify a file containing the seccomp configuration

  • lxc.no_new_privs: Specify whether the PR_SET_NO_NEW_PRIVS flag should be set for the container