Why?
If you run a Proxmox (cluster), sooner or later you might come to the point where you want to use Infrastructure as Code (IaC) principles to manage your workloads. You might also be annoyed by the fact that the default way of configuring, creating, starting, and stopping Linux containers (LXCs) in Proxmox usually happens manually using the web interface - at least I am.
How?
We're using Ansible. If you're not familiar with Ansible, check out the quickstart. In short, Ansible is a configuration management tool written in Python. It allows you to write your infrastructure and host configurations in concise YAML files (called playbooks). You can then execute these playbooks (usually via SSH) on an arbitrary amount of hosts and do things as simple as installing a package. There are no restrictions though, so with a bit of exercise, you can even do things like setting up webservers or managing Proxmox LXCs!
⚠ Ansible doesn't run on Windows, so you either need a Linux or macOS host/VM to follow this tutorial.
Assumptions
This is not an exhaustive guide on neither Proxmox nor Ansible. I assume that you have at least a basic understanding of how these tools work. If not, there are plenty of other blog posts and documentation pages out there that will help you get there.
Hands-on
Create a new folder on your machine and name it proxmox-lxc
. Populate it like shown below:
proxmox-lxc/
├── ansible.cfg
├── inventory
├── playbook_proxmox_lxc.yml
└── requirements.yml
Let's have a look into these files one after another.
requirements.yml
This file lists the external dependencies of your project. These could be Ansible roles from Ansible Galaxy or GitHub,
or some community collections. In this tutorial, we make heavy use of the bellackn.proxmox_lxc
role, which
requires one other role and one collection, as described in the role's README under Requirements. Put these in the
file:
---
roles:
- name: bellackn.proxmox_lxc
version: 4.1.0
- name: geerlingguy.pip
version: 2.0.0
collections:
- name: community.general
version: 2.1.1
Once that's done, run the following commands to install these dependencies on your machine:
$ ansible-galaxy role install -r requirements.yml
$ ansible-galaxy collections install -r requirements.yml
💡 With Ansible >=2.10, the command can also be shortened to
ansible-galaxy install -r requirements.yml
.
inventory
Our Ansible inventory comes here. Long story short:
proxmox
However you resolve your Proxmox instance, put that here. For example, if you can reach Proxmox at https://proxmox:8006 (as I can), the simple entry above works for you. If you have to use an FQDN, put that here.
ansible.cfg
Some general Ansible settings for our project belong here:
[defaults]
deprecation_warnings = False
nocows = True
The first entry ensures that Ansible doesn't spam us with deprecation warnings.
The second entry disables Ansible's default (!) behaviour to output every
log message wrapped in cowsay
. If you like messages like
____________________
< PLAY [Set up LXCs] >
--------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
all over your terminal, then you don't need this entry. I wouldn't recommend that, although cows are supreme animals.
playbook_proxmox_lxc.yml
Ah, finally. Put this in your playbook file:
---
- name: Set up LXCs
hosts: proxmox # This must match the hostname that you have put in `inventory`
gather_facts: no
vars:
# General settings
ansible_user: root
ansible_python_interpreter: /usr/bin/python3
# LXC-role specific settings
proxmox_lxc_api_user: your_proxmox_user # For example "root@pam"
proxmox_lxc_api_password: your_proxmox_password
proxmox_lxc_api_host: "{{ inventory_hostname }}"
proxmox_lxc_storage: local-lvm
# The LXCs you want to create
proxmox_lxc_containers_present:
- hostname: test
ostemplate: local:vztmpl/ubuntu-20.04-standard_20.04-1_amd64.tar.gz
netif: |
{"net0":"name=testnet,gw=192.168.0.1,ip=dhcp,bridge=vmbr0"}
password: password
cores: 1
disk: 16
memory: 1024
unprivileged: yes
# We delete the LXC we have just created
proxmox_lxc_containers_absent:
- hostname: test
roles:
- bellackn.proxmox_lxc
Here we specify what we want to do on Proxmox. First, we create an LXC called test
by populating the
proxmox_lxc_containers_present
list. We want the OS template to be Ubuntu 20.04 (this must be present on your Proxmox
instance beforehand) and the network gateway to be 192.168.0.1. This is my router address, yours is likely to be
different. The IP will be assigned by DHCP and the bridge we'll use is vmbr0 (also subject to change on your side).
The remaining variables are pretty self-explanatory; have a look at the role's documentation.
After this container was created, we want to delete it right away. To achieve this, we use the
proxmox_lxc_containers_absent
variable.
Run the playbook with this command:
$ ansible-playbook playbook_proxmox_lxc.yml -i inventory
Some things will happen then:
- Check that the required Python packages are installed on the Proxmox host
- Create the test container and start it
- Check if it can connect to the outside world (ping and SSH)
- Finally delete the container
... and that's it! You're now fully capable of managing your LXC's lifecycles on Proxmox using Ansible!
💡 Currently, there is an open newcomer-friendly issue in the
bellackn.proxmox_lxc
repository. Feel free to give me a hand!