Getting started

LXD installation details

At the time of writing this role (December 2019) LXD was not available natively in Debian. Packaging efforts are ongoing, however there's no telling if LXD will be included in the next Debian release (Bullseye). The upstream developers suggest installation on Debian via Snap, however this brings its own set of issues which are offtopic here.

Instead, on Debian hosts the debops.lxd role utilizes the debops.golang role to install the lxd and lxc binaries from upstream git repository by compiling them from source. The role will configure the rest of the needed infrastructure (systemd unit files, logrotate and sysctl configuration, POSIX groups, log directory, etc.) so that the LXD service should work out of the box on Debian without the need of a Snap installation.

The debops.golang configuration for building and installing LXD is defined in the lxd__golang__dependent_packages variable.

Due to the build dependency on the lxc-dev APT package, which pulls the lxc APT package automatically, the debops.lxc role and its dependencies will be used to configure the LXC environment. The lxcbr0 network brige will be automatically disabled in this case.

Example inventory

To enable LXD support on a host, it needs to be added to the [debops_service_lxd] Ansible inventory group:

[debops_all_hosts:children]
lxd_hosts
lxd_containers

[debops_service_lxd:children]
lxd_hosts

[lxd_hosts]
lxd-host    ansible_host=lxd-host.example.org

[lxd_containers]
webserver   ansible_host=webserver.example.org

By default, containers will use the lxdbr0 bridge managed by the LXD service, with their own internal lxd subdomain. You can use the debops.ifupdown Ansible role to configure additional network bridges on the LXD host, if you want to attach the containers to the public network.

Example playbook

If you are using this role without DebOps, here's an example Ansible playbook that uses the debops.lxd role:

---

- name: Manage LXD service
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_service_lxd' ]
  become: True

  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'

  roles:

    - role: resolvconf
      tags: [ 'role::resolvconf', 'skip::resolvconf' ]
      resolvconf__enabled: True

    - role: root_account
      tags: [ 'role::root_account', 'skip::root_account' ]

    - role: keyring
      tags: [ 'role::keyring', 'skip::keyring', 'role::golang' ]
      keyring__dependent_gpg_user: '{{ golang__keyring__dependent_gpg_user }}'
      keyring__dependent_gpg_keys:
        - '{{ golang__keyring__dependent_gpg_keys }}'
      golang__dependent_packages:
        - '{{ lxd__golang__dependent_packages }}'

    - role: apt_preferences
      tags: [ 'role::apt_preferences', 'skip::apt_preferences' ]
      apt_preferences__dependent_list:
        - '{{ golang__apt_preferences__dependent_list }}'
        - '{{ lxc__apt_preferences__dependent_list }}'

    - role: golang
      tags: [ 'role::golang', 'skip::golang' ]
      golang__dependent_packages:
        - '{{ lxd__golang__dependent_packages }}'

    - role: logrotate
      tags: [ 'role::logrotate', 'skip::logrotate' ]
      logrotate__dependent_config:
        - '{{ lxd__logrotate__dependent_config }}'

    - role: ferm
      tags: [ 'role::ferm', 'skip::ferm' ]
      ferm__dependent_rules:
        - '{{ lxc__ferm__dependent_rules }}'

    - role: python
      tags: [ 'role::python', 'skip::python', 'role::lxc' ]
      python__dependent_packages3:
        - '{{ lxc__python__dependent_packages3 }}'
      python__dependent_packages2:
        - '{{ lxc__python__dependent_packages2 }}'

    - role: sysctl
      tags: [ 'role::sysctl', 'skip::sysctl' ]
      sysctl__dependent_parameters:
        - '{{ lxc__sysctl__dependent_parameters }}'
        - '{{ lxd__sysctl__dependent_parameters }}'

    - role: lxc
      tags: [ 'role::lxc', 'skip::lxc' ]

    - role: lxd
      tags: [ 'role::lxd', 'skip::lxd' ]

# If a host has 'debops.dnsmasq' or 'debops.unbound' roles configured, execute
# its playbook in case that configuration applied by the 'lxd' role needs to be
# applied to 'dnsmasq' or 'unbound' services. This should ensure that the
# '*.lxd' subdomain for internal LXD containers is resolvable on the LXD host.
#
# If the host is not in the Ansible inventory groups required by the
# 'dnsmasq.yml' or the 'unbound.yml' playbooks, this should not impact
# anything.

- import_playbook: 'dnsmasq.yml'

- import_playbook: 'unbound.yml'

Ansible tags

You can use Ansible --tags or --skip-tags parameters to limit what tasks are performed during Ansible run. This can be used after a host was first configured to speed up playbook execution, when you are sure that most of the configuration is already in the desired state.

Available role tags:

role::lxd
Main role tag, should be used in the playbook to execute all of the role tasks as well as role dependencies.
role::lxd:init
Re-apply the LXD preseeding configuration. Requires the lxd__init_preseed variable to be set to True to be effective.

Other resources

List of other useful resources related to the debops.lxd Ansible role: