Wenn man mit Ansible VMware VMs automatisch aktualisiert wäre es nützlich, wenn man zuvor auch automatisch einen offline Snapshot (im ausgeschalteten Zustand) machen könnte. Die Erstellung des Snapshots im ausgeschalteten Zustand stellt die Konsistenz sicher. Auch wenn man einen Snapshot mit Memory Dump online machen könnte, bevorzuge ich immer die offline Methode.
Mittels Ansible lässt sich der ganze Prozess komplett automatisieren.
Der Prozess im Ansible play sieht folgendermassen aus:
- Ansible fährt den Host herunter und wartet bis er im VMware OFF ist
- Ein VM Snapshot wird erstellt
- Der Host wird wieder hochgefahren
- Warten bis der Service wieder online ist
- Update Prozess starten
Zunächst wird ein neuer Task ansible/tasks/vmware-offline-snapshot.yml erstellt, welcher dann im Playbook geladen werden kann:
---
- name: Make sure all the required variables are set
ansible.builtin.assert:
that:
- vcenter_hostname is defined
- vcenter_username is defined
- vcenter_password is defined
- name: Stop application services
ansible.builtin.systemd:
name: "{{ services_to_stop }}"
state: stopped
loop: "{{ services_to_stop | default([]) }}"
- name: Trigger guest shutdown via vCenter
vmware.vmware.vm_powerstate:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
datacenter: "{{ vcenter_datacenter }}"
name: "{{ ansible_facts['hostname'] }}"
state: shutdown-guest
validate_certs: false
register: __vm_shutdown
delegate_to: localhost
become: false
- name: Wait for VM to be powered off
community.vmware.vmware_guest_info:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
name: "{{ ansible_facts['hostname'] }}"
validate_certs: false
delegate_to: localhost
become: false
register: vm_info
retries: 30
delay: 10
until: (vm_info.instance.hw_power_status | default('')) == "poweredOff"
when: ( __vm_shutdown.changed | default(false) ) and not ansible_check_mode
- name: Get current snapshots
community.vmware.vmware_guest_snapshot_info:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
datacenter: "{{ vcenter_datacenter }}"
folder: "/{{ vcenter_datacenter }}/vm"
name: "{{ ansible_facts['hostname'] }}"
validate_certs: false
delegate_to: localhost
become: false
register: snapshot_info
- name: Remove existing snapshot if overwrite is enabled
vmware.vmware.vm_snapshot:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
datacenter: "{{ vcenter_datacenter }}"
folder: "/{{ vcenter_datacenter }}/vm"
name: "{{ ansible_facts['hostname'] }}"
state: absent
snapshot_name: "{{ vcenter_snapshot_name }}"
validate_certs: false
delegate_to: localhost
become: false
when:
- vcenter_overwrite_snapshot | default(false) | bool
- vcenter_snapshot_name in (snapshot_info.guest_snapshots.snapshots | default([]) | map(attribute='name') | list)
- name: Create snapshot of stopped VM
vmware.vmware.vm_snapshot:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
datacenter: "{{ vcenter_datacenter }}"
folder: "/{{ vcenter_datacenter }}/vm"
name: "{{ ansible_facts['hostname'] }}"
state: present
snapshot_name: "{{ vcenter_snapshot_name }}"
description: "{{ vcenter_snapshot_description }}"
validate_certs: false
delegate_to: localhost
become: false
register: snapshot_result
- name: Power on VM
vmware.vmware.vm_powerstate:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
datacenter: "{{ vcenter_datacenter }}"
name: "{{ ansible_facts['hostname'] }}"
state: powered-on
validate_certs: false
delegate_to: localhost
become: false
register: __vm_poweron
# Optional
- name: Wait until Website answers after the update
ansible.builtin.uri:
url: "{{ website_url }}"
method: GET
follow_location: true
status_code: 200
validate_certs: false
use_proxy: false
delegate_to: localhost
become: false
register: __http_postcheck
retries: 30
delay: 10
until: (__http_postcheck.content | default('')) is search('Willkomen', ignorecase=true)
changed_when: false
when: ( __vm_poweron.changed | default(false) ) and not ansible_check_mode
In ansible/group_vars/all/vmware.yml kommt nun die Konfiguration:
---
vcenter_hostname: "vcenter.example.com"
vcenter_username: "ansible@vsphere.local"
vcenter_datacenter: "MYDC"
vcenter_snapshot_name: "ansible-before-updates"
vcenter_snapshot_description: "Before automatic update with Ansible"
vcenter_overwrite_snapshot: true
Die VMware vCenter Zugangsdaten werden natürlich im ansible-vault abgelegt:
ansible-vault create ansible/group_vars/all/vmware.secrets.yml
vcenter_password: "secret"
Nun noch das Playbook dazu machen:
- name: Set downtime and make snapshots prior to GitLab update
hosts: gitlab
pre_tasks:
- name: Determine whether packages would get updated
ansible.builtin.package:
name: '*'
state: latest
register __update_packages
check_mode: false
- name: Make offline snapshots when update would happen
when: __update_packages.changed | default(false) | bool
block:
- import_tasks: tasks/vmware-offline-snapshot.yml
tasks:
- name: Updated all packages
ansible.builtin.package:
name: '*'
state: latest