Manage Proxmox LXCs with Ansible
Mon Jun 28, 2021 · 838 words · 5 min

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:

  1. Check that the required Python packages are installed on the Proxmox host
  2. Create the test container and start it
  3. Check if it can connect to the outside world (ping and SSH)
  4. 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!


about · blog · contact · legal notice · home