ようへいの日々精進XP

よかろうもん

Vagrant + DigitanOcean + JMeter で作る財布に少しだけ優しい(かもしれない)負荷試験環境

ゴール

  • 簡単なアプリケーションサーバーの負荷テスト
  • 自分の端末ではなくて外部のサーバーを利用して
  • コマンド一発(多くて二発)で負荷試験の開始、結果の収集を行う
  • 結果だけは自端末の JMeter で確認する(シナリオも自分の端末で作る)
  • 出来るだけコストを抑える

構成図とネタ

構成図

f:id:inokara:20150825181721p:plain

ネタ

以下を利用することで同じことが出来るはず。(但し、負荷試験のシナリオは任意で...)

github.com


メモ

要件と設定

ゴールを受けてのざっくり要件と設定の内容を整理する。

要件 設定 備考
簡単に...コマンド一発で... vagrant を利用する bootstrap.sh でテスト準備からテストまでを一気通貫で...
外部のサーバー DigitalOcean を利用する Amazon EC2 でも同じことは可能
シナリオの作成と結果は自分の端末で 自分の端末にも JMeter をインストールする 結果の取得には vagrant rsync-pull を利用
出来るだけコストを... DigitalOcean で使った分だけお支払い 最小構成の Droplet で...

検証の環境

# Mac のバージョン
% sw_vers                                                                                                                     
ProductName:    Mac OS X
ProductVersion: 10.10.4
BuildVersion:   14E46

# vagrant のバージョン
% vagrant version
Installed Version: 1.7.2

シナリオの作成

  • シナリオの作成についてはこちら
  • シナリオファイルは vagrant up 時に rsync でリモートサーバーの /vagrant ディレクトリに転送される

vagrant digitalocean の準備

$ vagrant plugin install vagrant-digitalocean

以下のように Vagrantfile を用意する。

Vagrant.configure('2') do |config|

  config.vm.provider :digital_ocean do |provider, override|
    override.ssh.private_key_path = ENV["DIGITAL_OCEAN_SSH_PRIVATE_KEY_PATH"]
    override.vm.box = 'digital_ocean'
    override.vm.box_url = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box"
    override.ssh.username = 'vagrant'
    provider.ssh_key_name = ENV["DIGITAL_OCEAN_SSH_KEY_NAME"]
    provider.token = ENV["DIGITAL_OCEAN_API_KEY"]
    provider.image = 'ubuntu-14-04-x64'
    provider.region = 'sgp1'
    provider.size = '512mb'
    provider.setup = true
  end

  config.vm.provision :shell, :path => "bootstrap.sh"

end

vagrant rsync-pull の準備

vagrant-rsync-pull プラグインをインストールする。

$ vagrant plugin install vagrant-rsync-pull

以下のように Vagrantfile を修正する。

--- Vagrantfile.bk      2015-08-25 15:49:58.000000000 +0900
+++ Vagrantfile 2015-08-25 15:50:03.000000000 +0900
@@ -14,5 +14,6 @@
   end
 
   config.vm.provision :shell, :path => "bootstrap.sh"
+  config.vm.synced_folder "./result/", "/vagrant/result/", type: "rsync_pull"
 
 end

最終的には以下のような Vagrantfile となる。

Vagrant.configure('2') do |config|

  config.vm.provider :digital_ocean do |provider, override|
    override.ssh.private_key_path = ENV["DIGITAL_OCEAN_SSH_PRIVATE_KEY_PATH"]
    override.vm.box = 'digital_ocean'
    override.vm.box_url = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box"
    override.ssh.username = 'vagrant'
    provider.ssh_key_name = ENV["DIGITAL_OCEAN_SSH_KEY_NAME"]
    provider.token = ENV["DIGITAL_OCEAN_API_KEY"]
    provider.image = 'ubuntu-14-04-x64'
    provider.region = 'sgp1'
    provider.size = '512mb'
    provider.setup = true
  end

  config.vm.provision :shell, :path => "bootstrap.sh"
  config.vm.synced_folder "./result/", "/vagrant/result/", type: "rsync_pull"

end

一応、レイテンシを考慮してシンガポールリージョンに起動することにする。

bootstrap.sh の用意

以下のような雑なシェルスクリプトで Provisioning を行う。

#!/bin/bash

sudo apt-get update
sudo apt-get -qq -y install unzip openjdk-7-jdk

if [ ! -f /home/vagrant/apache-jmeter-2.13/bin/jmeter ];then
  cd /home/vagrant/
  wget -q http://ftp.riken.jp/net/apache//jmeter/binaries/apache-jmeter-2.13.zip
  unzip -q apache-jmeter-2.13.zip
  chmod +x /home/vagrant/apache-jmeter-2.13/bin/jmeter
fi

if [ ! -d /vagrant/result ];then
  mkdir /vagrant/result
fi

sleep 10

# JMeter Running?
ps aux | grep \[A]pacheJMeter
if [ $? = "0" ];then
  pkill java  
  /home/vagrant/apache-jmeter-2.13/bin/jmeter -n -t /vagrant/oreno-thread.jmx -Jmeter.save.saveservice.output_format=xml -l /vagrant/result/result.jtl
else
  /home/vagrant/apache-jmeter-2.13/bin/jmeter -n -t /vagrant/oreno-thread.jmx -Jmeter.save.saveservice.output_format=xml -l /vagrant/result/result.jtl
fi

JMeter を走らせる為に最低限必要な環境の準備、準備が整ったら負荷試験を開始するという流れ。尚、JMeterコマンドラインで実行する場合には以下のオプションが必要になる。

