修士研究の一環で,仮想マシンの台数を増やしながら提案システムのスケーラビリティを測定する実験を行う必要がありました.今回はその過程で仮想マシンが大量に必要になったため,仮想マシンの作成手順を自動化しました.
自動化の過程は主に次の3つに大別されます.以降ではそれぞれをどのように自動化したのか説明します.
- 仮想マシンの作成
- OSインストール
- 個別の仮想マシンごとに設定を変更
1. 仮想マシンの作成
CDSLではハイパーバイザーとしてVMware ESXiを使っています.このESXiは無償版であるため仮想マシンを複製する機能がありません.そのため,今回はSSH経由でESXiへログインし,仮想マシンの構成ファイル(vmxファイル)をコマンドで自動生成することで仮想マシンを作成しました.
以下はPythonでESXiへSSH接続した後に発行しているコマンドの例です.cmd変数の中身が実行しているコマンド全体です.主な処理は,空の仮想マシンを作成,vmxファイルの作成,空の仮想マシンへのvmxファイルの指定,仮想マシン用のディスクの作成,仮想マシンの起動です.
cmd = f"""
vmid=`vim-cmd vmsvc/createdummyvm {vm_name} {vm_store_path}`
cd {vm_store_path}{vm_name}
sed -i -e '/^guestOS =/d' {vm_name}.vmx
cat << EOF >> {vm_name}.vmx
guestOS = "ubuntu-64"
memsize = "{vm_ram_mb}"
numvcpus = "{vm_cpu}"
ethernet0.addressType = "generated"
ethernet0.generatedAddressOffset = "0"
ethernet0.networkName = "{vm_network_name}"
ethernet0.pciSlotNumber = "160"
ethernet0.present = "TRUE"
ethernet0.uptCompatibility = "TRUE"
ethernet0.virtualDev = "vmxnet3"
ethernet0.wakeOnPcktRcv = "TRUE"
powerType.powerOff = "default"
powerType.reset = "default"
powerType.suspend = "soft"
sata0.present = "TRUE"
sata0:0.deviceType = "cdrom-image"
sata0:0.fileName = "{vm_iso_path}"
sata0:0.present = "TRUE"
annotation = "{concat_payload}"
EOF
rm {vm_name}-flat.vmdk {vm_name}.vmdk
vmkfstools --createvirtualdisk {vm_storage_gb}G -d thin {vm_name}.vmdk
vim-cmd vmsvc/reload $vmid
vim-cmd vmsvc/power.on $vmid
"""
これは過去に実装した cdsl-research/ecoman のコードを流用しています.
2. OSインストール
CDSLではLinux OSとしてUbuntu 20.04を使用しています.UbuntuにはOSインストールを自動化する方法としてAutoinstallが用意されています.今回はこのAutoinstallの設定を内包した独自インストーラ(独自ISOファイル)を作成し,インストールの手続きを全自動で行いました.
独自インストーラの作成手順は,(1)既存のOSインストーラをコマンドで解凍し「インストーラ構成ファイル群」を取り出します.次に,(2)その中にあるAutoinstall用の構成ファイルを編集します.さらに,(3)OSインストーラをビルドして独自ISOファイル(OSインストーラ)を作成します.
以下はAutoinstallの設定ファイルの例です.YAML形式で キーボード配列や言語ネットワーク設定, ユーザ情報やタイムゾーンを記述しています. sudoをパスワードなしで実行できるようにlate-commandsへコマンドを追記しました.構成ファイルは,その他の設定とあわせて cdsl-research/auto-install-ubuntu-2004 で公開しています.
#cloud-config
autoinstall:
version: 1
locale: ja_JP.UTF-8
keyboard:
layout: "jp"
network:
version: 2
ethernets:
ens160:
dhcp4: yes
storage:
layout:
name: direct
identity:
hostname: cdsl-ubuntu
password: "xxx"
username: cdsl
ssh:
install-server: yes
packages:
- curl
- htop
late-commands:
- sed -ie 's/%sudo\s\+ALL=(ALL:ALL) /&NOPASSWD:/' /target/etc/sudoers
user-data:
timezone: Asia/Tokyo
今回は上記の構成ファイルをOSインストーラがHTTPサーバから取得するように,ブートローダの起動オプションもあわせて変更しています.
独自ISOファイルを仮想マシンに設定し,仮想マシンを起動すると自動的にOSインストールが開始され,OSのインストール済みな仮想マシンが作成されます.
3. 個別の仮想マシンごとに設定を変更
仮想マシンの作成とOSのインストールを自動化すると,Ubuntuのインストールされた仮想マシンが大量に作成できます.以下は仮想マシンを大量に作成したときの仮想マシン一覧です.
これらの仮想マシンへSSHするためには,仮想マシンごとのIPアドレスを知る必要があります.CDSLではDHCPサーバとDNSサーバを連携したDynamic DNS(RFC 2136)を実現しています.そのため,仮想マシンにホスト名を設定すれば,自動的にホスト名で名前解決が行えます.しかし,インストール済みの仮想マシンは,全て同一のホスト名 cdsl-ubuntu
が設定されています.
そこで,今回は過去に作成したOSSである cdsl-research/nickns を使って「仮想マシンの名前」から「仮想マシンのIPアドレス」を解決し,仮想マシンにホスト名を割り当てます.
以下は,ホスト名を割り当てるために作成したシェルスクリプトです.nicknsへdigコマンドを使って名前解決し,そこで取得したIPアドレスへssh接続し,ホスト名を割り当てます.これにより仮想マシンにホスト名でアクセスできます.
#!/usr/bin/env bash
set -xeu -o pipefail
for i in {001..080}
do
ipaddr=$(dig A +short @127.0.0.1 -p 5310 koyama-log$i.local)
hostname="koyama-log$i"
echo
echo $ipaddr
echo $hostname
sshpass -p xxx ssh -o "StrictHostKeyChecking no" -l cdsl $ipaddr "sudo hostnamectl set-hostname $hostname && sudo netplan apply"
done
Dynamic DNSによるホスト名の割り当てはSlackへ自動通知しているため,実際に実行すると次のような結果が得られました.
最後に tmux-xpanes を使って作成した仮想マシン80台へ一気にSSHしてみました.さすがにディスプレイが小さいと限度があると感じました.
今後はAnsibleを使って自動で作業していこうと考えています.
CDSLではこうした仮想マシンのプロビジョニングや自動化も行っています.興味があればぜひご連絡ください!