はじめに
Bergenholm というネットワークインストールサーバをご存知だろうか?
数年前、私が iPXE の豊富な機能を最大限活かしたネットワークインストールサーバを作りたくて、Python の Web マイクロフレームワーク Flask をベースに作ったものである。
元々、Ansible のような構成管理ツールと連携して動作する事を想定して作ったものなので、REST API があるだけ。同 API を叩く専用のクライアントツール はあるが、WebUI 的な物は一切ない。
その割には、これまで Bergenholm のホスト/グループを操作する為の Ansible モジュールが無かったので、今回作ってみた。こちらからダウンロードできる。
試してみる
手始めに、Bergenholm サーバ上で上記のリポジトリをダウンロードする。
~$ git clone https://github.com/yosshy/ansible-bergenholm.git
~$ cd ansible-bergenholm
中には bergenholm_host, bergenholm_group モジュールに加えて、サンプルの Ansible Playbook (create.yml, delete.yml) やインベントリ (hosts.ini) が含まれている。
~/ansible-bergenholm$ ls -RF
.:
ansible.cfg create.yml delete.yml group_vars/ hosts.ini host_vars/ library/ LICENSE README.md
./group_vars:
sample
./host_vars:
ansibletest1 ansibletest2 ansibletest3
./library:
bergenholm_group.py bergenholm_host.py
hosts.ini はこの通り。
[sample:children]
targets
[targets]
ansibletest1
ansibletest2
ansibletest3
git リポジトリには含まれていない開発用のインベントリとグループで区別する為に sample グループを定義しているが、その必要が無ければ targets グループだけで良い。
CentOS 7 VM を自動構築する
次に、create.yml を見てみよう。
- name: CentOS 7 VM を用意する
hosts: targets
gather_facts: false
tasks:
- name: ESXi 上に VM を作成する
local_action:
module: vsphere_guest
vcenter_hostname: "{{ esxi_host }}"
username: "{{ esxi_user }}"
password: "{{ esxi_pass }}"
guest: "{{ vm_name }}"
state: powered_on
validate_certs: false
vm_extra_config:
vcpu.hotadd: yes
mem.hotadd: yes
vm_disk:
disk1:
size_gb: 20
type: thin
datastore: "{{ vm_datastore }}"
folder: disk1.vmdk
vm_nic:
nic1:
type: vmxnet3
network: bergenholm
network_type: standard
vm_hardware:
memory_mb: 2048
num_cpus: 2
osid: centos64Guest
scsi: paravirtual
esxi:
datacenter: ha-datacenter
hostname: eval
- name: ESXi 上の VM の情報を取得する
local_action:
module: vsphere_guest
vcenter_hostname: "{{ esxi_host }}"
username: "{{ esxi_user }}"
password: "{{ esxi_pass }}"
guest: "{{ vm_name }}"
vmware_guest_facts: true
validate_certs: false
esxi:
datacenter: ha-datacenter
hostname: eval
register: newvm
- name: Bergenholm 上に新しい VM の設定を登録する
local_action:
module: bergenholm_host
uuid: "{{ newvm.ansible_facts.hw_product_uuid }}"
params:
groups:
- centos7
- centos.amd64
hostname: "{{ vm_name }}"
ipaddr: "{{ vm_ipaddr }}"
netif: ens192
state: present
notify:
- VM を再起動して OS インストールを開始する
handlers:
- name: VM を再起動して OS インストールを開始する
local_action:
module: vsphere_guest
vcenter_hostname: "{{ esxi_host }}"
username: "{{ esxi_user }}"
password: "{{ esxi_pass }}"
guest: "{{ vm_name }}"
state: restarted
validate_certs: false
- name: OS インストール後の確認を行う
hosts: targets
gather_facts: false
tasks:
- name: OS インストール完了待ち
wait_for_connection:
sleep: 10
timeout: 3600
- name: Facts を取得する
setup:
- name: ディストリビューション情報を表示する
debug:
msg: "{{ ansible_distribution }} {{ ansible_distribution_version }} ({{ansible_distribution_release}})"
上記は少々長くてアレだが、name: だけを抽出するとこうなる。
- name: CentOS 7 VM を用意する
- name: ESXi 上に VM を作成する
- name: ESXi 上の VM の情報を取得する
- name: Bergenholm 上に新しい VM の設定を登録する
- name: VM を再起動して OS インストールを開始する
- name: OS インストール後の確認を行う
- name: OS インストール完了待ち
- name: Facts を取得する
- name: ディストリビューション情報を表示する
何とも簡単。説明はほとんど不要だろう。vsphere_guest モジュールについてはこちらの記事を参照されたし。
肝心の bergenholm_host モジュールの部分だけ見てみよう。
- name: Bergenholm 上に新しい VM の設定を登録する
local_action:
module: bergenholm_host
uuid: "{{ newvm.ansible_facts.hw_product_uuid }}"
params:
groups:
- centos7
- centos.amd64
hostname: "{{ vm_name }}"
ipaddr: "{{ vm_ipaddr }}"
netif: ens192
state: present
今回、Bergenholm サーバ上で ansible-playbook を実行する前提があったので local_action としているが、別のホストの場合は以下のようになる。
- name: Bergenholm 上に新しい VM の設定を登録する
bergenholm_host:
uuid: "{{ newvm.ansible_facts.hw_product_uuid }}"
params:
groups:
- centos7
- centos.amd64
hostname: "{{ vm_name }}"
ipaddr: "{{ vm_ipaddr }}"
netif: ens192
state: present
delegate_to: bergenholmserver.localdomain
各パラメータの説明は以下の通り:
- uuid: インストール先サーバの System UUID。物理マシンなら BIOS、各種 VM であれば設定ファイル等で定義されている。
- state: よくある present, absent の他に、OS インストールが完了した状態 (installed)、OS インストールが未完の状態 (uninstalled) の4つの値を指定できる。
- params: ホスト(ここでは VM)単位に設定すべきパラメータの一覧。Bergenholm では基本的に JSON でパラメータを記述するが、本モジュールでは YAML で良い。
- url: Bergenholm サーバの REST API の URL。いずれにせよ今はまだない VM の為のコマンド実行であるので、local_action か delegate_to を使用する必要がある。
また、Playbook 開始時点でアクセス不可なホストを含むインベントリを使用する場合、Playbook の gather_facts は false にしておく必要がある。ハマりどころなので注意。
では、Let's Play.
~/ansible-bergenholm$ time ansible-playbook -i hosts.ini create.yml
PLAY [CentOS 7 VM を用意する] ********************************************************************************************************************
TASK [ESXi 上に VM を作成する] *********************************************************************************************************************
changed: [ansibletest1 -> localhost]
changed: [ansibletest2 -> localhost]
changed: [ansibletest3 -> localhost]
TASK [ESXi 上の VM の情報を取得する] ******************************************************************************************************************
ok: [ansibletest3 -> localhost]
ok: [ansibletest1 -> localhost]
ok: [ansibletest2 -> localhost]
TASK [Bergenholm 上に新しい VM の設定を登録する] *********************************************************************************************************
changed: [ansibletest1 -> localhost]
changed: [ansibletest2 -> localhost]
changed: [ansibletest3 -> localhost]
RUNNING HANDLER [VM を再起動して OS インストールを開始する] **************************************************************************************************
changed: [ansibletest1 -> localhost]
changed: [ansibletest2 -> localhost]
changed: [ansibletest3 -> localhost]
PLAY [OS インストール後の確認を行う] *********************************************************************************************************************
TASK [OS インストール完了待ち] ************************************************************************************************************************
ok: [ansibletest3]
ok: [ansibletest1]
ok: [ansibletest2]
TASK [Facts を取得する] **************************************************************************************************************************
ok: [ansibletest2]
ok: [ansibletest3]
ok: [ansibletest1]
TASK [ディストリビューション情報を表示する] *******************************************************************************************************************
ok: [ansibletest1] => {
"msg": "CentOS 7.4.1708 (Core)"
}
ok: [ansibletest2] => {
"msg": "CentOS 7.4.1708 (Core)"
}
ok: [ansibletest3] => {
"msg": "CentOS 7.4.1708 (Core)"
}
PLAY RECAP **********************************************************************************************************************************
ansibletest1 : ok=7 changed=3 unreachable=0 failed=0
ansibletest2 : ok=7 changed=3 unreachable=0 failed=0
ansibletest3 : ok=7 changed=3 unreachable=0 failed=0
real 22m20.011s
user 1m20.872s
sys 0m14.432s
Wonderful!!!!
インベントリで定義された VM 3つが作成され、CentOS 7.4.1708 がインストールされた事がわかる。
では、同じコマンドを再度実行してみよう。Let's play.
~/ansible-bergenholm$ time ansible-playbook -i hosts.ini create.yml
PLAY [CentOS 7 VM を用意する] ********************************************************************************************************************
TASK [ESXi 上に VM を作成する] *********************************************************************************************************************
ok: [ansibletest3 -> localhost]
ok: [ansibletest1 -> localhost]
ok: [ansibletest2 -> localhost]
TASK [ESXi 上の VM の情報を取得する] ******************************************************************************************************************
ok: [ansibletest3 -> localhost]
ok: [ansibletest2 -> localhost]
ok: [ansibletest1 -> localhost]
TASK [Bergenholm 上に新しい VM の設定を登録する] *********************************************************************************************************
ok: [ansibletest2 -> localhost]
ok: [ansibletest3 -> localhost]
ok: [ansibletest1 -> localhost]
PLAY [OS インストール後の確認を行う] *********************************************************************************************************************
TASK [OS インストール完了待ち] ************************************************************************************************************************
ok: [ansibletest2]
ok: [ansibletest3]
ok: [ansibletest1]
TASK [Facts を取得する] **************************************************************************************************************************
ok: [ansibletest2]
ok: [ansibletest3]
ok: [ansibletest1]
TASK [ディストリビューション情報を表示する] *******************************************************************************************************************
ok: [ansibletest1] => {
"msg": "CentOS 7.4.1708 (Core)"
}
ok: [ansibletest2] => {
"msg": "CentOS 7.4.1708 (Core)"
}
ok: [ansibletest3] => {
"msg": "CentOS 7.4.1708 (Core)"
}
PLAY RECAP **********************************************************************************************************************************
ansibletest1 : ok=6 changed=0 unreachable=0 failed=0
ansibletest2 : ok=6 changed=0 unreachable=0 failed=0
ansibletest3 : ok=6 changed=0 unreachable=0 failed=0
real 0m28.405s
user 0m9.816s
sys 0m1.384s
Cool!!!!
bergenholm_host (と bergenholm_group) モジュールは冪等性を持っているので、現状のリソース登録を調べて、必要が無ければ何もしない。Ansible モジュールたる者、冪等性ぐらい備えていて当然だ。
VM を自動削除する
では、作ったばかりの VM 群を削除しよう。delete.yml を見てみる。
- name: VM を削除する
hosts: targets
gather_facts: false
tasks:
- name: ESXi 上の VM 情報を取得する
local_action:
module: vsphere_guest
vcenter_hostname: "{{ esxi_host }}"
username: "{{ esxi_user }}"
password: "{{ esxi_pass }}"
guest: "{{ vm_name }}"
vmware_guest_facts: true
validate_certs: false
esxi:
datacenter: ha-datacenter
hostname: eval
register: newvm
ignore_errors: true
- name: ESXi 上の VM を削除する
local_action:
module: vsphere_guest
vcenter_hostname: "{{ esxi_host }}"
username: "{{ esxi_user }}"
password: "{{ esxi_pass }}"
guest: "{{ vm_name }}"
state: absent
force: true
validate_certs: false
esxi:
datacenter: ha-datacenter
hostname: eval
- name: Bergenholm 上の VM の設定を削除する
local_action:
module: bergenholm_host
uuid: "{{ newvm.ansible_facts.hw_product_uuid }}"
state: absent
when: newvm | success
更に簡単。最早説明は要るまい。
では、Let's play.
~/ansible-bergenholm$ time ansible-playbook -i hosts.ini delete.yml
PLAY [VM を削除する] *****************************************************************************************************************************
TASK [ESXi 上の VM 情報を取得する] *******************************************************************************************************************
ok: [ansibletest3 -> localhost]
ok: [ansibletest2 -> localhost]
ok: [ansibletest1 -> localhost]
TASK [ESXi 上の VM を削除する] *********************************************************************************************************************
changed: [ansibletest1 -> localhost]
changed: [ansibletest3 -> localhost]
changed: [ansibletest2 -> localhost]
TASK [Bergenholm 上の VM の設定を削除する] ************************************************************************************************************
changed: [ansibletest1 -> localhost]
changed: [ansibletest3 -> localhost]
changed: [ansibletest2 -> localhost]
PLAY RECAP **********************************************************************************************************************************
ansibletest1 : ok=3 changed=2 unreachable=0 failed=0
ansibletest2 : ok=3 changed=2 unreachable=0 failed=0
ansibletest3 : ok=3 changed=2 unreachable=0 failed=0
real 0m19.939s
user 0m8.300s
sys 0m0.924s
Amazing!!!!
もちろん、delete.yml も再度実行できる。
~/ansible-bergenholm$ time ansible-playbook -i hosts.ini delete.yml
PLAY [VM を削除する] *****************************************************************************************************************************
TASK [ESXi 上の VM 情報を取得する] *******************************************************************************************************************
fatal: [ansibletest1 -> localhost]: FAILED! => {"changed": false, "msg": "No such VM ansibletest1. Fact gathering requires an existing vm"}
...ignoring
fatal: [ansibletest3 -> localhost]: FAILED! => {"changed": false, "msg": "No such VM ansibletest3. Fact gathering requires an existing vm"}
...ignoring
fatal: [ansibletest2 -> localhost]: FAILED! => {"changed": false, "msg": "No such VM ansibletest2. Fact gathering requires an existing vm"}
...ignoring
TASK [ESXi 上の VM を削除する] *********************************************************************************************************************
ok: [ansibletest2 -> localhost]
ok: [ansibletest1 -> localhost]
ok: [ansibletest3 -> localhost]
TASK [Bergenholm 上の VM の設定を削除する] ************************************************************************************************************
skipping: [ansibletest1]
skipping: [ansibletest2]
skipping: [ansibletest3]
PLAY RECAP **********************************************************************************************************************************
ansibletest1 : ok=2 changed=0 unreachable=0 failed=0
ansibletest2 : ok=2 changed=0 unreachable=0 failed=0
ansibletest3 : ok=2 changed=0 unreachable=0 failed=0
real 0m6.962s
user 0m5.584s
sys 0m0.588s
Yes!!!!
今回の delete.yml では、bergenholm_host モジュールは vsphere_guest モジュールが拾ってくる VM のシステム UUID に依存している。2回目の実行では VM が既に存在しないため、when: で bergenholm_host の実行をスキップしている。もし UUID が確定しているのであればスキップする必要はない。
Ubuntu 16.04 VM を自動構築する
create.yml を vi で編集して、下記のようにしてみよう。
~/ansible-bergenholm$ git diff
diff --git a/create.yml b/create.yml
index 6e4f2fd..6f49227 100644
--- a/create.yml
+++ b/create.yml
@@ -1,4 +1,4 @@
-- name: CentOS 7 VM を用意する
+- name: Ubuntu 16.04 VM を用意する
hosts: targets
gather_facts: false
tasks:
@@ -52,8 +52,8 @@
uuid: "{{ newvm.ansible_facts.hw_product_uuid }}"
params:
groups:
- - centos7
- - centos.amd64
+ - ubuntu1604
+ - ubuntu.amd64
hostname: "{{ vm_name }}"
ipaddr: "{{ vm_ipaddr }}"
netif: ens192
これで Ubuntu 16.04 が入った VM 3つが作成されるはずである。
では、Let's play.
~/git/ansible-bergenholm$ time ansible-playbook -i hosts.ini create.yml
PLAY [Ubuntu 16.04 VM を用意する] ****************************************************************************************************************
TASK [ESXi 上に VM を作成する] *********************************************************************************************************************
changed: [ansibletest3 -> localhost]
changed: [ansibletest2 -> localhost]
changed: [ansibletest1 -> localhost]
TASK [ESXi 上の VM の情報を取得する] ******************************************************************************************************************
ok: [ansibletest2 -> localhost]
ok: [ansibletest3 -> localhost]
ok: [ansibletest1 -> localhost]
TASK [Bergenholm 上に新しい VM の設定を登録する] *********************************************************************************************************
changed: [ansibletest2 -> localhost]
changed: [ansibletest3 -> localhost]
changed: [ansibletest1 -> localhost]
RUNNING HANDLER [VM を再起動して OS インストールを開始する] **************************************************************************************************
changed: [ansibletest2 -> localhost]
changed: [ansibletest3 -> localhost]
changed: [ansibletest1 -> localhost]
PLAY [OS インストール後の確認を行う] *********************************************************************************************************************
TASK [OS インストール完了待ち] ************************************************************************************************************************
ok: [ansibletest2]
ok: [ansibletest3]
ok: [ansibletest1]
TASK [Facts を取得する] **************************************************************************************************************************
ok: [ansibletest1]
ok: [ansibletest2]
ok: [ansibletest3]
TASK [ディストリビューション情報を表示する] *******************************************************************************************************************
ok: [ansibletest1] => {
"msg": "Ubuntu 16.04 (xenial)"
}
ok: [ansibletest2] => {
"msg": "Ubuntu 16.04 (xenial)"
}
ok: [ansibletest3] => {
"msg": "Ubuntu 16.04 (xenial)"
}
PLAY RECAP **********************************************************************************************************************************
ansibletest1 : ok=7 changed=3 unreachable=0 failed=0
ansibletest2 : ok=7 changed=3 unreachable=0 failed=0
ansibletest3 : ok=7 changed=3 unreachable=0 failed=0
real 31m50.377s
user 1m45.036s
sys 0m19.536s
Brilliant!!!!
期待通り、Ubuntu 16.04 の VM が3つ作成された。
では、後片付けをしよう。
~/ansible-bergenholm$ time ansible-playbook -i hosts.ini delete.yml
PLAY [VM を削除する] *****************************************************************************************************************************
TASK [ESXi 上の VM 情報を取得する] *******************************************************************************************************************
ok: [ansibletest1 -> localhost]
ok: [ansibletest3 -> localhost]
ok: [ansibletest2 -> localhost]
TASK [ESXi 上の VM を削除する] *********************************************************************************************************************
changed: [ansibletest3 -> localhost]
changed: [ansibletest1 -> localhost]
changed: [ansibletest2 -> localhost]
TASK [Bergenholm 上の VM の設定を削除する] ************************************************************************************************************
changed: [ansibletest1 -> localhost]
changed: [ansibletest2 -> localhost]
changed: [ansibletest3 -> localhost]
PLAY RECAP **********************************************************************************************************************************
ansibletest1 : ok=3 changed=2 unreachable=0 failed=0
ansibletest2 : ok=3 changed=2 unreachable=0 failed=0
ansibletest3 : ok=3 changed=2 unreachable=0 failed=0
real 0m20.222s
user 0m8.280s
sys 0m0.968s
Excellent!!!!
今回は VMware ESXi 上の VM で実験を行ったが、BIOS のシステム UUID さえ判っていれば、Bergenholm を使って物理マシンだろうが KVM だろうが OS の自動インストールが出来る。
最後に
興味を持って頂けたなら、是非 Bergenholm や Ansible bergenholm_host / bergenholm_group モジュールを使ってみて欲しい。
なお、「Ansible」という名称は SF小説に出てくる超光速通信装置、「Bergenholm」は同じく SF小説の超光速エンジンから採られている。
※この記事は Ansible Advent Calendar 2017 の 12/22 分です。