Using Ansible to provision LXC containers

Since all of us have a bit of extra time lately I grabbed a copy of Jeff Geerling's Ansible for DevOps to finally tackle the project to translate my many, many bash scripts into something for flexible and idempotent.

Ever since I began moving a lot of my cloud-hosted projects and applications to my own hardware in a colocation facility, I've spent a lot of time spinning up linux containers on Proxmox and running bash scripts to get them into a state that's useful for me. This can get tedious and time consuming!

My first project with Ansible was to not only streamline the creating of linux containers on my Proxmox hypervisor, but to provision them with the base configuration they need—and to subscribe them to my FreeIPA domain for central authentication.

Besides the included README, you can find the entire playbook on GitHub.

ansible-pve-lxc

ansible-pve-lxc is an Ansible playbook and set of roles for provisioning and configuring LXC containers in a Proxmox virtual environment, and subsequently subscribing them to a FreeIPA domain.

Define inventory with container configurations

This inventory is in the YAML format, but will also work in INI format

---
proxmox:
hosts:
pve.site.domain

containers:
hosts:
db1.site.domain:
ansible_host: 10.0.10.125
app1.site.domain:
ansible_host: 10.0.10.126

Populate host variables with individual container configurations

host_vars/db1.site.domain.yml

---
node: 'gold'
vmid: '110'
cores: '1'
memory: '1024'
swap: '0'
onboot: true
network: '{"net0":"name=eth0,ip=10.0.10.125/24,gw=10.0.10.1,ip6=dhcp,bridge=vmbr1"}'

host_vars/app1.site.domain.yml

---
node: 'gold'
vmid: '111'
cores: '2'
memory: '2048'
swap: '0'
onboot: true
network: '{"net0":"name=eth0,ip=10.0.10.126/24,gw=10.0.10.1,ip6=dhcp,bridge=vmbr1"}'

Configure variables

Define PVE API and LXC default variables

group_vars/proxmox.yml

---
api_host: 'pve.site.domain'
api_user: 'root@pam'

defaults:
node: 'gold'
storage: 'local-zfs'
cores: '1'
memory: '1024'
onboot: true
pubkey: ''
searchdomain: 'site.domain'
nameserver: '1.1.1.1,8.8.8.8'
ostemplate: 'bulk:vztmpl/centos-8-20200402_amd64.tar.gz'
network: '{"net0":"name=eth0,ip=dhcp,ip6=dhcp,bridge=vmbr1"}'

Define PVE API password, SSH public key, and IPA admin password

group_vars/all.yml

---
api_password: '<proxmox_api_password>'
ssh_pubkey: '<ssh_public_key>'
ipa_domain: 'ipa.site.domain'
ipa_realm: 'IPA.SITE.DOMAIN'
ipa_principal: 'admin'
ipa_admin_pw: '<ipa_admin_password>'

Optional (but suggested!): Use ansible-vault to encrypt group_vars/all.yml

$ nsible-vault encrypt group_vars/all.yml

Use ansible-pve-lxc

Optional: Temporarily disable ssh host key checking

$ export ANSIBLE_HOST_KEY_CHECKING=False

Run playbook

$ ansible-playbook -i inventory site.yml --ask-become-pass

Run playbook while asking for the vault password interactively

$ ansible-playbook -i inventory site.yml --ask-become-pass --ask-vault-pass

Optional: Re-enable ssh host key checking

$ unset ANSIBLE_HOST_KEY_CHECKING