Deploying Infrastructure on Proxmox with Ansible

Initial setup and first container

Table of Contents

I’ve broken down my HomeLab, and I’m rebuilding it in Ansible for deployment on a Proxmox cluster.

Configure Proxmox for ansible

I’ve been working off morph027’s workflow for a first successful run. He uses the ansible plugin proxmox_kvm, and I’m using proxmox (for containers).

Infrastructure

Short and sweet:

[proxmox]
gold
silver
bronze

Setup script

To get my blood pumping, I wrote a playbook to configure the three nodes:

# install_pip.yml
---
- name: 'prep proxmox hosts for automation'
  hosts: 'proxmox'
  gather_facts: false
  vars:
    packages:
      - 'python-pip'
      - 'python-dev'
      - 'build-essential'

  tasks:
    - name: 'install python-apt so native apt plugins work'
      package:
        name: 'python-apt'
        state: 'present'
    - name: 'switch to community repos'
      apt_repository:
        repo: 'deb https://enterprise.proxmox.com/debian/pve stretch pve-enterprise'
        state: 'absent'
      apt_repository:
        repo: 'deb http://download.proxmox.com/debian/pve stretch pve-no-subscription'
        state: 'present'
    - name: 'Update all packages to the latest version'
      apt:
        upgrade: 'dist'
    - name: 'Install pip packages'
      apt:
        name: "{{ packages }}"
    - name: 'pip update pip'
      pip:
        name: 'pip'
        state: 'latest'
    - name: 'Install dependencies'
      pip:
        name: 'virtualenv'
        state: 'latest'
      pip:
        name: 'proxmoxer'
        state: 'latest'

And ran that little bad boy.

Define variables

Since I’m using both LXC containers and VMs in my lab, this shows the beginnings of modular definitions. I’d like to define tiny, small, medium, and large hosts, a la cloud. Either as a complete system, or semi-modular. But for now, I just have this.

I’m also using the VM ID, because I want this to be idempotent.

---
# proxmox and proxmox_kvm options
api_user: 'root@pam'
api_password: '%'
api_host: 'gold'
defaults:
  balloon: '1024'
  cores: '1'
  cpu: 'host'
  format: 'qcow2'
  memory:
    ct: '1024'
    vm: '2048'
  net: '{"net0":"virtio,bridge=vmbr0"}'
  onboot: true
  ostype: 'l26'
  pubkey: '%'
  scsihw: 'virtio-scsi-pci'
  searchdomain: 'lan.nathancurry.com'
  storage:
    ct: 'local-lvm'
    vm: 'gluster'
  virtio: '{"scsi0":"gluster:10,cache=writeback,discard=on"}'

ostemplate: 'gluster:vztmpl/centos-7-default_20171212_amd64.tar.xz'

cts:
  ns:
    vmid:
    node: 'gold'
    type: 'centos'
    memory: '1024'
    swap: '0'
    cores: '1'
    ip_address: '10.3.3.2'
    netmask: '255.255.255.128'
    gateway: '10.3.3.1'
    nameserver: '10.3.3.1'

Define a playbook

This was where a lot of the work was. This was tailored to the spinning up VMs, and so I had to mess with it a bit.

---
- name: 'deploy containers'

  hosts: 'gold'
  gather_facts: false

  handlers:
  - name: 'sleep'
    pause:
      seconds: 10

  tasks:
  - name: 'include vars'
    include_vars: 'vars.yml'

  - name: 'create containers'
    proxmox:
      vmid: '{{ item.value.vmid | default([])}}'
      api_user: "{{ api_user }}"
      api_password: "{{ api_password }}"
      api_host: "{{ api_host }}"
      hostname: '{{ item.key }}'
      node: '{{ item.value.node }}'
      cores: '{{ item.value.cores | default(defaults.cores) }}'
      cpus: '{{ item.value.cpus | default(defaults.cpus) }}'
      memory: '{{ item.value.memory | default(defaults.memory.ct) }}'
      swap: '{{ item.value.swap | default([]) }}'
      disk: '{{ item.value.disk | default(defaults.disk.ct) }}'
      storage: '{{ item.value.storage | default(defaults.storage.lvm) }}'
      onboot: '{{ item.value.onboot | default(defaults.onboot) }}'
      pubkey: '{{ item.value.pubkey | default(defaults.pubkey) }}'
      searchdomain: '{{ item.value.searchdomain | default(defaults.searchdomain) }}'
      nameserver: '{{ item.value.nameserver | default(defaults.nameserver) }}'
      ostemplate: '{{ ostemplate }}'
      state: 'present'
    with_dict: "{{ cts }}"
    loop_control:
      pause: 5
    notify:
      - 'sleep'
    register: 'created_cts_pve'
    when: 'not item.value.cloudinit | default(false) | bool'

  - meta: 'flush_handlers'
    when: 'created_cts_pve.changed'

  - name: 'start ct deployment'
    proxmox:
      api_user: "{{ api_user }}"
      api_password: "{{ api_password }}"
      api_host: "{{ api_host }}"
      node: "{{ item.item.value.node }}"
      hostname: "{{ item.item.key }}"
      state: 'started'
    with_items: "{{ created_cts_pve.results }}"
    notify:
      - 'sleep'
    when: 'item.changed'

  - meta: 'flush_handlers'
    when: 'created_vms_pve.changed'

Press go

bash ansible-playbook -i infra main.yml

It spun up my container, and it’s live!