オプション 機能 ロングオプション 備考
-n JMeter を nongui mode で起動する --nongui
-t ストファイルを指定する --testfile ex) --testfile foo.jmx
-l 結果ファイルを指定する --logfile デフォルトの出力フォーマットは CSV となる

JMeterコマンドラインで実行する方法等に関しては下記の記事を参考にさせて頂いた。

有難うございます。

vagrant up

事前に DigitalOcean の管理コンソールにて SSH キーの登録を済ませておくこと。

# 環境変数に API キー等を指定
$ export DIGITAL_OCEAN_SSH_PRIVATE_KEY_PATH='~/.ssh/xxxxxxx.pem'
$ export DIGITAL_OCEAN_SSH_KEY_NAME='Vagrant'
$ export DIGITAL_OCEAN_API_KEY='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

# vagrant up
$ vagrant up --provider=digital_ocean

一発は vagrant up と共に負荷試験が開始されて終了する。

% vagrant up --provider=digital_ocean
Bringing machine 'default' up with 'digital_ocean' provider...
==> default: Using existing SSH key: ssh-key-name
==> default: Creating a new droplet...

(snip)

==> default: Reading package lists...
==> default: Creating summariser <summary>
==> default: Created the tree successfully using /vagrant/oreno-thread.jmx
==> default: Starting the test @ Tue Aug 25 04:36:04 EDT 2015 (1440491764640)
==> default: Waiting for possible shutdown message on port 4445
==> default: summary +    600 in  25.2s =   23.8/s Avg:   669 Min:     2 Max:  1946 Err:     0 (0.00%) Active: 26 Started: 30 Finished: 4
==> default: summary +    210 in     9s =   23.2/s Avg:   466 Min:     2 Max:  1597 Err:     2 (0.95%) Active: 0 Started: 30 Finished: 30
==> default: summary =    810 in  34.2s =   23.7/s Avg:   616 Min:     2 Max:  1946 Err:     2 (0.25%)
==> default: Tidying up ...    @ Tue Aug 25 04:36:39 EDT 2015 (1440491799073)
==> default: ... end of run

結果の取得

$ vagrant rsync-pull

以下のように出力される。

% vagrant rsync-pull
==> default: Rsyncing folder: /path/to/result/ => /vagrant/result/
==> default:   - Exclude: [".vagrant/", "Vagrantfile"]

パラメータを変えてテスト

例えば、シナリオを少し修正して再度テストしたい場合等はシナリオを修正して vagrant provision を実行する。

$ vagrant provision

以下のように出力される。

% vagrant provision
==> default: Rsyncing folder: /Users/kappa/git/myrepo/vagrant_ubuntu1404-digitalocean/result/ => /vagrant/result...
==> default: Rsyncing folder: /Users/kappa/git/myrepo/vagrant_ubuntu1404-digitalocean/ => /vagrant...
==> default: Running provisioner: shell...
    default: Running: /var/folders/7_/d15v38251nj6hbfmwkjh7lg00000gn/T/vagrant-shell20150825-88443-14bk3ff.sh
==> default: stdin: is not a tty
==> default: Ign http://mirrors.digitalocean.com trusty InRelease
==> default: Ign http://mirrors.digitalocean.com trusty-updates InRelease

(snip)

==> default: Hit http://security.ubuntu.com trusty-security/main Translation-en
==> default: Hit http://security.ubuntu.com trusty-security/universe Translation-en
==> default: Reading package lists...
==> default: Creating summariser <summary>
==> default: Created the tree successfully using /vagrant/oreno-thread.jmx
==> default: Starting the test @ Tue Aug 25 04:02:06 EDT 2015 (1440489726904)
==> default: Waiting for possible shutdown message on port 4445
==> default: summary +    590 in    23s =   25.8/s Avg:   575 Min:     2 Max:  1940 Err:     0 (0.00%) Active: 26 Started: 30 Finished: 4
==> default: summary +    220 in     9s =   25.7/s Avg:   370 Min:     2 Max:  1411 Err:     1 (0.45%) Active: 0 Started: 30 Finished: 30
==> default: summary =    810 in  31.5s =   25.8/s Avg:   519 Min:     2 Max:  1940 Err:     1 (0.12%)
==> default: Tidying up ...    @ Tue Aug 25 04:02:38 EDT 2015 (1440489758549)
==> default: ... end of run

結果の確認

スレッドグループに [統計レポート] と [グラフ表示] と [結果をツリーで表示] をそれぞれ追加した上でテスト結果ファイルを開く。

  • 統計レポート

f:id:inokara:20150825173933p:plain

  • グラフ表示

f:id:inokara:20150825173942p:plain

  • 結果をツリーで表示

f:id:inokara:20150825173954p:plain

後片付け

負荷試験が終わったら Droplet を削除しておこう。

% vagrant destroy
    default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Destroying the droplet...
==> default: Running cleanup tasks for 'shell' provisioner...

嬉しいところ、悩みどころ

嬉しいところ

  • ちょっとしたアプリケーション・サーバーの負荷試験を vagrant 一発(実質二発)でイケるのは嬉しい
  • 自分の端末を頑張らせなくて良いのは嬉しい

悩みどころ

  • 負荷を掛けるまでに少し時間がかかる(bootstrap.sh が毎度実行されるので)
  • JMeter の起動パラメータ指定等
  • JMeter のクラサバ構成の構築
  • JMeter サーバーの複数台構成
  • 本環境での試験結果をどれ位信用出来るのかは別途検証はしたい

で、なんぼかかったん?

  • 今回は最小構成の Droplet を使用した
  • 現時点では不明(Billing では確認出来なかった)だけど多分 10 円位のはず

ということで

悩みどころが多いけどちょっとした負荷試験がサクッと安価に試せたのは良かった。

以上。