Kahibaro
Discord Login Register

Linux containers (LXC/LXD)

Understanding LXC and LXD in Context

Linux containers (LXC/LXD) are system containers: they run a full Linux userspace (init, services, multiple processes) in an isolated environment sharing the host kernel. Compared to application containers (as in Docker/Podman), LXC/LXD feels more like lightweight virtual machines: you can ssh into them, run systemd, and manage them as full systems.

Key relationships:

You will mostly interact with LXD in modern setups; LXC alone is typically used for more custom, low-level scenarios.

Core Concepts: System Containers with LXC/LXD

System containers vs application containers

What makes LXC/LXD “system containers”:

This is well-suited for:

Installing and Initializing LXD

Exact installation commands vary by distribution, but the flow is similar.

On Ubuntu (typical example):

sudo apt update
sudo apt install lxd

Or via Snap (often the preferred method on Ubuntu):

sudo snap install lxd

After installation, run the initialization wizard:

sudo lxd init

The wizard will ask about:

You can reconfigure later with lxc network and lxc storage commands.

Basic LXD Workflow

LXD uses a single CLI: lxc. Some fundamental workflows:

Listing and using images

LXD provides image servers (remotes). The default is images: (a public image server) and ubuntu: (Ubuntu images).

List images from a remote:

lxc image list images:
lxc image list ubuntu:

Launch a container from an image:

# From the default 'ubuntu:' remote
lxc launch ubuntu:22.04 my-ubuntu
# From the generic 'images:' remote
lxc launch images:alpine/3.18 my-alpine

This creates and starts my-ubuntu or my-alpine as a running container.

Inspecting containers

List containers:

lxc list

Typical columns:

Get detailed info:

lxc info my-ubuntu

Starting, stopping, and deleting

Basic lifecycle operations:

lxc start my-ubuntu
lxc stop my-ubuntu        # Graceful (sends a signal)
lxc stop my-ubuntu --force  # Hard stop (like pulling the power)
lxc restart my-ubuntu
# Rename
lxc rename my-ubuntu dev-ubuntu
# Delete (must be stopped)
lxc delete dev-ubuntu

Accessing Containers

Getting a shell

Execute a command or open an interactive shell inside a container:

# Run a single command
lxc exec my-ubuntu -- uname -a
# Open an interactive shell (root)
lxc exec my-ubuntu -- bash

To get a non-root shell, either:

File transfers

Copy files between host and container:

# Host -> container
lxc file push ./script.sh my-ubuntu/root/
# Container -> host
lxc file pull my-ubuntu/etc/hosts ./hosts-from-container

You can also push directories with -r.

Console access

Some containers/VMs provide a console:

lxc console my-ubuntu

For containers using systemd, the console often behaves like the system console of a VM.

Managing Container Configuration

LXD stores configuration per instance (container/VM). You can view and edit it.

View current config:

lxc config show my-ubuntu

Edit interactively (opens an editor):

lxc config edit my-ubuntu

This exposes YAML-like configuration for:

You can set individual keys:

lxc config set my-ubuntu limits.cpu 2
lxc config set my-ubuntu limits.memory 2GB

Resources are controlled by cgroups under the hood, but LXD abstracts that away.

Storage with LXD

LXD uses storage pools and storage volumes.

Storage pools

A storage pool is a backend (ZFS, Btrfs, LVM, directory) where container root filesystems and volumes are stored.

List pools:

lxc storage list

Create a new pool (example using ZFS):

lxc storage create mypool zfs size=50GB

Set a pool as default:

lxc profile set default root disk pool=mypool

Root disks and extra volumes

Containers get a root disk device defined in a profile (usually the default profile):

lxc profile show default

You’ll see something like:

devices:
  root:
    path: /
    pool: default
    type: disk

To attach an extra storage volume:

  1. Create a custom volume:
   lxc storage volume create default mydata
  1. Attach to a container:
   lxc config device add my-ubuntu data disk pool=default source=mydata path=/mnt/data

Now /mnt/data in the container is backed by the mydata volume.

Networking with LXC/LXD

LXD manages networks, typically via bridges providing NAT.

Managed bridges

When you used lxd init, it probably created lxdbr0. Containers connect to this and receive private IPs (via dnsmasq):

List networks:

lxc network list

