船井総研デジタルのよもぎたです。
この記事は株式会社船井総研デジタル Advent Calendar 2022の4日目の記事です。
サマリ
Azureの仮想マシンスケールセットを作成し、実際に仮想マシンが増減する様子を観察しようという主旨の記事です。
目論見としては、およそ次のような流れを考えています。
- UbuntuにApacheをインストールしてCGIを有効にする
- CPUに負荷がかかるCGIスクリプトを作成する
- CGIスクリプトにアクセスして、実際にCPUに負荷がかかるのを確認する
- 仮想マシンのイメージを取得する
- 上記のイメージで仮想マシンスケールセットを作成し、ロードバランサー配下に配置する
- ロードバランサーにアクセスして負荷をかけ続けて、スケールアウトするのが確認出来たら停止する
- 仮想マシンが増減する様子を観察する
実際にやってみる
仮想マシンを準備する
仮想マシンの前に、必要に応じて仮想ネットワークとサブネット、それとネットワークセキュリティグループを用意します。ネットワークセキュリティグループの受信規則は、80/tcpをAnyから、22/tcpを自分のIPアドレスから許可するように設定しました。
仮想マシンはOSにUbuntu 22.04を、サイズをStandard B1lsで指定して、あとはデフォルトで作成しました。
Apacheの準備をする
仮想マシンが起動したら、Apacheの準備をしていきます。
何はともあれ、OSのアップデートをします。
$ sudo apt -y update
$ sudo apt -y upgrade
続いて、Apache2をインストールします。
$ sudo apt -y install apache2
Apache2のCGIを有効にします。今回はDocumentRoot直下にCGIスクリプトを置く想定です。
$ sudo a2enmod cgid
Enabling module cgid.
To activate the new configuration, you need to run:
systemctl restart apache2
$ sudo vi /etc/apache2/sites-available/000-default.conf
# ファイルの末尾に次の行を追加します
<Directory "/var/www/html">
Options +ExecCGI
AddHandler cgi-script .cgi
</Directory>
Apache2を再起動します。
$ sudo systemctl restart apache2
$ sudo systemctl status apache2
● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Active: active (running)
テストスクリプトを作成します。
$ sudo vi /var/www/html/test.cgi
$ sudo chmod 755 /var/www/html/test.cgi
$ cat /var/www/html/test.cgi
#!/bin/bash
echo "Content-type: text/plain"
echo ""
echo "Hello world."
echo ""
テストスクリプトにアクセスしてみます。
$ curl -I http://www.example.com/test.cgi
HTTP/1.1 200 OK
---snip---
Content-Length: 14
Content-Type: text/plain
とりあえず、Apache2でCGIスクリプトを実行する準備が整いました。
負荷のかかるCGIスクリプトを用意する
先ほどのテストスクリプトを負荷テスト用にリネームします。
$ sudo mv -v /var/www/html/{test,loadtest}.cgi
renamed '/var/www/html/test.cgi' -> '/var/www/html/loadtest.cgi'
負荷テスト用スクリプトに修正します。
$ cat /var/www/html/loadtest.cgi
#!/bin/bash
echo "Content-type: text/plain"
echo ""
echo "Hello world."
echo ""
/usr/bin/dd if=/dev/random of=/dev/null bs=1M count=256 > /dev/null 2>&1
負荷テスト用スクリプトをテストします。
$ /var/www/html/loadtest.cgi
Content-type: text/plain
Hello world.
Hello world.
が出力された後、プロンプトが返ってくるまで少し間があります。
負荷テスト用スクリプトにアクセスしてみます。
$ curl -I http://www.example.com/loadtest.cgi
HTTP/1.1 200 OK
---snip---
Content-Length: 14
Content-Type: text/plain
負荷テスト用スクリプトに無事アクセスできるのが確認できたので、ab
コマンドで大量アクセスしてみます。
負荷をかける側
$ ab -c 16 -t 5 -n 6400 http://www.example.com/loadtest.cgi
負荷をかけられた側
$ top -n 1 | head -10
top - 01:25:30 up 4 min, 1 user, load average: 2.53, 0.63, 0.23
Tasks: 137 total, 17 running, 120 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us,100.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 402.8 total, 4.2 free, 209.1 used, 189.4 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 169.2 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1098 www-data 20 0 3860 2644 1556 R 6.7 0.6 0:00.70 dd
1099 www-data 20 0 3860 2648 1556 R 6.7 0.6 0:00.70 dd
1112 www-data 20 0 3860 2580 1492 R 6.7 0.6 0:00.69 dd
無事負荷がかかることが確認できました。
いったん仮想マシンをシャットダウンして、イメージを取得することにします。
仮想マシンのイメージを取得する
仮想マシンのイメージを取得する手順については、こちらのページに詳しい記載があります。
簡単に言うと、仮想マシンの概要から「キャプチャ」をクリックして、あとはウィザードに従うだけです。
私はloadtest
という名前でイメージを取得しました。イメージの取得には結構時間がかかりました。
なお、イメージを取得したVMは起動できなくなるので、ご注意ください。
仮想マシンスケールセットを作成する
取得した仮想マシンイメージから、仮想マシンスケールセットを作成します。
手順については、こちらのページに詳しい記載があります。
その前に、フロントに置くロードバランサーを作成します。手順はこちらのページに詳しい記載があります。ただ、パラメータは自分の環境に合わせて適宜変更しました。
仮想マシンのイメージの概要から、「VMSSの作成」をクリックします。そうすると「仮想マシン スケール セットの作成」のウィザードに遷移しますので、お好みのパラメータを入力して仮想マシンのスケールセットを作成します。
ネットワークの設定では「負荷分散のオプション」で「Azure Load Balancer」を選択し、先ほど作成したロードバランサーを選択します。この時点でロードバランサーを新規作成することもできるようです。
次にスケーリングの設定です。私はパラメータを次のように設定しました。
- 「初期インスタンス数」を
1
に設定 - 「スケーリングポリシー」を
Autoscaling
に設定 - 「インスタンスの最大数」を
4
に設定 - 「期間 (分)」を
5
に設定
http://<ロードバランサーのフロントエンドIPアドレス>/
にアクセスして、応答があることを確認します。
Azure CLIから、仮想マシンスケールセットの状態を確認しておきます。
$ az vmss list-instances --resource-group <ResourceGroupName> --name loadtest --output table
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------
0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
仮想マシンが一つだけあることが分かります。
仮想マシンスケールセットに負荷をかける
ようやくここまで来ました。ここからが本番です。
仮想マシンスケールセットに負荷をかけつつ、Azure CLIで仮想マシンスケールセットの状態(VM数)を確認していきます。コマンドはそれぞれ次の通りです。
負荷をかける側
$ ab -c 16 -t 5 -n 64000 http://www.example.com//loadtest.cgi
仮想マシンスケールセットの状態を確認するAzure CLIコマンド
$ for i in {1..150}; do az vmss list-instances --resource-group <ResourceGroupName> --name loadtest --output table; echo "sleep 10s"; sleep 10; done
ではいざ、上記2つのコマンドを実行します。
仮想マシンスケールセットのVM数の推移は下記のとおりです。
$ for i in {1..150}; do az vmss list-instances --resource-group <ResourceGroupName> --name loadtest --output table; echo "sleep 10s"; sleep 10; done
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
---snip---
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------
0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
1 True japaneast VirtualMachineScaleSet loadtest_1 Creating
---snip---
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------
0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
1 True japaneast VirtualMachineScaleSet loadtest_1 Succeeded
---snip---
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------
0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
1 True japaneast VirtualMachineScaleSet loadtest_1 Succeeded
2 True japaneast VirtualMachineScaleSet loadtest_2 Creating
---snip---
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------
0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
1 True japaneast VirtualMachineScaleSet loadtest_1 Succeeded
2 True japaneast VirtualMachineScaleSet loadtest_2 Succeeded
---snip---
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------
0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
1 True japaneast VirtualMachineScaleSet loadtest_1 Succeeded
2 True japaneast VirtualMachineScaleSet loadtest_2 Succeeded
3 True japaneast VirtualMachineScaleSet loadtest_3 Creating
---snip---
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------
0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
1 True japaneast VirtualMachineScaleSet loadtest_1 Succeeded
2 True japaneast VirtualMachineScaleSet loadtest_2 Succeeded
3 True japaneast VirtualMachineScaleSet loadtest_3 Succeeded
---snip---
# 負荷をかけるのを停止
---snip---
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------
0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
1 True japaneast VirtualMachineScaleSet loadtest_1 Succeeded
2 True japaneast VirtualMachineScaleSet loadtest_2 Succeeded
3 True japaneast VirtualMachineScaleSet loadtest_3 Deleting
---snip---
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------
0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
1 True japaneast VirtualMachineScaleSet loadtest_1 Succeeded
2 True japaneast VirtualMachineScaleSet loadtest_2 Succeeded
---snip---
InstanceId LatestModelApplied Location ModelDefinitionApplied Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------ ---------- ------------------- --------------- ------------------------------------
0 True japaneast VirtualMachineScaleSet loadtest_0 Succeeded
負荷をかけ始めてしばらくして追加の仮想マシンがデプロイされること、負荷をかけるのを止めてから、順次仮想マシンが削除されることが確認できました。
負荷をかける前後を含めた仮想マシンのCPU負荷のグラフは次の画像のとおりです。
負荷をかけ始めるとともに急上昇し、負荷を止めると急下降しているのがご確認いただけると思います。
まとめ
無事、仮想マシンスケールセットで負荷に応じて仮想マシンが増減する様子を確認できました。当初の目標はひとまず達成です。しかし、実際にやってみて課題も感じました。
それは、負荷が仮想マシン追加の閾値を超えてから、実際に追加の仮想マシンが稼働し始めるまでの時間が長いということです。あらかじめ負荷がかかることが分かっていて、事前に手動でスケールアウトさせておくという使い方なら問題ないでしょう。しかし、突発的な負荷に迅速に対応するには不十分だと感じました。仮想マシンのプロビジョニングにはどうしても時間がかかるので仕方ないのでしょう。
ここはやはり、コンテナーの出番でしょうか。というわけで、近いうちにAKSのスケーリングも試してみたいと思います。
最後までお読みいただきありがとうございました。