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

184 lines
6.5 KiB
Markdown

# 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
```bash
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:**
```bash
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:
```bash
RUN EOF
# Comment
command1
command2
EOF
```
translates to the following script:
```bash
#!/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:
```bash
# 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](vmmgr-hooks) page.
## Example lxcfile
Following is an example of *lxcfile* for *Redis*:
```bash
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
```