はじめに
Linuxで仮想マシンを構築できるKVM。最近はVMwareのあれこれで注目度も上がっている気がする。
そんなKVMにも、Ansibleのダイナミックインベントリ用プラグインが公開されている。
今回はそのプラグインを使ってKVMのVMをダイナミックインベントリで読み込み接続するまでをやる。
私がKVMのダイナミックインベントリを使えるようにするまでに経験したエラーとその対処方は最後に説明する。
VMの構築
KVMでのVM構築はXMLのテンプレートを用意すればどんな設定でも可能だと思う。今回はそこらへんが躓きポイントとならないようになるべく平易な構築を行いたい。
と言うことで今回はvirt-install
コマンドを使ってVMを構築する。
構築に使用したコマンドは以下。
virt-install --virt-type kvm --location /path/iso_file --os-type linux --os-variant rhel9.0 --ram 4086 --vcpus 4 --disk /path/kvm/images/ansible_target.qcow2,size=20 --name ansible_target --network bridge=br0 --hvm --noautoconsole --initrd-inject /path/rhel_kickstart.cfg --extra-args "inst.ks=file:/rhel_kickstart.cfg ksdevice=enp1s0 onboot=yes"
インストール作業が手間だったためkickstart
を使用しているが特別な設定は行っていない。
kickstartで使用したファイルも一応記載しておく。<クリックで展開>(適当にインストールしたRHELから引っ張ったものなので最適化されていないが)
# Generated by Anaconda 34.25.4.9 # Generated by pykickstart v3.32 #version=RHEL9 text %addon com_redhat_kdump --enable --reserve-mb='auto' %end # Keyboard layouts keyboard --xlayouts='us' # System language lang en_US.UTF-8 %packages @^server-product-environment %end # Run the Setup Agent on first boot firstboot --enable # Generated using Blivet version 3.6.0 ignoredisk --only-use=vda autopart # Partition clearing information clearpart --none --initlabel # System timezone timezone Asia/Tokyo --utc # Root password rootpw --iscrypted hoge user --groups=wheel --name=holtit --password=fuga --iscrypted --gecos="holtit" firewall --disabled selinux --disabled reboot
VM側の手順
VMが作成できたので必要な設定を行う。
まずはゲストエージェントを入れる。こいつを入れることで外部からコマンド叩いてゲストOSの情報を取得したりできるようになる。
qemu-guest-agentのインストール
エージェントのインストールを行う。
RHEL系の場合
dnf -y install qemu-guest-agent
Debian系の場合
apt -y install qemu-guest-agent
パッケージ名が同じなので分かりやすい。
エージェントの起動
qemu-guest-agent
はサービスとして動作するため起動する。
systemctl start qemu-guest-agent
無事起動できればOK。
systemctl status qemu-guest-agent ● qemu-guest-agent.service - QEMU Guest Agent Loaded: loaded (/usr/lib/systemd/system/qemu-guest-agent.service; enabled; preset: enabled) Active: active (running) since Tue 2024-11-05 21:56:02 JST; 18min ago Main PID: 4894 (qemu-ga) Tasks: 2 (limit: 23084) Memory: 3.3M CPU: 332ms CGroup: /system.slice/qemu-guest-agent.service
Ansible側の設定、準備
KVM側の設定が終わったのでようやくAnsibleの話。
community.libvirtのインストール
KVMのVMをダイナミックインベントリで扱うためにはcommunity.libvirt.libvirt
を使用する。
そのため環境にcommunity.libvirt
が入っていない場合はインストールする必要がある。
ansible-galaxy collection install community.libvirt
インストール完了or既にしてある場合はちゃんとインストールができているか確認する。
ansible-galaxy collection list | grep libvirt
community.libvirt 1.3.0
ちゃんとできてる。
ライブラリ等のインストール
正直全部を書くことは面倒難しいので私の環境で追加で入れたものだけ列挙する。
# Pythonライブラリ libvirt-python
# その他パッケージ libvirt-dev pkg-config
ダイナミックインベントリの作成
いよいよダイナミックインベントリを作成する。
と言っても内容はこれだけ。
--- plugin: community.libvirt.libvirt uri: 'qemu+ssh://holtit@kvm-server/system'
今回、Ansibleを実行するマシンとKVMを動かしているマシンは別なので、uri
では上記のような指定になっている。
では読み込めるか見てみよう。
インベントリの内容を確認するには以下のコマンドを実行。
ansible-inventory -i inventory.yml --list
出力が長すぎるので一部割愛する。
"ansible_target": { "ansible_connection": "community.libvirt.libvirt_qemu", "ansible_libvirt_uri": "qemu+ssh://holtit@home-server/system", "guest_info": { "os.id": "rhel", "os.name": "Red Hat Enterprise Linux", "os.pretty-name": "Red Hat Enterprise Linux 9.4 (Plow)", "os.version": "9.4 (Plow)", "os.version-id": "9.4", }, "info": { "cpuTime_ns": 37860000000, "maxMem_kb": 4184064, "memory_kb": 4184064, "nrVirtCpu": 4, "state": "running", "state_number": 1 }, "interface_addresses": { "enp1s0": { "addrs": [ { "addr": "192.168.50.34", "prefix": 24, "type": 0 },
ホスト名やIPアドレスなどが取得できていることが分かる。
あとはこれをインベントリとして使用するだけ。
ダイナミックインベントリを使用したAnsible接続
ansible -i inventory.yml ansible_target -m ping ansible_target | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3.9" }, "changed": false, "ping": "pong" }
はい成功。
スムーズにできたように書いたが苦戦しまくって2回ぐらい諦めた。
以下に私の環境で発生し、そして解決できたエラーを記載する。
躓いたエラー集
qemu-guest-agent
サービスが起動できないとき
現段階ではゲストOS側から一方的に接続を試みている段階。ホストOSと接続するための経路を用意してあげる必要がある。
具体的な手順としては以下のブロックをVMに追加する。
<channel type='unix'> <target type='virtio' name='org.qemu.guest_agent.0'/> <address type='virtio-serial' controller='0' bus='0' port='1'/> </channel>
IDは自身の環境に合わせてほしい。
上記の設定が終わったらVMを再起動する。
私の環境ではVM内から発行するreboot
コマンドではダメで、一度VMを完全に停止させる必要がありそう。
GUIからの確認で申し訳ないが、上記の設定がうまくいくとchannel欄が新たに追加される。
VMを起動すると以下の行が追加されるはず。
<target> type="virtio" name="org.qemu.guest_agent.0" state="connected"/>
connectedになってればよさげ。
再起動が終わったら再びqemu-guest-agent
を起動しよう。
systemctl start qemu-guest-agent systemctl status qemu-guest-agent * qemu-guest-agent.service - QEMU Guest Agent Loaded: loaded (/lib/systemd/system/qemu-guest-agent.service; static) Active: active (running) since Tue 2024-11-05 20:23:57 JST; 12min ago Main PID: 492 (qemu-ga) Tasks: 2 (limit: 2293) Memory: 10.6M CPU: 153ms CGroup: /system.slice/qemu-guest-agent.service `-492 /usr/sbin/qemu-ga
無事起動できた。
Ansibleで接続した時Domain does not have required capabilities
になるとき
ansible-inventory -i inventory.yml --list
ではVMの情報が表示できるのにいざansible -i inventory.yml ansible_target -m ping
などで接続すると失敗するケースがある。
エラー文は以下。
ansible -i kvm_inventory/inventory.yml ansible_target -m ping [WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details ansible_target | UNREACHABLE! => { "changed": false, "msg": "Domain does not have required capabilities", "unreachable": true }
解決法と言うかトラシューのやり方はターミナルに書いてある通り。
詳細な出力をさせてみる。(長いので抜粋)
ansible -i kvm_inventory/inventory.yml ansible_target -m ping -vvv
<ansible_target> REQUIRED CAPABILITIES MISSING: ['guest-exec', 'guest-exec-status', 'guest-file-close', 'guest-file-open', 'guest-file-read', 'guest-file-write']
重要なのはREQUIRED CAPABILITIES MISSING
ここ。
qemu-guest-agent
がサービスとして起動していてもすべての機能が有効になっているわけではない。
Ansibleで接続するためには上記のものが有効になっている必要があるようだ。
と言うことで有効化する。
※私が以後作業するのはRHEL9.4である。Debian系のやり方までは扱わない。
理由としては手元のDebian12はqemu-guest-agentをインストールしサービスを起動しただけでAnsible接続に必要なものがすべて有効化されていたためである。
以下のファイルを編集する。
/etc/sysconfig/qemu-ga
いろいろコメントで書かれているだろうが修正するのは1行だけ。
FILTER_RPC_ARGS
の行。
あとはこの行にREQUIRED CAPABILITIES MISSING
で不足していると言われたものを追記するだけ。
私の環境では長々しく以下のようになった。※これで1行
FILTER_RPC_ARGS="--allow-rpcs=guest-sync-delimited,guest-sync,guest-ping,guest-get-time,guest-set-time,guest-info,guest-shutdown,guest-fsfreeze-status,guest-fsfreeze-freeze,guest-fsfreeze-freeze-list,guest-fsfreeze-thaw,guest-fstrim,guest-suspend-disk,guest-suspend-ram,guest-suspend-hybrid,guest-network-get-interfaces,guest-get-vcpus,guest-set-vcpus,guest-get-disks,guest-get-fsinfo,guest-set-user-password,guest-get-memory-blocks,guest-set-memory-blocks,guest-get-memory-block-info,guest-get-host-name,guest-get-users,guest-get-timezone,guest-get-osinfo,guest-get-devices,guest-ssh-get-authorized-keys,guest-ssh-add-authorized-keys,guest-ssh-remove-authorized-keys,guest-get-diskstats,guest-get-cpustats,guest-exec,guest-exec-status,guest-file-close,guest-file-open,guest-file-read,guest-file-write"
あとはサービスを再起動する。
systemctl restart qemu-guest-agent
これで完了。Ansibleから疎通テストしてみる。
ansible -i kvm_inventory/inventory.yml ansible_target -m ping ansible_target | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3.9" }, "changed": false, "ping": "pong" }
成功!!
終わりに
今回はKVMのダイナミックインベントリを使ってみた。
KVMはそもそも構成要素が分かりづらく、そこにAnsibleやAnsibleのダイナミックインベントリが絡むと更に分からなくなった。
記事内で挙げたエラー2つは私がめちゃくちゃ悩んだものなので誰かの参考になれば幸いである。
これで自宅の仮想環境にKVMを選んだことを肯定する材料が増えた。 とても満足!!