Ansible: KVMの仮想マシンを削除する

はじめに

検証環境としてサクッとVMを作ったり壊したりするのに便利なKVM、よく使っています。今回はKVM上で動作する仮想マシンを削除するためのPlaybookを作ってみます。手動で操作する場合は virsh を叩いたりしています。ただ、削除するにしても複数のサブコマンド実行が必要だったり、ホストマシンからの名前解決を/etc/hosts で簡易的に管理している場合はそちらのエントリも削除したりといった具合で手間がかかるため、そうした手間を省くのが今回のモチベーションです。

削除操作を自動化していますので試す場合はご注意ください&自己責任でお願いします。

準備

VMの操作には community.libvirt.virt モジュールを使います。

community.libvirt.virt module – Manages virtual machines supported by libvirt — Ansible Documentation

Playbookと同じディレクトリで requirements.yml を作成し、依存する collection を定義します。

requirements.yml

---
collections:
  - community.libvirt

collection をインストールします。

ansible-galaxy collection install -r requirements.yml -p collections

実装

今回作成したPlaybookがこちらです。

---
- name: Delete vms
  hosts: localhost
  gather_facts: false
  vars:
    vms:
      - hostname: 'centos8'
  tasks:
    - name: Get available vms
      community.libvirt.virt:
        command: list_vms
      register: existing_vms

    - name: Check if target vm name is existing
      ansible.builtin.assert:
        that: item.hostname in existing_vms['list_vms']
        fail_msg: "target vm '{{ item.hostname }}' is not found on kvm"
      loop: "{{ vms }}"

    - name: Destroy vms
      community.libvirt.virt:
        command: destroy
        name: "{{ item.hostname }}"
      loop: "{{ vms }}"
      ignore_errors: true

    - name: Undefine vms
      community.libvirt.virt:
        command: undefine
        name: "{{ item.hostname }}"
      loop: "{{ vms }}"

    - name: Delete qcow2 image
      ansible.builtin.file:
        path: "/var/lib/libvirt/images/{{ item.hostname }}.qcow2"
        state: absent
      loop: "{{ vms }}"

    - name: Delete hosts entry
      ansible.builtin.lineinfile:
        path: /etc/hosts
        regex: ".*{{ item.hostname }}.*"
        state: absent
      loop: "{{ vms }}"

複数のVMをまとめて削除できるよう、ドメイン名のリストを変数として定義し、各タスクで loop させています。安直に1つのPlaybookにまとめましたが、この処理をまるっとタスクファイルに切り出して include_tasks で呼び出すようにすれば、loopの定義が1箇所で済むのでもう少しスマートになりそうです。

削除の流れとしては、指定したドメインVMが存在するかを確認した上で、問題なければ destory、undefineを実行してVMを削除します。仮想マシンが停止している状態だと destory する際にエラーを返すため、 ignore_errors: true を対処しています。

また、前述の通り今回はホストマシンから仮想マシンに対する名前解決はホストマシン上の /etc/hosts で管理しているので、登録されたエントリも併せて削除しています。

実行結果

仮想マシンは以下のように停止した状態で削除してみます。

sudo virsh list --all
 Id   Name         State
-----------------------------
 -    centos8      shut off

いざ実行。

PLAY [Delete vms] ****************************************************************************************************************************************************************************

TASK [Get available vms] *********************************************************************************************************************************************************************
ok: [localhost]

TASK [Check if target vm name is existing] ***************************************************************************************************************************************************
ok: [localhost] => (item={'hostname': 'centos8'}) => {
    "ansible_loop_var": "item",
    "changed": false,
    "item": {
        "hostname": "centos8"
    },
    "msg": "All assertions passed"
}

TASK [Destroy vms] ***************************************************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: libvirt.libvirtError: Requested operation is not valid: domain is not running
failed: [localhost] (item={'hostname': 'centos8'}) => {"ansible_loop_var": "item", "changed": false, "item": {"hostname": "centos8"}, "msg": "Requested operation is not valid: domain is not running"}
...ignoring

TASK [Undefine vms] **************************************************************************************************************************************************************************
ok: [localhost] => (item={'hostname': 'centos8'})

TASK [Delete qcow2 image] ********************************************************************************************************************************************************************
changed: [localhost] => (item={'hostname': 'centos8'})

TASK [Delete hosts entry] ********************************************************************************************************************************************************************
changed: [localhost] => (item={'hostname': 'centos8'})

PLAY RECAP ***********************************************************************************************************************************************************************************
localhost                  : ok=6    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1

無事削除できました。

まとめ

KVM上で動作するVMを削除するPlaybookについて記載しました。