以前、AnsibleのVMwareモジュールとcloud-initを利用した仮想マシンのカスタマイズを書きましたが、今回はAnsibleを使ったcloud-initを利用した仮想マシンのカスタマイズ方法について書いてみたいと思います。
構成
- vCenter 7.0 U3
- ESXi 7.0 Update 3
- Ubuntu 22.04 (テンプレートVM)
- open-vm-tools 11.3.5
- cloud-init 22.2
インストール
前回の手順と比べてAnsibleのバージョンがだいぶ新しくなっているため、再度インストール手順を載せておきます。
community.vmware
を利用したAnsibleが実行できる環境を準備してみようと思います。
Ansible 7(ansible-core 2.14)以降をインストールする場合は、Python 3.9以降がインストールされている必要があります。
Releases and maintenance — Ansible Documentation
venvの環境をインストールします。(Ansibleの公式サイトでは、pipxによるインストール手順に変更されてました。)
$ python3 --version Python 3.9.5 $ sudo apt install python3.9-venv $ mkdir ansible-vmware $ cd ansible-vmware $ python3 -m venv venv (python3 -m venv [仮想環境ディレクトリ名])
venvというフォルダが作成されました。
仮想環境のアクティベートし、Ansibleをインストールします。
$ source venv/bin/activate (venv) $ python -m pip install ansible
Collectionをインストールします。requirements.ymlを用意し、インストールしてみます。
(venv) $ vi requirements.yml collections: - name: community.vmware (venv) $ ansible-galaxy collection install -r requirements.yml
collectionのフォルダ内にrequirements.txtがあり、こちらを利用し、pyvmomiとvSphere Automation Python SDKをインストールします。
(venv) $ python -m pip install -r ~/.ansible/collections/ansible_collections/community/vmware/requirements.txt (venv) $ pip list Package Version ---------------------------------- --------- ansible 8.5.0 ansible-core 2.15.5 certifi 2023.7.22 cffi 1.16.0 charset-normalizer 3.3.0 cryptography 41.0.4 idna 3.4 importlib-resources 5.0.7 Jinja2 3.1.2 lxml 4.9.3 MarkupSafe 2.1.3 nsx-policy-python-sdk 4.1.0.1.0 nsx-python-sdk 4.1.0.1.0 nsx-vmc-aws-integration-python-sdk 4.1.0.1.0 nsx-vmc-policy-python-sdk 4.1.0.1.0 packaging 23.2 pip 23.3 pkg_resources 0.0.0 pycparser 2.21 pyOpenSSL 23.2.0 pyvmomi 8.0.2.0 PyYAML 6.0.1 requests 2.31.0 resolvelib 1.0.1 setuptools 44.0.0 six 1.16.0 urllib3 2.0.6 vapi-common-client 2.44.0 vapi-runtime 2.44.0 vcenter-bindings 4.2.0 vmwarecloud-aws 1.64.0 vmwarecloud-draas 1.23.0 vsphere-automation-sdk 1.86.0
前回のAnsibleの構成をもとに、cloud-initを利用した仮想マシンをカスタマイズするロールを書いていきます。
まず、rolesに guest_cloud_init
というロールを作成します。ロールの作成はansible-galaxyコマンドを利用します。
$ cd ~/ansible-vmware $ cd roles $ ansible-galaxy init guest_cloud_init $ tree -L 2 . └── guest_cloud_init ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── README.md ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml
taskのmain.ymlを編集します。テンプレートからのクローンと、仮想マシンにメタデータとユーザデータを設定を行っています。
$ cd guest_cloud_init $ vi task/main.yml --- - name: Clone a virtual machine from Linux template community.vmware.vmware_guest: hostname: "{{ vcenter_hostname }}" username: "{{ vcenter_username }}" password: "{{ vcenter_password }}" datacenter: "{{ datacenter_name }}" validate_certs: no state: present template: "{{ template }}" folder: "/{{ datacenter_name }}/vm" name: "{{ vm_name }}" cluster: "{{ cluster_name }}" delegate_to: localhost - name: Set the metadata and userdata for the virtual machine community.vmware.vmware_guest: hostname: "{{ vcenter_hostname }}" username: "{{ vcenter_username }}" password: "{{ vcenter_password }}" validate_certs: no state: present name: "{{ vm_name }}" advanced_settings: - key: guestinfo.metadata value: "{{ lookup('template', 'metadata.j2') | b64encode }}" - key: guestinfo.metadata.encoding value: base64 - key: guestinfo.userdata value: "{{ lookup('template', 'userdata.j2') | b64encode }}" - key: guestinfo.userdata.encoding value: base64 delegate_to: localhost
templateのmetadata.j2を編集します。このようにすることで、仮想マシン名とゲストOS内のホスト名を同一にすることができます。テンプレート内ではネットワーク設定は固定としていますが、変数として定義も可能です。
$ vi template/metadata.j2 --- instance-id: {{ vm_name }} local-hostname: {{ vm_name }} hostname: {{ vm_name }} network: version: 2 ethernets: ens192: dhcp4: false addresses: - 192.168.1.2/24 gateway4: 192.168.1.1 nameservers: addresses: - 192.168.1.1
templateのuserdata.j2を編集します。
$ vi template/userdata.j2 --- #cloud-config users: - default - name: username ssh_authorized_keys: - 公開鍵をペースト sudo: ALL=(ALL) NOPASSWD:ALL groups: sudo, wheel lock_passwd: true shell: /bin/bash packages: - 必要なパッケージ名を追加
次に、taskの実行に必要な変数について homelab_vm
グループの情報として取得できるように、group_vars配下にフォルダを作成して記載していきます。
$ cd ~/ansible-vmware/group_vars $ mkdir homelab_vm $ cd homelab_vm $ vi main.yml --- vcenter_hostname: vCenter Name datacenter_name: Datacenter Name cluster_name: Cluster Name template: Template Name vm_name: VM Name
playbookを実行できるか確認します。
$ ansible-playbook -i hosts pb_guest_cloud_init.yml PLAY [homelab_vm] ************************************************************************************************************************************************************************ TASK [guest_cloud_init : Clone a virtual machine from Linux template] ****************************************************************************************************** changed: [VM name -> localhost] TASK [guest_cloud_init : Set the metadata and userdata for the virtual machine] ****************************************************************************************** changed: [VM name -> localhost] PLAY RECAP ***************************************************************************************************************************************************************** VM name : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
全体構成として以下のようになりました。
$ tree -L 4 . ├── ansible.cfg ├── group_vars │ ├── all │ │ ├── main.yml │ │ └── vault.yml │ └── homelab_vm │ └── main.yml ├── host_vars ├── hosts ├── pb_guest_cloud_init.yml ├── requirements.yml ├── roles │ └── guest_cloud_init │ ├── defaults │ │ └── main.yml │ ├── files │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── README.md │ ├── tasks │ │ └── main.yml │ ├── templates │ │ ├── metadata.j2 │ │ └── userdata.j2 │ ├── tests │ │ ├── inventory │ │ └── test.yml │ └── vars │ └── main.yml └── venv ├── bin ~ 中略 ~
VMが起動後に、ホスト名が変更されたことや、公開鍵認証を利用してsshでログインできることを確認します。
$ ssh username@192.168.1.2 $ hostnamectl
Ansibleのvmware_guestモジュールは、カスタマイズ仕様を使ったゲストOSの設定が可能ですが、cloud-initには対応はしていなかったため、このような方法でcloud-initが利用できるようになり、より自動化がしやすくなっていくのでは思います。