2025-11-15 14:34:58 +01:00
|
|
|
|
# Ansible Role: Proxmox VM → Template → Clones (Cloud‑Init)
|
|
|
|
|
|
|
|
|
|
|
|
Automates the entire lifecycle of a Debian GenericCloud VM on Proxmox:
|
|
|
|
|
|
- Download the Debian image
|
|
|
|
|
|
- Create a base VM
|
|
|
|
|
|
- Optionally enable UEFI, SecureBoot, TPM 2.0, GPU passthrough
|
|
|
|
|
|
- Convert the VM into a template
|
|
|
|
|
|
- Spin up any number of Cloud‑Init clones with static or dynamic networking
|
|
|
|
|
|
|
|
|
|
|
|
## Features
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ Auto‑download Debian Bookworm GenericCloud image
|
|
|
|
|
|
- ✅ Create VM (CPU, RAM, networking, storage)
|
|
|
|
|
|
- ✅ DHCP or static IP support
|
|
|
|
|
|
- ✅ Cloud‑Init: users, SSH keys, passwords, timezone, packages
|
|
|
|
|
|
- ✅ Optional TPM 2.0 + SecureBoot (OVMF)
|
|
|
|
|
|
- ✅ Optional GPU passthrough or VirtIO GPU
|
|
|
|
|
|
- ✅ Optional disk resize
|
|
|
|
|
|
- ✅ Convert base VM into a template
|
|
|
|
|
|
- ✅ Create multiple clones from template
|
|
|
|
|
|
- ✅ Start clones after creation
|
|
|
|
|
|
|
|
|
|
|
|
## Folder Structure
|
|
|
|
|
|
|
|
|
|
|
|
```
|
2025-11-15 12:58:55 +01:00
|
|
|
|
ANSIBLE_PROXMOX_VM/
|
2025-11-15 14:34:58 +01:00
|
|
|
|
├─ defaults/
|
|
|
|
|
|
│ └─ main.yml
|
|
|
|
|
|
├─ tasks/
|
|
|
|
|
|
│ └─ main.yml
|
|
|
|
|
|
├─ templates/
|
|
|
|
|
|
│ ├─ cloudinit_userdata.yaml.j2
|
|
|
|
|
|
│ └─ cloudinit_vendor.yaml.j2
|
|
|
|
|
|
└─ README.md
|
|
|
|
|
|
```
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
## Requirements
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
- Proxmox API / Environment
|
|
|
|
|
|
- Role runs on the Proxmox host via localhost, using `qm` CLI commands.
|
|
|
|
|
|
- Ansible must have SSH access to the Proxmox node.
|
|
|
|
|
|
- User must have permission to run `qm` commands (root recommended).
|
|
|
|
|
|
- Proxmox storage pool such as `local-lvm`.
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
## Debian Cloud Image
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
The image is automatically downloaded if not present:
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
```
|
2025-11-15 12:58:55 +01:00
|
|
|
|
/var/lib/vz/template/qemu/debian-genericcloud-amd64.qcow2
|
2025-11-15 14:34:58 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Variables (`defaults/main.yml`)
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
```yaml
|
|
|
|
|
|
# Base VM settings
|
2025-11-15 12:58:55 +01:00
|
|
|
|
vm_id: 150
|
|
|
|
|
|
hostname: debian-template-base
|
|
|
|
|
|
memory: 4096
|
|
|
|
|
|
cores: 4
|
|
|
|
|
|
bridge: vmbr0
|
|
|
|
|
|
storage: local-lvm
|
|
|
|
|
|
mac_address: "DE:AD:BE:EF:44:55"
|
|
|
|
|
|
cpu_type: host
|
|
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
# Networking
|
|
|
|
|
|
ip_mode: dhcp # or 'static'
|
2025-11-15 12:58:55 +01:00
|
|
|
|
ip_address: "192.168.1.60/24"
|
|
|
|
|
|
gateway: "192.168.1.1"
|
|
|
|
|
|
dns:
|
|
|
|
|
|
- "1.1.1.1"
|
|
|
|
|
|
- "8.8.8.8"
|
|
|
|
|
|
ipconfig0: "{{ 'ip=dhcp' if ip_mode == 'dhcp' else 'ip=' + ip_address + ',gw=' + gateway }}"
|
|
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
# Cloud‑Init user
|
2025-11-15 12:58:55 +01:00
|
|
|
|
ci_user: debian
|
|
|
|
|
|
ci_password: "SecurePass123"
|
|
|
|
|
|
ssh_key_path: "~/.ssh/id_rsa.pub"
|
|
|
|
|
|
timezone: "Europe/Berlin"
|
|
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
# Disk
|
2025-11-15 12:58:55 +01:00
|
|
|
|
resize_disk: true
|
|
|
|
|
|
resize_size: "16G"
|
|
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
# GPU passthrough
|
2025-11-15 12:58:55 +01:00
|
|
|
|
gpu_passthrough: false
|
|
|
|
|
|
gpu_device: "0000:01:00.0"
|
|
|
|
|
|
virtio_gpu: false
|
|
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
# UEFI + TPM
|
2025-11-15 12:58:55 +01:00
|
|
|
|
enable_tpm: false
|
|
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
# Templates + Clones
|
2025-11-15 12:58:55 +01:00
|
|
|
|
make_template: true
|
|
|
|
|
|
create_clones: true
|
|
|
|
|
|
clones:
|
|
|
|
|
|
- id: 301
|
|
|
|
|
|
hostname: app01
|
|
|
|
|
|
ip: "192.168.1.81/24"
|
|
|
|
|
|
gateway: "192.168.1.1"
|
2025-11-15 14:34:58 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Usage
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
### Include the role in a playbook
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
2025-11-15 12:58:55 +01:00
|
|
|
|
- hosts: proxmox
|
|
|
|
|
|
become: true
|
|
|
|
|
|
roles:
|
|
|
|
|
|
- ANSIBLE_PROXMOX_VM
|
2025-11-15 14:34:58 +01:00
|
|
|
|
```
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
### Run directly
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
```bash
|
2025-11-15 12:58:55 +01:00
|
|
|
|
ansible-playbook tasks/main.yml -i inventory
|
2025-11-15 14:34:58 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Clone Creation Flow
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
For each clone defined in `clones`:
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
1. `qm clone 150 <clone_id>`
|
|
|
|
|
|
2. Set hostname & Cloud‑Init netplan
|
|
|
|
|
|
3. Start the VM
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
### Example `clones` section
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
2025-11-15 12:58:55 +01:00
|
|
|
|
clones:
|
|
|
|
|
|
- id: 301
|
|
|
|
|
|
hostname: app01
|
|
|
|
|
|
ip: "192.168.1.81/24"
|
|
|
|
|
|
gateway: "192.168.1.1"
|
2025-11-15 14:34:58 +01:00
|
|
|
|
```
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
## Cloud‑Init Templates
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
### `templates/cloudinit_userdata.yaml.j2`
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
|
|
|
|
|
Defines:
|
2025-11-15 14:34:58 +01:00
|
|
|
|
- `users`
|
|
|
|
|
|
- SSH key
|
|
|
|
|
|
- password
|
|
|
|
|
|
- timezone
|
|
|
|
|
|
- package updates
|
|
|
|
|
|
- custom commands
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
### `templates/cloudinit_vendor.yaml.j2`
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
|
|
|
|
|
Defines:
|
2025-11-15 14:34:58 +01:00
|
|
|
|
- default packages
|
|
|
|
|
|
- DNS (optional)
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
## Notes & Best Practices
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
- Ensure Proxmox has snippets storage enabled (`Datacenter → Storage`).
|
|
|
|
|
|
- If cloning fails with an invalid IP, check the format: `"192.168.1.81/24"`.
|
|
|
|
|
|
- Both SSH keys and password login are supported (`ssh_pwauth: true`).
|
|
|
|
|
|
- If GPU passthrough is enabled, ensure the host kernel is configured for IOMMU.
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
## Future Improvements (optional)
|
2025-11-15 12:58:55 +01:00
|
|
|
|
|
2025-11-15 14:34:58 +01:00
|
|
|
|
- Switch to `community.general.proxmox` API module instead of CLI
|
|
|
|
|
|
- Validate clone IDs
|
|
|
|
|
|
- Automated post‑deployment provisioning (Ansible SSH into clones)
|
|
|
|
|
|
- Publish as a Galaxy‑ready role
|