Skip to main content

Using Ansible & Terraform w/ LXD

I've been making more and more use of infrastructure as code tools, specifically Ansible & Terraform. Most of my servers are running in LXD containers, which these tools provide interactions with.

Source Documentation
Architecture

The server has LXD installed and is configured for remote connections. The client has LXD installed as well and connects to the server. See Remote LXD Connections for more details on setting up LXD remoting. The client should be installed and configured on your workstation. The following should work from the workstation:

$ lxc ls lxd-server-01:
+------------------+---------+----------------------+------+-----------+-----------+
|      NAME        |  STATE  |         IPV4         | IPV6 |   TYPE    | SNAPSHOTS |
+------------------+---------+----------------------+------+-----------+-----------+
| lxd-container-01 | RUNNING | 192.168.1.100 (eth0) |      | CONTAINER | 0         |
+------------------+---------+----------------------+------+-----------+-----------+
| lxd-container-02 | RUNNING | 192.168.1.101 (eth0) |      | CONTAINER | 0         |
+------------------+---------+----------------------+------+-----------+-----------+
Example Terraform Configuration

Below is an example main.tf configuration for use with LXD. See comments in the example for important notes.

terraform {
  required_providers {
    lxd = {
      source = "terraform-lxd/lxd"
      version = ">= 1.10.1"
    }
  }
}

provider "lxd" {
  generate_client_certificates = false
  accept_remote_certificate = false

  ## If running the LXD client as a snap, the below config_dir should work
  ## If running another distro, try omitting this to use the default of $HOME/.config/lxc
  config_dir =  "$HOME/snap/lxd/common/config"

  lxd_remote {
    ## name is the name as shown in 'lxc remote list'
    name = "lxd-server-01"
    default = true
  }
}

resource "lxd_container" "lxd-container-01" {
  name = "lxd-container-01"
  image = "images:ubuntu/22.04"

  ## This copies a file in. In my case, I'm configuring static IPs using netplan,
  ## so the netplan configs are stored with the terraform code
  file {
    source = "netplan/lxd-container-01.yml"
    target_file = "/etc/netplan/10-lxc.yaml"
  }

  ## You can also configure disk mounts, and other LXD devices
  device {
    name = "mariadb"
    type = "disk"
    properties = {
      path = "/var/lib/mysql"
      source = "/tank/mariadb"
    }
  }
}
Example Ansible Inventory
---
all:
  hosts:
    lxd-server-01:
  children:
    containers:
      hosts:
        lxd-container-01:
        lxd-container-02:
      vars:
        ansible_connection: lxd
        ansible_lxd_remote: lxd-server-01

Once you have your inventory.yml vars properly configured you can run ansible as you normally would.

$ ansible -bom ping -i inventory.yml lxd-container-0*
lxd-container-01 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": false,"ping": "pong"}
lxd-container-02 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": false,"ping": "pong"}