Understanding and Using LXC and LXD
LXC/LXD is a Virtual Machine-like (VM), yet lightweight, Linux container system. Each container has its own filesystem, process space and network stack, thus firewalling a container from its host and the other containers. Rather than emulating hardware they all use the same kernel, so the containers run much more efficiently.
Interesting uses for lxc:
• compartmentalization (for security, or imposing resource limits)self-contained build or application
• environments that are independent of the host OS
• run an older OS version than the host (e.g. run a Ubuntu 12.04 container on a 16.04 host)
• run a different distro than the host (e.g. run a Fedora container on an Ubuntu host)
What is LXC (lex-see)?
From the official LXC page:
“LXC containers are often considered as something in the middle between a chroot and a full fledged virtual machine. The goal of LXC is to create an environment as close as possible to a standard Linux installation but without the need for a separate kernel.”
“LXC is a userspace interface for the Linux kernel containment features. Through a powerful API and simple tools, it lets Linux users easily create and manage system or application containers.
“Current LXC uses the following kernel features to contain processes:
Kernel namespaces (ipc, uts, mount, pid, network and user)Apparmor and SELinux profilesSeccomp policiesChroots (using pivot_root)Kernel capabilitiesCGroups (control groups)
What is LXD (lex-dee)?
From the official LXD page:
“LXD is a container ‘hypervisor’ and a new user experience for LXC.” Basically it’s a layer above lxc that manages containers using liblxc and a Go binding. “The daemon exports a REST API both locally and, if enabled, over the network.”
“It's basically an alternative to LXC's tools and distribution template system with the added features that come from being controllable over the network.”
How does LXC/LXD differ from Virtualbox, Docker?
Virtualbox is a full VM, emulating hardware and running a kernel on top of it, whereas lxc does not emulate hardware and uses the same kernel as the host.
Docker containers only run a single process and do not have init, whereas lxc does have init and therefore can run a full userspace. Docker containers also have less networking flexibility. It is possible to run Docker in an lxc container.
By default, when a container is created it assigned a non-routable IP address dynamically via DHCP, and that address is added to the bridge lxdbr0 running NAT. All kinds of configurations are possible, such as:
routable IP address so packets flow directly to the containerbridge two interfaces, e.g. for a front-end container that needs a routable IP address to talk to the internet while bridging to containers running various back-end application components on non-routable IP addressesfan networking, for very dense virtualization
Note that lxd 2.3+ has much better networking support, since most networking config happens in lxd with its config stored alongside all the other container config, instead of having to configure it all separately.
A Word about ZFS
ZFS is the preferred filesystem to use with lxd, due to:
instantaneous snapshotsper-filesystem quotas and reservationspartition-less, so any number of filesystems can be created dynamicallydeduplicationease of transferring filesystems between hosts (zfs send/recv), which is useful for migrating containers between hosts
Installation (Ubuntu 16.04 or newer)
$ sudo apt install lxd $ sudo apt install zfsutils-linux $ sudo lxd init
LXC/LXD Crib Sheet
Launch a new container
lxc launch ubuntu falcon lxc launch ubuntu:16.04 falcon lxc launch ubuntu:12.04/i386 falcon
Get a list of OS images
lxc image list images:
Start a shell inside a container
lxc exec falcon bash
See running containers
Start/stop a container
lxc start falcon lxc stop falcon lxc restart falcon lxc pause falcon
Move files into/out of a container
lxc file push myfile falcon/path/to/dest lxc file pull falcon/path/to/source myfile lxc file edit <container>/<path>
Limit how much disk space a container can use (ZFS/btrfs only)
lxc config device set falcon root size 20GB
Add a remote lxd to control
lxc remote add tatooine tatooine.example.com:8443
Create and launch a container on a remote host
lxc launch ubuntu:16.04 tatooine:cantina
Connect to a remote container
lxc exec tatooine:cantina bash
Move a container from one instance of lxd to another
lxc stop falcon lxc move falcon tatooine:bar
Automatic Container Setup upon First Boot
Cloud-init is a de facto standard for specifying container configuration. May have originated with AWS. With it you can do things on first boot like:
copy ssh keys into the containerupdate all packages to the latestpre-install packagesetc.
lxc launch ubuntu:16.04 falcon --config=user.user-data="$(cat cloud-init.yaml)" cloud-init.yaml: #cloud-config # Update apt database on first boot # (ie run apt-get update) # # Default: true # Aliases: apt_update package_update: true # Upgrade the instance on first boot # (ie run apt-get upgrade) # # Default: false # Aliases: apt_upgrade package_upgrade: true packages: - rsync # add each entry to ~/.ssh/authorized_keys for the configured user or the # first user defined in the user definition directive. ssh_authorized_keys: - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAu815gmOvEKtfzWp2YQvhz/vpeNX5XczpfKgSxExocjuUV2L70mRHhtF45TwgNdcgWoW5QmYVDrAyuJvywG8NVM77s+UzDrllm+4s7sBBYqZ8kawLjVlHF6NNJn5EhPE5AJGGiTtI0QgM7YGUGx8ZkIC2/VFOxiYjfJV2S9oTHZW3NNc8THb7gBfROxu5KVHIC2Mz9JToZSLX3Evl05HFjYW6Ijs+00af7VBcgXRnEWCZNmbI8G4PSHLSo0NzH1mPPNzAavCfLKZ4MGF10KPWDdsx/YbNPPlr8ZIDCDW3W2N/ldKu8GSfOfNti7KlAj2HUVgupwOQlClWnIozye3eBw== email@example.com - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUPpQPBwOhs2Bk20ZJO0OdjZOVyYOsJxldl+P8s8LTvYDLkaxLZGtaIyaQISybI/5kUQa6soPhxn8x1lzDWnQU109pdFNbTlqtnQZi/lBu8qwMzeaWf2PL/Dd7F7ha5VA11omtBM87f5rRm4hGT3i96WxDg6/KW2/oqVBufa9P7WMQKRyKuSB0Tw5GzJrFcUvUDYDJ2KYIeCVfPUiinTrdVSCUMuPdhLxbRag//8OrN4+ACON+Gbe0l0cx172HHHcfaQZmrlb3W7JuyQg2m6BO45SC8/qpL50fDld1LmswrqzwOqwwlF3dq3x67sei3puP5vZIVhOEq3gGIQxyvb/5 firstname.lastname@example.org