LXD

In Juju, LXD is a machine cloud that can run both system containers and virtual machines, and works as described below.

Note

This reference assumes basic familiarity with Juju. If you are new to Juju, start with the Tutorial, then use this page together with the generic materials it links to. For a cloud-specific starting point, see Appendix: Example workflows.

Reasons to use a LXD cloud

The LXD cloud, especially when used locally, is great for:

  • creating a repeatable deployment: Juju enables you to quickly iterate to construct the optimal deployment for your situation, then distribute that across your team.

  • local development: Juju’s localhost cloud can mirror the production ops environment (without incurring the costs involved with duplicating it).

  • learning Juju: LXD is a lightweight tool for exploring Juju and how it operates.

  • rapid prototyping: LXD is great for when you’re creating a new charm and want to be able to quickly provision capacity and tear it down.

Why Docker wouldn’t work

Juju expects to see an operating system-like environment, so a LXD system container fits the bill. Docker containers are laid out for a singular application process, with a self-contained filesystem rather than a base userspace image.

Requirements

  • Juju 2.9.x: LXD 5.0

  • Juju 3.x.x: LXD 5.x

Concepts

The following table shows how LXD abstractions map to Juju concepts:

LXD

Juju

Container or VM instance

machine

Process in a container or VM

unit

Group of units for one workload

application

Storage pool volume

storage

LXD project

Administrative boundary for model resources (roughly)

Cluster member

Placement target (zones)

The cloud

See also: Cloud, Juju | Manage clouds, Terraform Provider for Juju | Manage clouds

As for all machine clouds, the cloud is registered in Juju via a cloud definition, stored in clouds.yaml on the client (on Linux: ~/.local/share/juju/clouds.yaml) and following this schema:

clouds:
  <cloud-name>:  # User-defined name
    type: lxd
    auth-types:
      - <auth-type>                # See Authentication types below
    endpoint: <lxd-api-url>        # LXD API endpoint (remote only)
    config:                        # Optional: model config defaults
      <config-key>: <value>        # See Configuration keys below

Localhost vs. remote LXD

  • Local LXD cloud: Recognized as localhost cloud. Credential pre-defined for admin users.

  • Clustered LXD cloud: In Juju, this counts as a remote cloud. You must add its definition to Juju explicitly.

  • Remote LXD cloud: Requires the API endpoint URL for the remote LXD server.

Credentials

See also: Credential, Juju | Manage credentials, Terraform Provider for Juju | Manage credentials

As for all machine clouds, credentials are stored in credentials.yaml on the client and follow this schema:

credentials:
  localhost                       # or user-defined for remote
    <credential-name>:             # User-defined credential name
      auth-type: <auth-type>       # certificate | interactive (see Authentication types below)
      <attribute>: <value>         # Auth-type-specific attributes (see below)

Local LXD cloud: If you are a Juju admin user, the credential is already known to Juju. Run juju bootstrap, then juju credentials to confirm. (Pre-defined credential name in Juju: localhost.) Otherwise, add manually as you would a remote.

Remote LXD cloud: Requires the API endpoint URL for the remote LXD server.

Authentication types

LXD supports the following authentication types:

certificate

Attributes:

  • server-cert: The path to the PEM-encoded LXD server certificate file (required).

  • client-cert: The path to the PEM-encoded LXD client certificate file (required).

  • client-key: The path to the PEM-encoded LXD client key file (required).

interactive

Attributes:

  • trust-token: The LXD server trust token (optional, required if trust-password is not set). This is the recommended method for authenticating with a remote LXD server. Added in Juju 3.6.4.

  • trust-password: The LXD server trust password (optional, required if trust-token is not set).

Controllers

See also: Controller, Juju | Manage controllers, Terraform Provider for Juju | Manage controllers

Bootstrap behavior

Creates a controller container or VM on LXD. Uses LXD API calls to create profiles, images, and instances.

Note

If juju bootstrap hangs, it could be due to a firewall issue. See: LXD | UFW: Add rules for the bridge .

Resources created at bootstrap

The controller runs on an LXD instance provisioned using the same mechanisms as workload machines – see Resources created per machine for the full per-machine resource model. Controller-specific differences are noted below.

Compute

  • LXD image: Downloaded from image servers (simplestreams), filtered by base OS, architecture, and virtualization type, and cached locally in /var/lib/lxd/images.

  • Controller instance: Created from the selected image with the default profile plus the model profile, connected to network and root storage, then started. Instance name: juju-<modeluuid>-<machinenum>.

Storage

  • Model profile: Name juju-<modelname>-<shortID>. Includes settings such as boot.autostart=true and security.nesting=true. Applied to every container/VM in the model.

Models

