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 is configured with LXD, 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 remoting. The client should be installed and configured on your workstation.

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

Once you have your Ansible inventory configured, you may run ansible playbooks against your containers like you would any other system managed by Ansible.

---
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"}