Motivation
If we instantiate LXC containers, say with Ubuntu 22.04, and try ssh onto it, you will find that the default setting (at least the image from Ubuntu cloudimage) of SSH server doesn’t allow password for authentication. Only SSH keys are allowed. Also the container would get the IP from the dhcp, which could be inconvenient if you want these containers talking to each other (unlike docker compose which would populate the /etc/hosts with the container names).
The goal here is to be able to provision multiple ephermal hosts for lab exercises (breaking stuff in order to learn them …)
Solution
There are many solution to the the scenario here indeed. This time we would explore the use of cloud-init (which integrated well with the LXD) with Terraform (which also see a recent(?) update to the provider for lxd)
Tasks
Simple enough, i need
Get the SSH keys to the authorized_keys
Configure static IP automatically
populate the /etc/hosts for QoL
Cloud-init
There are two file i need for cloud-init to do what i aim to do, the cloud-init.user-data and cloud-init.network-config. LXD doc
The cloud-init.user-data would be something like
#cloud-config users: - name: mgmt groups: admin ssh_authorized_keys: - [your pub key]
The cloud-init.network-config would be like below. The file follows Version 2 format defined for the Netplan tool (well supported on Ubuntu).
network: version: 2 ethernets: eth0: addresses: - 10.188.251.100/24
Notice that we should actually template this file because we will need to instantiate multiple hosts. The CIDR range should also be getting from the bridge defined by the network module and default profile as well. For simplicity, we will just use the value of the default bridge given when we first do lxc init.
Terraform
We will do a minimal PoC setup for one container for now, so we don’t bother with the templating stuff for now. I, however, did spend sometime try to get the above 2 files inline on the terraform config. I tried either both the indent-aware Heredoc and the plain Heredoc syntax, both failed. I decided to go with the file function of tf and ended up with the below
terraform { required_providers { lxd = { source = "terraform-lxd/lxd" version = "2.0.0" } } } provider "lxd" { } resource "lxd_instance" "container1" { name = "container1" image = "ubuntu:22.04" config = { "cloud-init.user-data" = file("/home/mgmt/my-user-data"), "cloud-init.network-config" = file("/home/mgmt/my-network-config") } }
Finally …
terraform apply and …
ssh into it to verify the ssh key did go through