See also: Model, Juju | Manage models, Terraform Provider for Juju | Manage models

Configuration keys

LXD supports the following cloud-specific model configuration keys:

Storage

  • project: The LXD project name to use for Juju’s resources. Type: string. Default: "default". Immutable: false.

Machines

See also: Machine, Juju | Manage machines, Terraform Provider for Juju | Manage machines

Note

With LXD system containers, constraints are interpreted as resource maximums (as opposed to minimums).

There is a 1:1 correspondence between a Juju machine and a LXD container/VM. Compare juju machines and lxc list.

Constraints

LXD supports the following constraints:

Compute

  • arch. Valid values: Host architecture.

  • cores

  • instance-type

  • mem. The maximum amount of memory that a machine/container will have.

  • virt-type. Valid values: container (default), virtual-machine.

Networking

  • zones. LXD node name(s). In clustered LXD, specifies which cluster member to place the instance on.

Storage

Placement directives

LXD supports the following placement directives:

Resources created per machine

Applies to all machines, including controller machines. Controller-specific defaults are documented in Resources created at bootstrap.

Compute

  • LXD instance: Container (default) or VM (when constrained with virt-type). Name: juju-<modeluuid>-<machinenum>.

  • Profiles applied: In order: (1) default (LXD built-in), (2) model profile (juju-<model>-<id>), (3) charm profiles (juju-<model>-<id>-<appname>-<rev>) if specified by charm.

  • Constraints via config: limits.cpu=<cores> (CPU cores limit), limits.memory=<MiB>MiB (memory limit).

Networking

  • Network interfaces: Default eth0 bridged to default network. Additional NICs (eth1, eth2, etc.) for space constraints. Each NIC: type nic, nictype=bridged, parent host bridge, generated MAC address.

  • Cloud-init network config: Netplan generated for multiple NICs when needed.

Storage

  • Root disk device (if constraint specified): Type disk, pool from root-disk-source, path /, size in MiB.

Networking behavior

  • Network discovery: Lists LXD networks and uses bridge networks for machine placement.

  • Subnet ID format: subnet-<hostBridgeName>-<CIDR>. Example: subnet-lxdbr0-10.0.0.0/24.

  • NIC assignment: Default eth0 from default profile. Additional NICs for space constraints are bridged to host bridges.

  • IP assignment: Assigned by host bridge DHCP on the LXD host.

Storage behavior

See also: lxd for the LXD storage provider configuration options.

  • Storage pools: Juju storage pool creates a corresponding LXD storage pool. LXD pool for Juju lxd pool created on first use (named juju).

  • Volumes stored: /var/lib/lxd/storage-pools/<pool-name>.

  • Default pools attempted: lxd-zfs (driver zfs) then lxd-btrfs (driver btrfs).

Charm profiles

LXD Profiles allow a configuration to be applied to any instance. Juju applies charm profiles during the creation or modification of a LXD container.

Storage

Storage providers

In addition to generic storage providers, LXD provides the following cloud-specific storage providers:

lxd

Type: LXD storage pools (filesystem-backed, no volumes)

Scope: Environment-wide pools

Configuration options:

  • driver: LXD storage driver. Valid values: zfs, btrfs, lvm, ceph, dir.

  • lxd-pool: The name to give to the corresponding storage pool in LXD.

Any other parameters will be passed to LXD (e.g., zfs.pool_name).

Example deployment:

juju deploy postgresql --storage pgdata=lxd,8G

Appendix: Example workflows

Bootstrap on a remote LXD server

  1. Add the remote LXD cloud with juju add-cloud, providing the remote server’s API endpoint URL.

  2. Add credentials with juju add-credential choosing interactive or certificate.

  3. Bootstrap with juju bootstrap <cloud-name> <controller-name>.

LXD clustering

LXD clustering provides high-availability deployment. In a clustered LXD cloud, Juju deploys units across cluster nodes. Availability zones map to cluster member names.

LXD projects

LXD projects provide isolated namespaces for models (multi-tenancy). Configured via cloud spec Project field. Profile, network, storage, and container APIs are scoped to the project.

LXD images

LXD is image-based. All LXD containers come from images and any LXD daemon instance (also called a “remote”) can serve images. When LXD is installed, a locally-running remote is provided (Unix domain socket) and the client is configured to talk to it (named ‘local’). The client is also configured to talk to several other, non-local, ones (named ‘ubuntu’, ‘ubuntu-daily’, and ‘images’).

An image is identified by its fingerprint (SHA-256 hash), and can be tagged with multiple aliases. Juju pulls official cloud images from the ‘ubuntu’ remote (http://cloud-images.ubuntu.com ) and caches them locally in /var/lib/lxd/images.