Spotter-VM/doc/toolchain/lxc-build.md
Disassembler f8403c5f42
Remove MERGE capability, add FROM
layer inheritance is now linear
2019-11-30 09:59:11 +01:00

6.5 KiB

Building LXC containers

Overview

lxcbuild utility creates a LXC container based on its build recipe and build context path given in command line parameter. If a filename is given, the build recipe is loaded from the file and the directory in which the file resides is taken as build context, ie. all relative paths are resolved from it. In case a directory path is passed as parameter, the directory is then used as build context and a file called lxcfile from the given directory is used as build recipe.

Usage

lxcbuild <buildpath>
 where the buildpath can be either specific lxcfile or a directory containing one

Directives used in lxcfile

The lxcfile syntax is designed to resemble Dockerfile syntax in order to ease the potential transition. Since LXC operates on much lower level of abstraction than Docker, some principles are applied more explicitly and verbosely. Major difference between Docker and lxcbuild is that every directive in Dockerfile creates a new filesystem layer whereas layers in lxcbuild are managed manually.

IMAGE

  • Usage: IMAGE <name>
  • Description: Sets container name. Every lxcfile needs to have one, otherwise no LXC config can be written and no RUN scripts can be run. LXC configuration file is written to path /var/lib/lxc/<name>/config
  • Docker equivalent: -t in docker build command line parameters
  • Populates LXC field: lxc.uts.name

LAYER

  • Usage: LAYER <path>
  • Description: Includes OverlayFS layer. Unlike Dockerfile's FROM, in lxcfile all layers need to be defined. The LAYER directives are given from the lowermost to the uppermost layer, where the lowermost is usually the basic operating system and the uppermost is the working layer in which all subsequent RUN commands and other action will take place.
  • Docker equivalent: FROM
  • Populates LXC field: lxc.rootfs.path

RUN

  • Usage:

    RUN <label>
    <commands>
    <label>
    
  • Description: Executes a shell script in the currently built container. The <label> is an arbitrary user defined string which needs to be given as the first parameter and repeated at the end of the script block. The shell script between the labels is passed as-is, including comments and empty lines, to a POSIX shell with -e and -v parameters set. Basically, following lxcfile entry:

    RUN EOF
        # Comment
        command1
        command2
    EOF
    

    translates to the following script:

    #!/bin/sh
    set -ev
    
    # Comment
    command1
    command2
    

    The command chaining via && which is required in Dockerfile is optional in lxcbuild.

  • Docker equivalent: RUN

  • Populates LXC field: None

COPY

  • Usage: COPY <source> [destination]

  • Description: Recursively copies <source> files into <destination>. Source path is relative to the build context directory, destination path is relative to the container root directory. The files are copied as root:root. Permissions can be changed by subsequent RUN command.

    The <source> can be given as http:// or https:// URL in which case gzip, bzip2 or xz tar archive is expected to be downloaded and unpacked into the <destination>. This is commonly used for creating a basic root filesystem of the container in similar fashion like with Docker's FROM scratch.

  • Docker equivalent: COPY or ADD

  • Populates LXC field: None

USER

  • Usage: USER <uid> <gid>
  • Description: Sets UID/GID of the container init process to <uid> and <gid>. The default UID/GID is 0:0 (root:root).
  • Docker equivalent: USER
  • Populates LXC field: lxc.init.uid and lxc.init.gid

CMD

  • Usage: CMD <command> [parameters...]
  • Description: Sets the init process of the container. This is the process which is automatically started after the container is launched. The default command is /bin/true which immediately terminates with return code 0.
  • Docker equivalent: CMD
  • Populates LXC field: lxc.init.cmd

ENV

  • Usage: ENV <variable> <value>
  • Description: Populates environment variable <variable> with <value> which is then passed to the init process when the container is launched.
  • Docker equivalent: ENV
  • Populates LXC field: lxc.environment

WORKDIR

  • Usage: WORKDIR <dirname>
  • Description: Sets working directory of the container init process to <dirname>. The default working directory is the container's root directory.
  • Docker equivalent: WORKDIR
  • Populates LXC field: lxc.init.uid and lxc.init.gid

HALT

  • Usage: HALT <signal>
  • Description: Sets container stop signal to <signal>. The default signal is SIGINT.
  • Docker equivalent: --signal in docker kill command line parameters
  • Populates LXC field: lxc.signal.halt

LXC config

Although lxcfile populates some LXC config fields, there are lot of defaults with remain unchanged. The template file to which lxcbuild fills in the values looks as follows:

# Image name
lxc.uts.name = {name}

# Network
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up

# Volumes
lxc.rootfs.path = {rootfs}

# Mounts
lxc.mount.entry = shm dev/shm tmpfs rw,nodev,noexec,nosuid,relatime,mode=1777,create=dir 0 0
lxc.mount.entry = /etc/hosts etc/hosts none bind,create=file 0 0
lxc.mount.entry = /etc/resolv.conf etc/resolv.conf none bind,create=file 0 0
{mounts}

# Init
lxc.init.cmd = {cmd}
lxc.init.uid = {uid}
lxc.init.gid = {gid}
lxc.init.cwd = {cwd}

# Environment
lxc.environment = PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
{env}

# Halt
lxc.signal.halt = {halt}

# Log
lxc.console.size = 1MB
lxc.console.logfile = /var/log/lxc/{name}.log

# Other
lxc.arch = x86_64
lxc.cap.drop = sys_admin
lxc.hook.pre-start = /usr/bin/vmmgr prepare-container
lxc.hook.start-host = /usr/bin/vmmgr register-container
lxc.hook.post-stop = /usr/bin/vmmgr unregister-container
lxc.include = /usr/share/lxc/config/common.conf

For explanation of hooks and overall container integration and behavior, refer to VMMgr hooks page.

Example lxcfile

Following is an example of lxcfile for Redis:

IMAGE redis
LAYER shared/alpine
LAYER redis/redis

RUN EOF
    # Create OS user (which will be picked up later by apk add)
    addgroup -S -g 6379 redis
    adduser -S -u 6379 -h /var/lib/redis -s /bin/false -g redis -G redis redis

    # Install Redis
    apk --no-cache add redis
EOF

USER 6379 6379
CMD redis-server /etc/redis.conf