Show a network:

lxc network show lxdbr0

Attaching networks to containers

Bridge interfaces are added as devices:

lxc config device add my-ubuntu eth0 nic network=lxdbr0 name=eth0

You can create additional networks (e.g. for internal-only communication) and add interfaces to containers as needed.

Exposing services (proxy devices)

To expose a service running in a container to the host or external network, use proxy devices:

# Forward host port 8080 to container port 80
lxc config device add my-ubuntu webport proxy \
  listen=tcp:0.0.0.0:8080 \
  connect=tcp:127.0.0.1:80

This is convenient for testing web apps inside containers.

Profiles: Reusable Configuration

Profiles are templates for configuration and devices applied to containers.

View existing profiles:

lxc profile list
lxc profile show default

Create a custom profile (example: limited resources and extra disk):

lxc profile create limited
lxc profile edit limited

Example limited profile contents:

config:
  limits.cpu: "2"
  limits.memory: 1GB
devices:
  root:
    path: /
    pool: default
    type: disk
  data:
    path: /data
    pool: default
    source: shared-data
    type: disk

Apply to a container at launch:

lxc launch ubuntu:22.04 test1 -p default -p limited

Or add to an existing container:

lxc profile add my-ubuntu limited

Profiles make it easy to standardize environments (e.g., “web”, “db”, “ci-runner”).

Snapshots, Clones, and Image Management

Snapshots

Snapshots capture the state of a container’s filesystem at a point in time.

Create snapshot:

lxc snapshot my-ubuntu before-upgrade

List snapshots:

lxc info my-ubuntu | grep -A5 Snapshots

Restore snapshot:

lxc restore my-ubuntu before-upgrade

Snapshots are fast and space-efficient when using copy-on-write storage backends (ZFS/Btrfs/LVM-thin).

Cloning containers

Create a new container as a copy of an existing one:

lxc copy my-ubuntu my-ubuntu-copy

Useful for:

Creating and using images

Convert a container to an image:

lxc publish my-ubuntu --alias ubuntu-base

List local images:

lxc image list

Launch new containers from your image:

lxc launch ubuntu-base new-instance

You can also export/import images:

lxc image export ubuntu-base ./ubuntu-base.tar.gz
lxc image import ./ubuntu-base.tar.gz --alias ubuntu-base

This is handy for sharing standardized environments.

Security and Isolation Features

LXC/LXD rely on kernel isolation primitives (namespaces, cgroups, capabilities, seccomp, AppArmor) but LXD exposes user-friendly toggles.

Key concepts for this chapter’s scope:

Privileged vs unprivileged containers

You can toggle via a configuration key:

lxc config set my-ubuntu security.privileged true

Be cautious with privileged containers, especially on multi-user systems.

Nesting containers

To run containers inside LXD containers (for CI or testing):

lxc config set my-ubuntu security.nesting true

Nesting has security implications but is common for build/test pipelines.

Lightweight VM-Like Use Cases

LXD supports both containers and full virtual machines, but this chapter focuses on containers. Still, some VM-like use cases with containers are:

In practice, you can treat an LXD system container almost like a VM:

Example: Simple End-to-End Workflow

A minimal workflow to illustrate LXC/LXD in practice:

  1. Launch a container:
   lxc launch ubuntu:22.04 web1
  1. Enter the container and install a web server:
   lxc exec web1 -- bash
   apt update
   apt install -y nginx
   exit
  1. Expose HTTP to the host on port 8080:
   lxc config device add web1 http proxy \
     listen=tcp:0.0.0.0:8080 \
     connect=tcp:127.0.0.1:80
  1. Test from the host:
   curl http://127.0.0.1:8080
  1. Snapshot before experimentation:
   lxc snapshot web1 clean
  1. If configuration gets messy, restore:
   lxc restore web1 clean

This demonstrates how LXC/LXD provides fast, reproducible, VM-like environments using container technology.

When to Choose LXC/LXD

Given there is a separate chapter on Docker/Podman, it’s helpful to clarify when LXC/LXD is a better fit:

Use LXC/LXD when you want:

Use application containers (Docker/Podman) when you want:

Both can coexist; many people develop services in LXD containers and then package them as application containers for production.

Views: 19

Comments

Please login to add a comment.

Don't have an account? Register now!