Files
ansible-collection-infrastr…/roles/proxmox_lxc_provision/README.md
T
patrick 4f09e886c2 feat(proxmox_lxc_provision): support custom bridge, interface name, and VLAN tag
The bridge (vmbr0) and interface name (eth0) were previously hardcoded
in the netif string, and there was no way to set an 802.1Q VLAN tag.
Expose lxc_bridge, lxc_iface_name, and lxc_vlan_tag (optional) so
containers can be attached to non-default bridges or tagged into a VLAN
without forking the role.

Also drop the misleading 'lxc_ipv6 | default(omit)' filter — default(omit)
does not produce omission inside a string context, and lxc_ipv6 always
has a default of 'auto' in defaults/main.yml.
2026-06-27 21:23:14 -04:00

204 lines
8.3 KiB
Markdown
Executable File

# Ansible Role: proxmox_lxc_provision
## Description
This Ansible role manages the provision of LXC containers and templates on a Proxmox host. By default the role will create and start an LXC container. It allows creating a new container from a [container image](https://pve.proxmox.com/wiki/Linux_Container#pct_container_images) or cloning an existing container or template container.
It also includes tasks which may be used individually:
- `clone.yml`: Creates a new LXC container by cloning another container or template
- `convert.yml`: Converts an LXC container to a template
- `create.yml`: Creates a new LXC container
- `delete.yml`: Deletes an LXC container given its vmid or hostname
- `start.yml`: Starts an LXC container
- `stop.yml`: Stops an LXC container
- `update.yml`: Updates an existing LXC container
- `wait.yml`: Waits for SSH to be available on the container
- `check-exists.yml`: Checks if an LXC exists by `lxc_vmid` or `lxc_hostname`
- `post-clone.yml`: Post-clone configuration (passwords, SSH host key regeneration). Runs against the new container; depends on the `system_setup` role.
- `edit-config.yml`: Edits `/etc/pve/lxc/<vmid>.conf` directly to add ID mappings and NVIDIA GPU passthrough entries. Must be delegated to the Proxmox host.
## Requirements
- Ansible 2.12 or higher
- Python 3.6 or higher
- requests
- proxmoxer
- passlib
## Role Variables
### Required Proxmox API Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `proxmox_api_host` | The IP address or hostname of the Proxmox server | `192.168.1.10` |
| `proxmox_api_user` | The username for Proxmox authentication, typically in format `username@realm` | `ansible@pve` |
| `proxmox_api_token_id` | The API token ID used for authentication | `token` |
| `proxmox_api_token_secret` | The secret key associated with the API token | `xxx-yyy-zzz` |
| `proxmox_node` | The name of the Proxmox node to target | `pve01` |
### Optional Proxmox API Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `proxmox_api_port` | The port on which the Proxmox API is listening | `8006` |
| `proxmox_api_validate_certs` | Whether to validate SSL certificates | `false` |
| `proxmox_delegate_host` | Inventory hostname for delegated tasks (pct commands). Use this to inherit `ansible_become_password` from inventory. | `{{ proxmox_api_host }}` |
### Required Container Variables
| Variable | Description | Example |
|----------|-------------|---------|
| `lxc_template` | The OS template to create the LXC from. Mutually exclusive with `lxc_clone_from` | `local:vztmpl/debian-12_amd64.tar.zst` |
| `lxc_clone_from` | The vmid of the container or template to clone. Mutually exclusive with `lxc_template` | `201` |
| `lxc_hostname` | The hostname for the container | `my-container` |
| `lxc_vmid` | The VM ID for the container | `100` |
### Optional Container Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `lxc_clone_type` | Clone type when using `lxc_clone_from` | `full` |
| `lxc_storage` | Target storage for the container | `local-zfs` |
| `lxc_size` | Disk size in GB | `16` |
| `lxc_disk` | The target storage and storage size | `local-zfs:16` |
| `lxc_root_password` | Password for the root account. On creates from `lxc_template` it is set via the Proxmox API; on clones it is applied inside the container by `post-clone.yml`. | - |
| `lxc_user_name` | Name of an additional non-root user to manage in `post-clone.yml` (clone path only). | `admin` |
| `lxc_user_password` | Password for `lxc_user_name`. Only applied on the clone path via `post-clone.yml`. The user must already exist in the source template. | - |
| `lxc_cores` | The number of CPU cores | `4` |
| `lxc_memory` | Memory size in MB | `2048` |
| `lxc_swap` | Swap memory size in MB | `2048` |
| `lxc_ipv4` | The IPv4 address | `dhcp` |
| `lxc_ipv6` | The IPv6 address | `auto` |
| `lxc_gateway` | The default gateway | `10.0.0.1` |
| `lxc_nameserver` | DNS nameserver | `10.0.0.7` |
| `lxc_bridge` | Linux bridge on the Proxmox host to attach the container to | `vmbr0` |
| `lxc_iface_name` | Interface name inside the container | `eth0` |
| `lxc_vlan_tag` | 802.1Q VLAN tag (integer 1-4094). Omitted from netif when unset. | - |
| `lxc_pubkey_file` | Path to SSH public key file | `~/.ssh/id_ed25519.pub` |
| `lxc_features` | List of container features | `["nesting=1"]` |
| `lxc_tags` | Tags for the container | `["ansible-managed"]` |
| `lxc_start` | Start container after creation | `true` |
| `lxc_unprivileged` | Create as an unprivileged container | `true` |
| `lxc_mounts` | Dict of additional bind mounts (e.g. `{ mp0: "/srv/data,mp=/data" }`) | - |
| `lxc_onboot` | Start container on Proxmox host boot | `false` |
| `lxc_startup` | Startup order string passed to Proxmox (e.g. `order=1,up=30`) | - |
| `lxc_timezone` | Timezone inside the container (e.g. `Europe/Berlin`) | - |
| `lxc_nvidia_gpu_mount` | Add NVIDIA GPU passthrough entries via `edit-config.yml` | `false` |
| `gpu_device_id` | Major device number for `/dev/nvidia*` (required when `lxc_nvidia_gpu_mount` is true) | - |
| `uvm_device_id` | Major device number for `/dev/nvidia-uvm*` (required when `lxc_nvidia_gpu_mount` is true) | - |
| `lxc_id_mappings` | Multi-line `lxc.idmap:` block written into the container config by `edit-config.yml` | - |
## Example Playbook
### Prerequisites
Set up your Proxmox API connection variables in group vars:
```yaml
# group_vars/all.yml
proxmox_api_host: "10.0.1.1"
proxmox_api_port: 8006
proxmox_api_user: "automation@pve"
proxmox_api_token_id: "mytoken"
proxmox_api_token_secret: "{{ vault_proxmox_token }}"
proxmox_api_validate_certs: false
proxmox_node: "pve01"
proxmox_delegate_host: "proxmox_server" # inventory hostname for become_password
```
### Creating a new LXC from template
```yaml
- name: Create and start an LXC container
hosts: localhost
connection: local
vars:
lxc_vmid: 100
lxc_hostname: new-debian-container
lxc_template: "local:vztmpl/debian-12_amd64.tar.zst"
lxc_ipv4: "10.0.0.99/24"
roles:
- role: proxmox_lxc_provision
```
### Creating a new LXC by cloning an existing container
```yaml
- name: Clone an LXC container
hosts: localhost
connection: local
vars:
lxc_vmid: 101
lxc_hostname: cloned-container
lxc_clone_from: 200
lxc_ipv4: "10.0.0.100/24"
roles:
- role: proxmox_lxc_provision
```
### Idempotent Behavior
The role includes idempotency checking. If a container with the specified `lxc_vmid` or `lxc_hostname` already exists, the role will skip provisioning and exit gracefully. Sets `lxc_exists` fact for use in subsequent tasks.
### Using Standalone Tasks
When using individual task files via `tasks_from`, you must set `module_defaults` at the play level since the tasks bypass the role's main entry point:
```yaml
- name: Convert container to a template
hosts: localhost
module_defaults:
community.proxmox.proxmox:
api_host: "{{ proxmox_api_host }}"
api_port: "{{ proxmox_api_port }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
validate_certs: "{{ proxmox_api_validate_certs }}"
node: "{{ proxmox_node }}"
vars:
lxc_hostname: "{{ lxc_hostname }}"
tasks:
- include_role:
name: proxmox_lxc_provision
tasks_from: convert
```
### Creating an LXC Container and Converting it to a Template
```yaml
---
- name: Create and start an LXC container
hosts: localhost
connection: local
vars:
lxc_vmid: "{{ lxc_vmid }}"
lxc_hostname: "{{ lxc_hostname }}"
lxc_template: "local:vztmpl/debian-12_amd64.tar.zst"
lxc_ipv4: "10.0.0.99/24"
roles:
- role: proxmox_lxc_provision
# Run configuration tasks on the container...
- name: Convert the created container to a template
hosts: localhost
module_defaults:
community.proxmox.proxmox:
api_host: "{{ proxmox_api_host }}"
api_port: "{{ proxmox_api_port }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
validate_certs: "{{ proxmox_api_validate_certs }}"
node: "{{ proxmox_node }}"
vars:
lxc_hostname: "{{ lxc_hostname }}"
tasks:
- include_role:
name: proxmox_lxc_provision
tasks_from: convert
```