Proxmox VM Deployment Automation
Create new VMs in Proxmox using VM Templates and Ansible in under 2 minutes.
This guide builds upon the previous Ansible tutorial, demonstrating how to leverage Proxmox and Ansible to create and deploy reusable Proxmox templates. This process reduces the time required to spin up a new VM, allowing you to have a ready-to-go machine in under two minutes.
Proxmox Template Creation
Download the Latest ISO Image:
- Navigate to
Storage > ISO Images > Download from URL
and download the latest LTS image for Ubuntu or the required distribution.
Create a VM to be Used as a Template:
- Create a VM as you usually would for a non-template VM:
- Set the VM's hardware settings and deploy the OS.
- Install the QEMU guest agent.
- Create an Ansible account and configure the SSH key.
- Remove the installation disk after setup.
- By default, Ubuntu uses Netplan to set DHCP without the MAC address, which means each new VM from the template will have the same IP as the original machine. To change this and issue a new IP to each new templated VM:
sudo nano /etc/netplan/50-cloud-init.yaml
- Add
dhcp-identifier: mac
underDHCP4: true
. - Save and exit.
- Shut down the VM completely.
Create the Template:
- Right-click on the VM and select
Create Template
.
Deploy a New VM:
- Right-click on the template and select
Clone
. - Choose
Mode: Full Clone
and set the desired name for the new VM.
Using Ansible for VM Setup
After deploying the new VM, you can optionally use Ansible to update the system, change the hostname, and install MeshCentral. The VM template is fully functional as-is, but for any additional configurations beyond the base setup, it is advisable to use Ansible.
Create an Ansible Inventory File
[servers]
NEW_SERVER_IP
[servers:vars]
ansible_user=ansible_user
ansible_ssh_private_key_file=/root/.ssh/id_ed2545219
ansible_become=true
ansible_become_method=sudo
ansible_become_password=password
new_machine
Ansible Playbooks
Create the individual YAML files for different tasks.
- Connectivity and Update Playbook (
new_update.yml
)
---
- name: Check connectivity and perform updates
hosts: servers
gather_facts: no
tasks:
- name: Ping all servers
ping:
- name: Update apt cache
apt:
update_cache: yes
- name: Upgrade all packages
apt:
upgrade: dist
- name: Check if upgrades were successful
shell: dpkg -l
register: result
- name: Display upgrade result
debug:
var: result.stdout
new_update.yml
- MeshCentral Deployment Playbook (
new_meshcentral.yml
)
---
- name: Deploy MeshCentral
hosts: servers
become: true
vars:
meshcentral_script_url: "https://remote.yourdomain.com/meshagents?script=1"
meshcentral_server_url: "https://remote.yourdomain.com"
meshcentral_key: "CONNECTION_KEY"
tasks:
- name: Download the MeshCentral install script (direct)
get_url:
url: "{{ meshcentral_script_url }}"
dest: /tmp/meshinstall.sh
- name: Download the MeshCentral install script (no proxy)
command: "wget '{{ meshcentral_script_url }}' --no-proxy -O /tmp/meshinstall.sh"
- name: Make the MeshCentral install script executable
file:
path: /tmp/meshinstall.sh
mode: '0755'
- name: Run the MeshCentral install script
command: "/tmp/meshinstall.sh '{{ meshcentral_server_url }}' '{{ meshcentral_key }}'"
environment:
https_proxy: ""
new_meshcentral.yml
- Set Host Name Playbook (
new_hostname.yml
)
---
- name: Change Hostname Playbook
hosts: servers
gather_facts: yes
become: yes
vars_prompt:
- name: new_hostname
prompt: "Please enter the new hostname"
private: no
tasks:
- name: Set the new hostname
hostname:
name: "{{ new_hostname }}"
- name: Update /etc/hostname
lineinfile:
path: /etc/hostname
line: "{{ new_hostname }}"
create: yes
- name: Update /etc/hosts
lineinfile:
path: /etc/hosts
regexp: '^127\.0\.1\.1'
line: "127.0.1.1 {{ new_hostname }}"
create: yes
backrefs: yes
- name: Reboot the server to apply changes
reboot:
msg: "Reboot initiated by Ansible for hostname change"
pre_reboot_delay: 5
post_reboot_delay: 30
reboot_timeout: 600
- name: Wait for the server to come back
wait_for_connection:
delay: 30
timeout: 300
- name: Confirm the hostname has been changed
command: hostname
register: result
- name: Verify hostname
debug:
msg: "Hostname has been changed to {{ result.stdout }}"
when: result.stdout == new_hostname
new_hostname.yml
- Deploy Docker and Docker Compose (
new_docker.yml
)
---
- name: Install Docker and Docker Compose
hosts: all
become: true
tasks:
- name: Update the apt package index
apt:
update_cache: yes
- name: Install Docker
apt:
name: docker.io
state: present
- name: Start Docker service
systemd:
name: docker
state: started
enabled: yes
- name: Install Docker Compose
apt:
name: docker-compose
state: present
new_docker.yml
Combine all the individual playbooks into a master playbook (new_machine_master.yml
):
---
- import_playbook: new_hostname.yml
- import_playbook: new_update.yml
- import_playbook: new_meshcentral.yml
- import_playbook: new_docker.yml
new_machine_master.yml
Edit the Inventory File:
- Update the IP address in the
new_machine
inventory file:nano new_machine
- Execute the Master Playbook:
ansible-playbook -i new_machine new_machine_master.yml
Creating a New VM from a Template
Whenever a new VM is required, follow these steps to deploy one:
Clone the Template:
- Right-click on the Proxmox template and select
Clone
. - Choose
Mode: Full Clone
and set the desired name.
Get the New VM's IP:
- Wait for the VM to boot up and retrieve its IP address.
Update the Inventory File:
- Add the new IP address to the
servers
list in thenew_machine
inventory file on your Ansible machine:nano new_machine
- Run the Ansible Playbook:
ansible-playbook -i new_machine new_machine_master.yml
Feel free to tweak and expand on these examples as needed for your specific environment.