AnsibleのCommunity.GeneralコレクションにはProxmoxVEを操作するためにモジュールがいくつか含まれており、これを使ってVMを作ったり、作成済みテンプレートからクローンしたりできる。
特にクラウドイメージを使ったVMのクローンにおける追加パッケージインストールなどのPVEがUIでサポートしてないカスタムcloud-Initの機能は、Ansibleでvendor設定ファイルを作成・配置・設定して全自動で処理できるので、よく使う機能をパラメタ設定できるようにしておけば、VM作成をもっと効率的にできるようになる。(例えばAWXやAAPのUIを使う、とかね)
前置きはこれくらいにして、主要なVM操作のプレイブック例についてまとめ
環境
- PVEバージョン: 8.3.3
- Ansible Core 2.18.2 (Ansible 11.2.0)
- Python
- proxmoxer 2.2.0
- requests 2.32.3
- Collection
- community.general 10.3.0
AnsibleはPVEとは別ホストで実行。
準備
Proxmox操作のモジュールはproxmoxerとrequestsに依存するのでAnsible実行ホストでpipで入れておく。
接続方法
Playのターゲットはlocalhostにして、各タスクでモジュールのパラメタのapi_hostやapi_userで接続情報を設定するのがシンプル。
この場合実行環境がlocalhostになるので、必要な依存モジュール(proxmoxerなど)はローカルに入れれば良い。(リモートで実行する場合は、リモートに依存モジュールが必要)
api_hostなどの接続・認証情報については、10.3.0時点のドキュメントには記載がないが、PROXMOX_PASSWORDとPROXMOX_PORT以外にもPROXMOX_HOSTとPROXMOX_USERも使用できるので、基本的にはプレイブックでなく環境変数でセットした方が機密情報をコードに書かずに済むので個人的にはお勧め。
api_host=dict(type='str', required=True, fallback=(env_fallback, ['PROXMOX_HOST']) ), api_port=dict(type='int', fallback=(env_fallback, ['PROXMOX_PORT']) ), api_user=dict(type='str', required=True, fallback=(env_fallback, ['PROXMOX_USER']) ), api_password=dict(type='str', no_log=True, fallback=(env_fallback, ['PROXMOX_PASSWORD']) ), # https://github.com/ansible-collections/community.general/blob/10.3.0/plugins/module_utils/proxmox.py#L27-L53
なお、PVEのユーザーアカウント(初期構築時の管理者ユーザーであればroot)の場合、ここで指定する文字列はRealmを加えてroot@pamになるので注意。
作成関連
VMの作成
素のVMを作る機会はもうあまりないけど、まずは基本。
- name: create VM community.general.proxmox_kvm: name: "{{ vm_name }}" vmid: "{{ vm_id }}" node: "{{ pve_node }}" cpu: x86-64-v2-AES sockets: 2 cores: 2 memory: 8192 net: net0: 'virtio,bridge=vmbr0' net1: 'virtio,bridge=vmbr1,firewall=1' net2: 'e1000,bridge=vmbr2' sata: sata0: 'local-lvm:10' ide: ide2: 'media=cdrom,pecorino-dev:iso/ubuntu-22.04.1-live-server-amd64.iso'
個人的によく使うと思う基本的なパラメタは以下の通り。
| パラメタ | 意味 |
|---|---|
| name | VM名 |
| vmid | VMのID |
| node | (クラスタ組んでるときの)VMを作るPVEノード名 |
| cpu | CPU種別 |
| sockets | CPUソケット数 |
| cores | CPUコア数 |
| memory | メモリサイズ |
- NIC(
net)について - ストレージ(
sata)について- 1つ目は
sata0、2つ目はsata1でサブキーを作成 - 値はコロン区切りで、ストレージ名、ディスクサイズ(GB)
- 前述の記述例は、PVE構築時にデフォルトで作成されるはずの
local-lvmに10GBのディスクをセット
- 1つ目は
- CD/DVD(OSインストール用isoファイルセット)について
テンプレートからVMのクローンとVM設定
本題。
クローン
使うモジュールはVM作成と同じくcommunity.general.proxmox_kvmモジュール。
ただしVM作成と異なり、VMスペック系のパラメタはクローン時に指定していても無効になるため、クローン後に別途更新する必要がある。
まずはVMのクローンは以下。
- name: create VM from template community.general.proxmox_kvm: clone: "{{ template }}" name: "{{ vm_name }}" newid: "{{ vm_id }}" node: "{{ pve_node }}" full: false
| パラメタ | 意味 |
|---|---|
| clone | クローン元のテンプレート/VM名 |
| name | クローン先のVM名 |
| newid | クローン先のVMのID |
| node | (クラスタ組んでるときの)VMを作るPVEノード名 |
クローンできたら、次はVMの設定更新。
ただしNIC等の更新は現バージョンだとupdate_unsafe: trueをセットしないと受け付けない仕様になっており、名前的にちょっと不安感あるため、NICとストレージは別モジュールを使って別途実行する。
NICの更新
まずはNICの更新。
例としてNIC0とNIC1をセット。
使うのはcommunity.general.proxmox_nicモジュール。
- name: set NIC0 community.general.proxmox_nic: vmid: "{{ vm_id }}" model: e1000 interface: net0 bridge: vmbr0 - name: set NIC1 community.general.proxmox_nic: vmid: "{{ vm_id }}" interface: net1 bridge: vmbr1
modelを省略した場合はデフォルトのvirtioが使用される。
テンプレートの方にNICを定義してあり、クローンした時点で変更が不要の場合は、これらのタスクは定義しなくても良い。
また、NIC0のみテンプレートに定義があり、NIC1のみ追加したい場合は、NIC1の定義のみ記述すればOK
ストレージサイズの設定
次にストレージサイズの設定。
使うのはcommunity.general.proxmox_diskモジュール。
- name: update disk size community.general.proxmox_disk: vmid: "{{ vm_id }}" disk: scsi0 size: 30G state: resized
GUIからだと「増分」の指定になるが、Ansibleからだと指定サイズへ固定設定ができる。
この例だと、「30GBのディスク」としてセットされる。
ただし使用として増加しかできずに縮小はできないため、クローンした時点のディスクサイズより小さいサイズは指定できない(エラーになる)ので注意。
GUIと同様に「増分」を指定したい場合は、例えば+5GBであれば+5と記述すればOK (その場合再実行の際に5GBずつ増加するのでやはり注意)
VMとcloud-Init設定
使うのはVM作成やクローンと同じくcommunity.general.proxmox_kvmモジュール。
ただしパラメタにupdateを指定する。
- name: update VM configuration community.general.proxmox_kvm: update: true vmid: "{{ vm_id }}" node: "{{ pve_node }}" cpu: x86-64-v4 sockets: 2 cores: 4 memory: 8192 tags: - dev - infra ## 以降はcloud-init設定 ciuser: cloud-user cipassword: curry_tabetai sshkeys: 'ssh-...... ............' ipconfig: ipconfig0: 'ip=192.168.0.87/24,gw=192.168.0.1' ipconfig1: 'ip=172.16.0.87/24' # ipconfig1: ip=dhcp nameservers: - 192.168.0.4 - 8.8.8.8 cicustom: "vendor=pecorino-dev:snippets/{{ vm_id }}.yaml"
| パラメタ | 意味 |
|---|---|
| update | VM作成でなく更新時はtrue指定 |
| vmid | 更新対象VMのID |
| node | (クラスタ組んでるときの)VMを作るPVEノード名 |
| cpu | CPU種別 |
| sockets | CPUソケット数 |
| cores | CPUコア数 |
| memory | メモリサイズ |
| tags | タグ(list) |
cloud-initに関するパラメタは以下。
内容は基本的にGUIで指定するときと同じ値を指定するので特に問題ないと思う。(雑)
| パラメタ | 意味 |
|---|---|
| ciuser | ユーザー名 |
| cipassword | パスワード |
| sshkeys | SSH公開鍵文字列 |
| ipconfig | IPアドレス設定 |
| nameservers | DNS設定 |
| cicustom | カスタムvendor設定ファイル |
cicustomについては[Proxmox VE] Cloud-Initのvendorデータを使ってサブスクリプション済みRHELのVMをサクッと作成するでも触れたが、vendor=ストレージ名:snippets/vendoer設定ファイル名の書式。
verndor設定ファイルをテンプレートからのVMクローンの一連の流れに組み込むのであれば、PVEサーバー(あるいは別のNFSサーバーとか)で使えるストレージに対してLinuxサーバー自動化で普段使っているcopyモジュールで事前にコピーしてやればOK
以下はAnsible実行環境の~/.ssh/configに接続情報が定義されてる前提で、pve01でアクセスできるPVEサーバーへ定義ファイルを作成する例。
サーバー構成的にはスニペット対応のNFSサーバーの領域を/mnt/pve/pecorino-devにマウントしており、タスク定義はdelegate_toを使用し、これまでの他タスクはローカルホスト実行しながら、このタスク単体はpve01で処理するように定義している。
- name: create snippets file ansible.builtin.copy: content: | #cloud-config packages: - qemu-guest-agent - podman dest: "/mnt/pve/pecorino-dev/snippets/{{ vm_id }}.yaml" delegate_to: pve01
これを応用すれば、PVEのGUIで使えるcloud-init設定以外のカスタマイズもAnsibleでパラメタ化してやれば、効率的にVMを生やせる。
ちなみに、NIC設定をproxmox_kvmへ組み込むなら以下の通り。
net: net0: 'virtio,bridge=vmbr0' net1: 'virtio,bridge=vmbr1' update_unsafe: true
その他
VM IDの取得
VM情報参照関連はcommunity.general.proxmox_vm_infoモジュールを使う。
全VMのID一覧を列挙するには以下。
(IDでなく全情報を出力したければフィルタしなければOK)
- name: list VM community.general.proxmox_vm_info: node: "{{ pve_node }}" register: vm_list - debug: msg: "{{ vm_list.proxmox_vms | map(attribute='vmid') }}"
指定VM(のID)の情報を得るには以下。
- name: vm info community.general.proxmox_vm_info: node: "{{ pve_node }}" vmid: "{{ vmid }}" # network: true register: vm_info - debug: var: vm_info
NICの情報は現状得ることができないが、network: trueを指定かつ、VMが起動しておりqemu-guest-agentが動作していれば、NICというよりはIPアドレス情報が得られる。
GUIのサマリ画面のIP情報とほぼ同等。
電源管理
シャットダウンする
- name: stop instance community.general.proxmox_kvm: vmid: "{{ vmid }}" state: stopped
ブートする
- name: start instance community.general.proxmox_kvm: vmid: "{{ vmid }}" state: started
state: restartedにするとリブートするが、停止状態から起動はしない。(running状態からの場合にリブートする)
VMの削除
- name: remove instance community.general.proxmox_kvm: vmid: "{{ vmid }}" state: absent
参考
モジュールの使い方についてはAnsibleのドキュメントに加えて、内部で使用しているproxmoxerのドキュメントも参照するのも良い。