Recently, I had to deploy a bunch of VMs to a vSphere cluster. Although there are many VMware solutions that can achieve this, I wanted to get my hands dirty with Ansible.

Lets begin by installing pyvmomi

root@ubuntu:~# apt install pip -y
root@ubuntu:~# apt-get update
root@ubuntu:~# pip install pyvmomi

Install the VMware vSphere Automation SDK for Python

root@ubuntu:~# pip install --upgrade git+https://github.com/vmware/vsphere-automation-sdk-python.git

Install ansible

root@ubuntu:~# sudo apt install software-properties-common
root@ubuntu:~# sudo apt install ansible

Create a new Ansible role

Ansible Roles let you automatically load related vars, files, tasks, handlers, and other Ansible artifacts based on a known file structure. After you group your content into roles, you can easily reuse them and share them with other users.

root@ubuntu:~/ansible# ansible-galaxy init automate-vm-deploy
- Role automate-vm-deploy was created successfully

Before we can define variables, create a VM template in vCenter Server that you will be using to deploy VMs from.

VM Template

Define variables in automate-vm-deploy/vars/main.yml

root@ubuntu:~/ansible/automate-vm# cat automate-vm-deploy/vars/main.yml 
---
##### vCenter #####
vcenter_hostname: "vc802.gs.labs"
vcenter_username: "administrator@vsphere.local"
vcenter_password: "SOMEPASS"
datacenter_name: "Sydney"
cluster_name: "dell-r630"
folder: "k3s"
template_name: "debian11"
virtual_machine_datastore: vsanDatastore
vm_username: root
vm_password: SOMEPASS
k3s_token: THISISAtoken12345!

Populate tasks in automate-vm-deploy/tasks/main.yml

root@ubuntu:~/ansible/automate-vm# cat automate-vm-deploy/tasks/main.yml 
- name: Deploying control plane vms from {{ template_name }}
  vmware_guest:
    hostname: "{{ vcenter_hostname }}"
    username: "{{ vcenter_username }}"
    password: "{{ vcenter_password }}"
    validate_certs: no
    datacenter: "{{ datacenter_name }}"
    state: poweredon
    folder:  "{{ folder }}"
    template: "{{ template_name }}"
    name: "k3s-control-{{ inventory_hostname }}"
    cluster: "{{ cluster_name }}"
    datastore: "{{ virtual_machine_datastore }}"
    wait_for_ip_address: yes
  delegate_to: localhost

- name: Deploy worker vms from {{ template_name }}
  vmware_guest:
    hostname: "{{ vcenter_hostname }}"
    username: "{{ vcenter_username }}"
    password: "{{ vcenter_password }}"
    validate_certs: no
    datacenter: "{{ datacenter_name }}"
    state: poweredon
    folder:  "{{ folder }}"
    template: "{{ template_name }}"
    name: "k3s-worker-{{ inventory_hostname }}"
    cluster: "{{ cluster_name }}"
    datastore: "{{ virtual_machine_datastore }}"
    wait_for_ip_address: yes
  delegate_to: localhost

- name: Set Hostname and update DNS for control plane vms
  vmware_vm_shell:
    hostname: "{{ vcenter_hostname }}"
    username: "{{ vcenter_username }}"
    password: "{{ vcenter_password }}"
    validate_certs: no
    datacenter: "{{ datacenter_name }}"
    folder: "{{ folder }}"
    vm_id: "k3s-control-{{ inventory_hostname }}"
    vm_username: "{{ vm_username }}"
    vm_password: "{{ vm_password }}"
    vm_shell: /usr/bin/hostname
    vm_shell_args: "k3s-control-{{ inventory_hostname }} && dhclient -r && dhclient -4"
  delegate_to: localhost

- name: Set Hostname and update DNS for worker vms
  vmware_vm_shell:
    hostname: "{{ vcenter_hostname }}"
    username: "{{ vcenter_username }}"
    password: "{{ vcenter_password }}"
    validate_certs: no
    datacenter: "{{ datacenter_name }}"
    folder: "{{ folder }}"
    vm_id: "k3s-worker-{{ inventory_hostname }}"
    vm_username: "{{ vm_username }}"
    vm_password: "{{ vm_password }}"
    vm_shell: /usr/bin/hostname
    vm_shell_args: "k3s-worker-{{ inventory_hostname }} && dhclient -r && dhclient -4"
  delegate_to: localhost

- name: Install K3S Control Plane
  vmware_vm_shell:
    hostname: "{{ vcenter_hostname }}"
    username: "{{ vcenter_username }}"
    password: "{{ vcenter_password }}"
    validate_certs: no
    datacenter: "{{ datacenter_name }}"
    folder: "{{ folder }}"
    vm_id: "k3s-control-{{ inventory_hostname }}"
    vm_username: "{{ vm_username }}"
    vm_password: "{{ vm_password }}"
    vm_shell: /bin/curl
    vm_shell_args: -sfL https://get.k3s.io | K3S_TOKEN={{ k3s_token }} sh -s - server --cluster-init --node-name k3s-control-{{ inventory_hostname }}.gs.labs
    wait_for_process: true
  delegate_to: localhost

- name: Install K3S Worker Node
  vmware_vm_shell:
    hostname: "{{ vcenter_hostname }}"
    username: "{{ vcenter_username }}"
    password: "{{ vcenter_password }}"
    validate_certs: no
    datacenter: "{{ datacenter_name }}"
    folder: "{{ folder }}"
    vm_id: "k3s-worker-{{ inventory_hostname }}"
    vm_username: "{{ vm_username }}"
    vm_password: "{{ vm_password }}"
    vm_shell: /bin/curl
    vm_shell_args: -sfL https://get.k3s.io | K3S_TOKEN={{ k3s_token }} sh -s - agent --server https://k3s-control-{{ inventory_hostname }}.gs.labs:6443 --node-name k3s-worker-{{ inventory_hostname }}.gs.labs
    wait_for_process: true
  delegate_to: localhost

Create a file with the list of VM Names

root@ubuntu:~/ansible/automate-vm# cat vm-list
student1
student2
student3
student4

Create the main ansible playbook

root@ubuntu:~/ansible/automate-vm# cat main-playbook.yml 
---
- hosts: all
  gather_facts: no
  roles:
  - automate-vm-deploy

Run the Ansible playbook

PLAY [all] **********************************************************************************************
TASK [automate-vm-deploy : Deploy control plane vms from debian11] **********************************************************************************************changed: [student1]
changed: [student2]
changed: [student3]
changed: [student4]

TASK [automate-vm-deploy : Deploy worker vms from debian11] **********************************************************************************************
changed: [student1]
changed: [student2]
changed: [student3]
changed: [student4]

TASK [automate-vm-deploy : Set Hostname and update DNS for control plane vms]**********************************************************************************************
changed: [student1]
changed: [student2]
changed: [student3]
changed: [student4]

TASK [automate-vm-deploy : Set Hostname and update DNS for worker vms] **********************************************************************************************
changed: [student1]
changed: [student2]
changed: [student3]
changed: [student4]

TASK [automate-vm-deploy : Install K3S Control Plane] **********************************************************************************************
changed: [student1]
changed: [student2]
changed: [student3]
changed: [student4]

TASK [automate-vm-deploy : Install K3S Worker Node]**********************************************************************************************
changed: [student1]
changed: [student2]
changed: [student3]
changed: [student4]

PLAY RECAP **********************************************************************************************student1                   : ok=6    changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
student2                   : ok=6    changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
student3                   : ok=6    changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
student4                   : ok=6    changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0