doridoridoriand’s diary

主に技術的なことを書いていく予定(たぶん)

クラウドベンダーのIPアドレス範囲の調べ方

小ネタです。クラウドベンダーがIPアドレスをどのくらい保有しているのか気になって調査したことがあったので、記事に起こしてみました。

今回調べたクラウドベンダー

今回はIPv4のみ調査しました。IPv6を含めると マンドクセ 膨大になりすぎて後述するスクリプトの計算が終わらないので。

AWS

AWSでは保有しているIPアドレスのCIDRブロックをAPIとして 公開 しています。 ページに記載されているCIDRブロックを計算すればIPアドレス保有数がわかります。 以下のようなコードを書いて個数を調べてみました

※計算時間短縮のため、並列演算をしています。実行するとCPUを使い切る挙動になるのでご注意ください。

試しに実行したところ、

$ ruby show_number_of_aws_ip_address.rb
I, [2019-09-28T20:25:00.222308 #61863]  INFO -- : Start to parse IP Address ranges of AWS.
I, [2019-09-28T20:25:00.786106 #61863]  INFO -- : Number of CIDR blocks: 1818
I, [2019-09-28T20:34:05.882460 #61863]  INFO -- : Completed to calculate number of IP addresses. Number of IP address of AWS: 93482928

9300万個所有しているようです。多いですね。

GCP

GCPではspfレコードに所有しているIPアドレス一覧を 記載 しています。 シェルで試しに引っ張ってきてみました。

$ netBlockAddr=(`dig -t txt _spf.google.com +short | tr ':' '\n' | grep net | tr ' ' '\n' | grep net`); for i in ${netBlockAddr[@]}; do dig -t txt $i +short; done | tr ' ' '\n' | grep ip4 | tr ':' '\n' | grep -v ip4;
35.190.247.0/24
64.233.160.0/19
66.102.0.0/20
66.249.80.0/20
72.14.192.0/18
74.125.0.0/16
108.177.8.0/21
173.194.0.0/16
209.85.128.0/17
216.58.192.0/19
216.239.32.0/19
172.217.0.0/19
172.217.32.0/20
172.217.128.0/19
172.217.160.0/20
172.217.192.0/19
108.177.96.0/19
35.191.0.0/16
130.211.0.0/22

※shell力がうんこなので、どなたかもっと良い書き方あったら教えて下さい(切実)

AWSの時と同様にスクリプトを書いてみました。

$ ruby show_number_of_gcp_ip_address.rb
I, [2019-09-28T21:15:23.028779 #91774]  INFO -- : Start to parse IP Address ranges of GCP.
I, [2019-09-28T21:15:23.678997 #91774]  INFO -- : Number of CIDR blocks: 19
I, [2019-09-28T21:15:25.140817 #91774]  INFO -- : Completed to calculate number of IP addresses. Number of IP address of GCP: 322816

めちゃくちゃ少ない。。!
本当に合っているのか不安になる少なさですね。GoogleAppEngineに関してはこのリストに入ってない可能性もあるので、もうちょっと調べてみます(多分)

Azure

Azureでは、以前はXMLによるファイル提供での公開だったのですが、その手法が 廃止予定 になり、その代わりとして Service Tag DiscoveryAPI がプレビュー公開されています。今回はService Tag DiscoveryAPIを利用した方法で計算してみます。

以下のスクリプトで調査可能です。

$ ruby show_number_of_azure_json_ip_address.rb
I, [2019-09-28T21:27:09.594383 #96119]  INFO -- : Start to parse IP Address ranges of Azure.
I, [2019-09-28T21:27:10.568397 #96119]  INFO -- : Number of CIDR blocks: 17009
I, [2019-09-28T21:29:32.258446 #96119]  INFO -- : Completed to calculate number of IP addresses. Number of IP address of Azure: 30981085

特筆すべきはCIDRブロックの多さですね。比較的細かいアドレスレンジを大量に集めているようです。


クラウドベンダーのアドレスをブロックしたいニッチな要求(このご時世実施したらメリットよりデメリットのほうが大きいと思いますが)の時などに参考になればと思います。
IBM CloudやOracle Cloud Platformも、時間を見つけて追加していこうと思います。

AWSにKubernetesクラスタを立てる with eksctl

仕事でKubernetesクラスタを触る機会があったので、家でも触ってみたいと思い、実施したことを忘備録的にまとめます。 AWSのページを確認すると

の2パターンが確認できます。 eksctl とはWeaveworksがメインで開発している、eksを簡単に構築・運用できるようにするためのコマンドラインツールになります。使用感としてはGCPgcloud コマンドに近いとのことです。 ( gcloud コマンド、ちゃんと使ったこと無いので伝聞なのが心苦しいですが。。)

コンソールから実施するタイプの方は、Kuberentes及びAWS CloudFormationなどにある程度慣れている方向けです(結構たいへんです)。
今回は構築・削除を簡単にしたいので、 eksctl を利用する方式を取ります。

※以下構築方法はあくまでプライベートでの検証用途です。会社の環境で同じ設定をすると、おそらく(というか確実に)インフラ or SRE エンジニアからぶっ飛ばされるので気をつけましょう。

やること

(全然セットアップしてない体で説明を開始します。してあるよって方はスキップでおk)

  1. IAMユーザーの作成&アクセスポリシーの追加
  2. AWS CLIのセットアップ
  3. eksctlのセットアップ
  4. 立てちゃう

とりあえずローカル以外でKubernetesを立てるというだけなら、eksctlコマンドを利用すれば驚くほど簡単になっています。

1. IAMユーザーの作成&アクセスポリシーの追加

1.

以下の用にIAMの画面からキーを発行します。 f:id:doridoridoriand:20190703185930p:plain ここでは ユーザー名: eks-power-access アクセスの種類: プラグラムによるアクセス

としました。

2.

次にポリシーをアタッチします。本当はダメな設定ですが、スポットの検証用ということでAdministrator権限をつけています。
(これが万一流出するとほぼ確実に不正利用されるので気をつけましょう) f:id:doridoridoriand:20190703190612p:plain

本来ならば、EKSの構築に必要な権限を調べて、それのみアタッチすべきですが、 ちょっと面倒くさかった 作業簡略化のためAdministratorをつけています

3.

最後入力内容を確認しましょう f:id:doridoridoriand:20190703191141p:plain

4.

キーが発行できたらCSVをダウンロードしておきましょう。画面からでも確認できますが、ダウンロードできるものはしておいたほうが何かと確実です。 f:id:doridoridoriand:20190703205514p:plain

2. AWS CLIのセットアップ

(正直ここまでセットアップ済みだよ!!って方がほとんどだと思いますが)
aws cliのインストールにはpythonが必要になります。お使いのPCがMacでしたらすでに導入されているので問題ないです。
python3系じゃないとだめだろ!!!馬鹿野郎!!!という方はググって頑張ってください。
pyenvもしくはvirtualenvを入れているという方はおそらく説明不要だと思うので、ここの文章はスキップで問題ないです。

他OSの方も、python導入(Windowsに関しては、スタンドアローンインストーラーがあるのでpythonを使わなくても使用可能です)に関してはググって頑張ってください。

以下コマンドで導入することができます

$ pip install awscli

Windowsスタンドアローンインストーラーの方はこちらを参照ください。

3. eksctlのセットアップ

こちらもすぐに終わります。

Linux

$ curl --silent --location "https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
$ sudo mv /tmp/eksctl /usr/local/bin

Mac

$ brew tap weaveworks/tap
$ brew install weaveworks/tap/eksctl

Windows

$ chocolatey install eksctl

ここに書きましたが、最新コマンドはこちらで確認をお願いします。
補完は好き好きで(あると便利です)

4. 立てちゃう

はい。立てちゃいます。

なんにも考えないで実行すると、以下コマンドになります

$ eksctl create cluster

ですが、このコマンドだと m5.large インスタンス2台を us-west-2 (オハイオ) リージョンにて、専用VPCを作成して構築することになります。あとクラスタ名がランダムで決まります。
検証用途にこのサイズのインスタンスは大きすぎるので、ある程度指定してあげましょう。

引数で指定してあげることもできますが、設定値はyamlで管理できるので、是非yamlにしましょう。

以下を指定しました。

以下のようなyamlになるかと思われます。

githubにもいくつかサンプルがあるので、是非参考にしてみてください。

作成するには、以下コマンドを実施します。

$ eksctl create cluster --config-file simple-kubernetes-with-eksctl.yml

10分程度で完成しました

$ eksctl create cluster --config-file simple-kubernetes-with-eksctl.yml
[ℹ]  using region ap-northeast-1
[ℹ]  setting availability zones to [ap-northeast-1d ap-northeast-1a ap-northeast-1c]
[ℹ]  subnets for ap-northeast-1d - public:192.168.0.0/19 private:192.168.96.0/19
[ℹ]  subnets for ap-northeast-1a - public:192.168.32.0/19 private:192.168.128.0/19
[ℹ]  subnets for ap-northeast-1c - public:192.168.64.0/19 private:192.168.160.0/19
[ℹ]  nodegroup "worker00" will use "ami-0dfbca8d183884f02" [AmazonLinux2/1.12]
[ℹ]  creating EKS cluster "kube00-tokyo" in "ap-northeast-1" region
[ℹ]  1 nodegroup (worker00) was included
[ℹ]  will create a CloudFormation stack for cluster itself and 1 nodegroup stack(s)
[ℹ]  if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=ap-northeast-1 --name=kube00-tokyo'
[ℹ]  2 sequential tasks: { create cluster control plane "kube00-tokyo", create nodegroup "worker00" }
[ℹ]  building cluster stack "eksctl-kube00-tokyo-cluster"
[ℹ]  deploying stack "eksctl-kube00-tokyo-cluster"
[ℹ]  building nodegroup stack "eksctl-kube00-tokyo-nodegroup-worker00"
[ℹ]  --nodes-min=2 was set automatically for nodegroup worker00
[ℹ]  --nodes-max=2 was set automatically for nodegroup worker00
[ℹ]  deploying stack "eksctl-kube00-tokyo-nodegroup-worker00"
[✔]  all EKS cluster resource for "kube00-tokyo" had been created
[✔]  saved kubeconfig as "/Users/dorian/.kube/config"
[ℹ]  adding role "arn:aws:iam::xxxxxxxxxxxx:role/eksctl-kube00-tokyo-nodegroup-wor-NodeInstanceRole-13QV27O8G46HU" to auth ConfigMap
[ℹ]  nodegroup "worker00" has 0 node(s)
[ℹ]  waiting for at least 2 node(s) to become ready in "worker00"
[ℹ]  nodegroup "worker00" has 2 node(s)
[ℹ]  node "ip-192-168-19-13.ap-northeast-1.compute.internal" is ready
[ℹ]  node "ip-192-168-36-85.ap-northeast-1.compute.internal" is ready
[ℹ]  kubectl command should work with "/Users/dorian/.kube/config", try 'kubectl get nodes'
[✔]  EKS cluster "kube00-tokyo" in "ap-northeast-1" region is ready

では実際にkubectlコマンドが通るか試してみましょう。

$ kubectl get nodes
NAME                                               STATUS    ROLES     AGE       VERSION
ip-192-168-19-13.ap-northeast-1.compute.internal   Ready     <none>    8m        v1.12.7
ip-192-168-36-85.ap-northeast-1.compute.internal   Ready     <none>    8m        v1.12.7
$ kubectl describe nodes
Name:               ip-192-168-19-13.ap-northeast-1.compute.internal
Roles:              <none>
Labels:             alpha.eksctl.io/cluster-name=kube00-tokyo
                    alpha.eksctl.io/instance-id=i-0d24521d0fc8630ef
                    alpha.eksctl.io/nodegroup-name=worker00
                    beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/instance-type=t3.micro
                    beta.kubernetes.io/os=linux
                    failure-domain.beta.kubernetes.io/region=ap-northeast-1
                    failure-domain.beta.kubernetes.io/zone=ap-northeast-1d
                    kubernetes.io/hostname=ip-192-168-19-13.ap-northeast-1.compute.internal
Annotations:        node.alpha.kubernetes.io/ttl=0
                    volumes.kubernetes.io/controller-managed-attach-detach=true
CreationTimestamp:  Wed, 03 Jul 2019 20:20:37 +0900
Taints:             <none>
Unschedulable:      false
Conditions:
  Type             Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
  ----             ------  -----------------                 ------------------                ------                       -------
  OutOfDisk        False   Wed, 03 Jul 2019 20:25:58 +0900   Wed, 03 Jul 2019 20:20:37 +0900   KubeletHasSufficientDisk     kubelet has sufficient disk space available
  MemoryPressure   False   Wed, 03 Jul 2019 20:25:58 +0900   Wed, 03 Jul 2019 20:20:37 +0900   KubeletHasSufficientMemory   kubelet has sufficient memory available
  DiskPressure     False   Wed, 03 Jul 2019 20:25:58 +0900   Wed, 03 Jul 2019 20:20:37 +0900   KubeletHasNoDiskPressure     kubelet has no disk pressure
  PIDPressure      False   Wed, 03 Jul 2019 20:25:58 +0900   Wed, 03 Jul 2019 20:20:37 +0900   KubeletHasSufficientPID      kubelet has sufficient PID available
  Ready            True    Wed, 03 Jul 2019 20:25:58 +0900   Wed, 03 Jul 2019 20:20:47 +0900   KubeletReady                 kubelet is posting ready status
Addresses:
  InternalIP:   192.168.19.13
  ExternalIP:   xxx.xxx.xxx.xxx
  InternalDNS:  ip-192-168-19-13.ap-northeast-1.compute.internal
  ExternalDNS:  ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
  Hostname:     ip-192-168-19-13.ap-northeast-1.compute.internal
~~~~

問題なさそうですね。 では、一通り必要な検証が終わったとして、お金節約のため、クラスタを削除しましょう。以下コマンドで実施できます。

eksctl delete cluster --name kube00-tokyo
$ eksctl delete cluster --name kube00-tokyo
[ℹ]  using region ap-northeast-1
[ℹ]  deleting EKS cluster "kube00-tokyo"
[✔]  kubeconfig has been updated
[ℹ]  2 sequential tasks: { delete nodegroup "worker00", delete cluster control plane "kube00-tokyo" [async] }
[ℹ]  will delete stack "eksctl-kube00-tokyo-nodegroup-worker00"
[ℹ]  waiting for stack "eksctl-kube00-tokyo-nodegroup-worker00" to get deleted
[ℹ]  will delete stack "eksctl-kube00-tokyo-cluster"
[✔]  all cluster resources were deleted

削除されました。

Kubernetes自体はローカルでも検証することはできますが、クラウドベンダーの機能(AWSで言えばALBIngress, IAMとRBACの連携など)を試すときはサーバー上に構築する必要があります。
eksctlのおかげで、AWSでも簡単に構築できるようになったので、是非試してみてください。

バックエンドの種類を雑に把握する in AWS

ちょっと調査で使用したので、備忘録がてら記事に起こします。

静的サイトホスティングや、アセット系の保存場所S3を使うことはよくあることだと思います。 ですが、S3の静的サイトホスティングを有効にした状態で直接CNAMEやRoute53のエイリアスレコードを貼ってしまうとキャッシュされず、アクセスされるたびに毎回S3にGETが走ってしまうことになります。

個人のサイトなど低頻度アクセスなサイトであればそれほど問題にはなりませんが、商用サービスなどでは以下の問題が生じることがあります。

  • 転送容量によっては、CDNを経由しないと高額になる(とはいえ月間150TB以上転送したときに目の当たりにする問題だったりしますが)
  • GETリクエストに対する課金がCloudFront経由だった場合より高くなる
  • S3のAPIのRateLimitに引っかかる恐れがある(スパイクアクセスが発生したときに問題が表面化すると思われます)

またそもそも論としてS3は多機能ではありますが、メインの機能はストレージサービスですので、コンテンツ配信は別サービスに任せるのがアーキテクチャー的にも吉です。

ですが、以下理由により現在設定されているレコードのバックエンドが、S3直なのかCloudFront経由なのかを調べられない状況が存在します。

  • AWS CLIを現在叩けるPCではない
  • CLI or マネジメントコンソールに対するアクセス権限が無い

以上に対する対応方法として、簡易的にですが、以下の方法を使用することでバックエンドがS3直 or CloudFront経由かを判断できます。

  • curlでヘッダを見て判断する
  • digで返ってきたIPをnslookupする

curlでヘッダを見て判断する

CloudFront => S3となっているサイトに対してcurlを実行すると以下のような結果が返ってきます。

$ curl -I https://example.com/
HTTP/2 200
content-type: text/html
content-length: 1462
date: Sun, 09 Jun 2019 07:44:59 GMT
last-modified: Fri, 13 Oct 2017 03:20:02 GMT
etag: "ccde8929cea4684f8c27cac3f2060c5f"
accept-ranges: bytes
server: AmazonS3
x-cache: Hit from cloudfront
via: 1.1 d90dc9dxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT53
x-amz-cf-id: W0WBTwtWRofoio0ZqLSabHmPkbR3GtlPXXXXXXXXXXXXXXXXXX==

このときserverには AmazonS3 と入っており、一見バックエンドがS3直と勘違いしそうですが、

x-cache: Hit from cloudfront
x-amz-cf-pop: NRT53
x-amz-cf-id: W0WBTwtWRofoio0ZqLSabHmPkbR3GtlPlf_0UudiW7caw62BQ048WQ==

とあるように、CloudFront特有のヘッダがついていることがわかります。 それぞれ

  • x-cache: キャッシュのヒット可否及びTTL切れなどの情報
  • x-amz-cf-pop: どのPOPからレスポンスを受けているか
  • x-amz-cf-id: リクエストごとに付与されているユニークなID

となっています。 S3直のドメインにて同様にcurlを打つと、

curl -I https://example.com/
HTTP/1.1 200 OK
x-amz-id-2: INa97Ph1bsyjvUzPVj8jMxJPiON6ZIWnfXcUs30iyaSqJ46vs+xxxxxxxxxxxxxxxxJ+Evb4=
x-amz-request-id: E0000000000000F
Date: Sun, 09 Jun 2019 08:01:12 GMT
Last-Modified: Tue, 24 Jan 2017 11:03:17 GMT
ETag: "0553432f5fbc381066c8aee67a7afadb"
Accept-Ranges: bytes
Content-Type: text/html
Content-Length: 2728
Server: AmazonS3

というヘッダになっておりCloudFrontを挟んだときのような、キャッシュ情報などはありません。

digで返ってきたIPをnslookupする

IPアドレスにはられているDNSレコードを逆引きしてあげることにより、バックエンドがS3かCloudFrontかを知ることができます。

S3がバックエンドの場合、

$ dig example.com +short | xargs nslookup
Server:         127.0.1.1
Address:        127.0.1.1#53

Non-authoritative answer:
000.000.000.000.in-addr.arpa        name = s3-website-ap-northeast-1.amazonaws.com.

Authoritative answers can be found from:

とCNAMEに s3-website-ap-northeast-1.amazonaws.com. と入ってきます。

CloudFrontが間に挟んである場合、

$ dig exapmle.com +short | head -1 | xargs nslookup
Server:         127.0.1.1
Address:        127.0.1.1#53

Non-authoritative answer:
000.000.000.000.in-addr.arpa        name = server-000-000-000-000.nrt20.r.cloudfront.net.

Authoritative answers can be found from:

とCNAMEに server-000-000-000-000.nrt20.r.cloudfront.net. と入ってきます。

以上からバックエンドの種類を判断することが可能です。 実際の障害対応とかでは適切な権限を持ったエンジニアが対応するかと思われるので、上の手法を使うことは無いと思いますが、このような手法でもできないことは無いということをお伝えしたく記事にしました。

(ブログ書く頻度が低すぎて文体が毎回変わってますが、そのうち統一します。。)

Rubyのoptparseの挙動について

もう知ってる人にとっては、当たり前じゃん何言ってるのみたいな内容かもしれませんが、私は最近知ったので。。

Rubyには optparse というコマンドライン引数を読み取るライブラリが標準でついてくる。 これを使ってよくバッチ処理とかに使うスクリプトを書いてたりする。

この前書いたコードで以下のようなオプションを書いた。

OPTIONS = {}
OptionParser.new do |opt|
  opt.on('-n', '--no-daemon') {|v| OPTIONS[:no_daemon] = v}
  opt.parse!(ARGV)
end

デーモン状態で動くほうが通常モードだったアプリケーションなので、デーモン状態でない時を明示的にしたいときにと思い、 --no-daemon とした。 当初はこの引数を以下のように使用していた。

unless OPTIONS[:no_daemon]
  # :no_daemonがfalseだったときの処理(デーモン状態で動かしたいときの処理)
end

しかしどうも期待どおりの挙動を示してくれない(常にデーモン状態になる)のでドキュメントを見た。library optparse

--[no-]...などとすることで、否定型のオプションを指定することができます。

require 'optparse'
opt = OptionParser.new

opt.on('-a', '--foo') {|v| p v }
opt.on('--[no-]bar') {|v| p v }

opt.parse!(ARGV)
p ARGV

ruby sample.rb -a foo bar --bar baz --no-bar
# => true
     true
     **false**                              # <- --no-bar の指定による。
     ["foo", "bar", "baz"]

noってつけると否定形になって、falseが返ってくるのか

いつもTrueの感覚で書いていたので普通にミスった。

つわけで当初書いたここのコードブロックは

--no-daemonオプションあり => false
--no-daemonオプションなし => nil => false

となるので、常にデーモン状態となったわけだった。

最終的に以下のように修正した。

if OPTIONS[:no_daemon].nil?
  # :no_daemonがfalseだったときの処理(デーモン状態で動かしたいときの処理)
end

こっちのほうが素直な実装だとは思う。

corretto8をAnsible経由でインストールしてAmazonLinuxで使う

前回書いたブログの日にちが1月2日だって。もう引くレベル。

個人用途ではOracleJavaのライセンス問題はそこまで気にする必要ないけれども、会社でJavaを使ってサービス作って運営する業務をしている身としては、頭の片隅にいつもいる感じで、ちょっと気持ち悪かったのも事実。

そんなときに登場した Corretto

AWSありがてえ。。

以外の何者でもない感じであった。(まあOpenJDKでいこうってプロジェクトもあるので完全ではないけど)

Jenkinsを立てる必要が出てきて、どうせなら使ってみようと思って、Ansible経由でインストールしてみたので、その過程を忘備録的に残しておく。
※Jenkinsのことを脳死で嫌う人いるけれども、別にそれをCircleCIやCodeShip変えたからモダンだみたいなのも個人的にはよく分からない。まあ確かにCircleCIチョー便利なのは納得しますが。

使用環境はAmazonLinux2。いきなりAnsibleのtask貼っちゃう。

はい。これだけ。AmazonLinuxならこれだけでインストール完了します。

ついでにJnekinsをインストールするtaskも貼っておく。

これらのインストールが完了して、初期設定とか済ませて、本当にcorrettoが使われているのかをJenkinsの管理画面から確認する。

jenkins runs with corretto8
jenkins runs with corretto8

問題なさそう。

ターミナルをカラフルに表示してみる

12月があっという間で本当に光陰矢の如しとはこのとこだなと思いましたまる

一ヶ月強ぶりの更新となった。一ヶ月ぶりの更新なのにまさかの小ネタなのはお許し下さい

ログ出力時のターミナルの表示をもっとリッチにしたいと思い、どの色が使用可能なのかを確認したかったので作った突貫スクリプト
こちらのブログを参考にした

以下gistにまとめた

実行するとこんな感じで表示される f:id:doridoridoriand:20180102214957p:plain

次回はもっとまともな記事を書こう

JMeterのクラスタをゆるく立ててみる

仕事でJMeterクラスタを使う必要が出てきたので、割と簡単に立てられる方法無いかなと思い、実際にやった方法を忘備録的に残しておく。(まあ会社のwikiにちゃんとあるんだけれど)

GatlingやSaasなどが既に沢山ある状況で、なんで昔ながらのJMeterかというと、既にあるシナリオを使いたいというのが最大の理由。 とはいえJMeterが悪いわけでは全く無いので新しい何かにするモチベーションもなかったのも事実。

構築は全部AWS上。スレッド数がそこそこ多いので、Master-Slave構成とした。 東京リージョンを使用して建てたが、負荷が1つのAZに依るのはテスト的にも基盤的にも良くないだろうと考え、2つのAZに均等にまたがって建てるようにした。
Slave側をstop/startする度にパブリックDNSが変わるのも不便かと思い、本当はEIPをアタッチすべきであるが、aws shellを使ってPublicDNS名引けるよなと思ったこと、将来的にはクラスタサイズを自由に変えたいという思いがあったことなどから敢えてEIPは使用していない。

tag:Nameを適切に設定していれば、aws cliとjqを使用して以下のように取得することが可能である。
以下はtag:Nameを load-test-jmeter-slave-1c に設定していた場合の例。

$ aws ec2 describe-instances --filters="Name=tag:Name, Values=load-test-jmeter-slave-1c" | jq -r ".Reservations[].Instances[].PublicDnsName"
ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com
ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com

これが分かればMasterからSlaveに接続する際に困らないはず。

JMeterとJava8のインストールはAnsibleを使用。 JMeterインストールの主要部分を切り出したロールはこんな感じ。

---

- name: download Apache JMeter
  shell: >
    wget -O {{ jmeter.src_path }} {{ jmeter.pkg_url }}

- name: Unarchive Apache JMeter
  unarchive:
    src: "{{ jmeter.src_path }}"
    dest: "{{ jmeter.dst_path }}"
    remote_src: yes

vars配下には以下の内容を記したmain.ymlを配置してある。

## vars for Apache Jmeter
---
jmeter:
  src_path: /usr/local/src/source/apache-jmeter-3.3.tgz
  dst_path: /usr/local/src/script
  pkg_url: http://ftp.yz.yamagata-u.ac.jp/pub/network/apache//jmeter/binaries/apache-jmeter-3.3.tgz

読むと分かるのだがこれはJMeterのインストールにしか使えない。メモリのアロケーションとかその他confをいじった状態で再度Ansibleを流してしまうと綺麗サッパリなくなってしまうので注意。
(本当はちゃんと主要ファイルをテンプレート化して撒く処理を追加するなりすれば良いのだけれど、ゆるくクラスタを立ててみるの趣旨からはそれてしまうので、今回はなしの方向で)

ここまで出来ればとりあえずJMeterをMaster-Slave構成で起動できるようになる。

Masterから実際に繋いでみる。コマンドは以下のようになるはず。

$ ./jmeter -n -t test.jmx -e -l log.jtl \
  -R ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com,ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com,ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com

一応オプションを説明すると、

-n cliモードで起動(本テストでは基本的にGUIを起動しないように)
-t シナリオファイルの指定
-e 実行後のレポート出力
-l 実行後のログファイルの出力
-R 使用するSlaveのエンドポイント

もっとちゃんと設定すると、 このページのような GatlingライクなHTMLでグラフィカルなレポートも出力できたりするが、今回はとりあえず動かしたかったので。 今回はここまで。