Y_Yamashitaのブログ

勉強したことのアウトプット・メモが中心。記事の内容は個人の見解であり、所属組織を代表するものではありません。

極めて個人的な、AWS Summit 2024の感想と反省

6/20(木)、21(金)の両日、AWS Summit 2024に一般参加者として参加してきました。

昨年の2023年に初めて参加し、今回が2回目の参加だったのですが、個人的に色々と反省点がありました。 1年に1回しかないイベントのため、このままだと次回も同じ過ちを犯すかもしれないので、反省点をブログに残しておこうと思います。ついでに個人的な感想も書いておこうと思います。

はじめにお断り

AWS Summit 2024 でどのような出し物があったかということや、当日のオペレーション・ルールなどについては触れません。その辺は、下記の emi さんのブログでとてつもなく分かりやすく説明されていますので、そちらをご参照ください。

dev.classmethod.jp

また、感想については個人的な所感で、かなり感覚的な話が多いです。キチンとした調査や分析に基づいた意見ではありませんので、予めご了承ください。

個人的な感想

まずは参加してみての個人的な感想を記載します。

生成AIに関するブース・セッションが非常に多かった

世間は生成AIブーム一色ですし、生成AIに関するトピックスに特化した「週刊生成AI with AWS」が公式ブログで発表されるくらいですから、もちろん生成AIが中心になるとは思っていましたが、想像以上に生成AIに関するブース・セッションの割合が多かったです。

AWSの人が事例や展示を直接説明してくれる「AWS Village」というエリアがあるのですが、 体感的に、7~8割くらいのブースが生成AI絡みなんじゃ?と感じるほどでした。(あくまで体感なので、実際の正確な割合は分かりませんが。。)

それに比べると、ネットワークやストレージなどのインフラ周りのブースに関しては、昨年と比べてもかなり縮小されたような気がしました。(これも体感ですが)

サーバレス構成はもはやデフォ

昨年のSummitの時点でも既に、事例のアーキテクチャではサーバレス構成が多く見受けられたように思いますが、今年は更にそれが顕著になり、Summit中に見たアーキテクチャ図はほぼ全てサーバレス構成で、EC2を立てている構成は見なかった気がします。

もちろん世の中ではEC2を使っているケースはたくさんあるでしょうし、あえてEC2を選択するようなケースもあるとは思いますが、作る側としてはサーバレス構成のノウハウもしっかり押さえておく必要があるなと感じました。私はサーバレスの経験・知見があまり無いため、キャッチアップを加速させねばという危機感を覚えました。

リアルで知り合いに会えて嬉しかった

6月に転職して新しい会社に入社したため、まだ社内に知り合いがほとんどおらず、少し寂しい思いをしているのですがw、そんなタイミングで前職の仲間や知り合いに会って話が出来て、非常に嬉しかったですし、良い刺激ももらえました。

前職がブースを出していたので行ってみたのですが、概ね温かく迎えていただけたようで、大変ありがたかったです。

パートナー企業の表彰が羨ましい。。w

AWS Summitに合わせて、以下の表彰が行われますが、受賞資格があるのはAWS Partner Network (APN) 参加企業に所属しているエンジニアとなります。

2024 Japan AWS Jr. Champions の発表 | AWS JAPAN APN ブログ

2024 Japan AWS All Certifications Engineers の発表 | AWS JAPAN APN ブログ

2024 Japan AWS Top Engineers の発表 | AWS JAPAN APN ブログ

2024 Japan AWS Ambassadors の発表 | AWS JAPAN APN ブログ


私は先月までAPN参加企業に所属していたのですが、今は違うため、応募資格がありません。しかし、X(旧Twitter)のタイムラインで「受賞しました!」というツイートがたくさん流れてきたり、当日の発表時の盛り上がりを見ていると、ちょっと羨ましいなと思ってしまいました。。w

個人的な反省点

ここからは、来年に向けた個人的な反省点を記載します。

申し込みをもっと早くするべきだった

Summitへ申し込んだのが、開催1週間前の6/14だったのですが、その時点で、かなりのセッションがすでに満席となってしまっていました。 6月に転職をして新しい会社に入社したため、Summitへ参加できるか不透明だったこともあったのですが、もう少し早く申し込むべきでした。

時間配分を事前に考慮すべきだった

今回、事前に時間配分を十分考慮しなかった結果、いくつか気になっていたブースで話を聞く時間が取れませんでした。。また、気になっていたブースセッションもいくつか見逃してしまいました。

メインセッションに関しては後でオンデマンド配信されるものも結構あるので、ブースで直接色々な話を聞く時間をもう少し多く取っても良かったかな、と思いました。特に人気のあるブースでは説明者の方の手がなかなか空かず、話を聞くのに少し待つ必要があるケースもあるので、時間に余裕を持っておけば良かったです。

また、偶然知り合いにあった時は、せっかくなら色々と話をしたいので、ある程度ゆとりを持った計画にしておくべきだなと思いました。

事前の技術的なキャッチアップが不十分だった

生成AIやそれを活用したアプリケーションに関する話題が多いことは、ある程度は予想できたことでした。(上述通り、実際には予想以上でしたが。。)しかし、生成AIやアプリケーション開発、サーバレスに関するキャッチアップが十分とはいえず、せっかくAWSの人に直接あれこれ聞ける貴重な機会を十分に活かしきることができませんでした。

サービスの概要や一般的なユースケースについては、公式ドキュメントや公式ブログでもある程度説明されているので、せっかく直接質問できるのであれば、実際に設計・構築・運用していく中でぶつかった障壁や悩み等、もう一段深い話が出来れば理想的だったなと思いました。

終わりに

色々と反省点はありましたが、知見が増えたり、色々な刺激をもらえてモチベーションが上がった事は間違いないですし、会いたかった人たちにリアルで会えましたし、行って本当に良かったと思っています。だからこそ、来年はもっと「行って良かった」と思えるように、今回の反省を活かして臨みたいと思います。

【Amazon Bedrock】AWS SDK for Python(Boto3)で、SDXLモデルのパラメータを指定してイメージ生成してみた

最近、Amazon Bedrockを勉強中です。AWS SDK等でInvokeModel APIをコールしSDXLモデルのイメージ生成を行う場合、マネジメントコンソールのプレイグラウンドと比べて、より多くのパラメータを指定可能であることを知ったので、試してみました。

マネジメントコンソールのプレイグラウンドで指定可能なパラメータ

マネジメントコンソールのプレイグラウンドでは、以下のパラメータが指定可能です。

パラメータ 内容
負のプロンプト 生成してほしくないものを記述する。
画像サイズ 画像のサイズを指定する。ランドスケープポートレートは横長か縦長かの指定に利用する。
プロンプト強度 プロンプトにどれだけ厳密に従うかを決める値。
生成ステップ イメージ生成の処理を繰り返すサイクル数。値が大きいほど精密で正確なイメージが作成される。
シード 乱数生成のシード。プロンプトとシード値が同じ場合、同じイメージが生成される。プロンプトが同じでも、シード値が異なると違うイメージとなる。

もし、イメージ生成の際に画風を指定したい場合、そのようなパラメータは存在しないので、プロンプトで「anime style」などと指定する必要があります。

InvokeModel APIで指定可能なパラメータ

InvokeModel APIを使用する場合、上記のプレイグラウンドで指定可能なパラメータに加えて、更に色々なパラメータを指定可能です。詳細は下記の公式ドキュメントを参照してください。

docs.aws.amazon.com

今回は、マネジメントコンソールのプレイグラウンドに存在しないパラメータの内、「style_preset」を使用してみます。このパラメータは、画像モデルを特定のスタイルに導くためのもので、3d-model, analog-film, anime, cinematic, comic-book等、複数のスタイルがあらかじめ用意されています。

Boto3でパラメータを指定しイメージ生成してみた

それでは実際にBoto3でパラメータを指定しイメージ生成してみます。今回はAmazon SageMakerノートブックインスタンスのJupyterLabを利用します。

ノートブックでコードを順番に実行していきます。まずはBedrockのランタイムにアクセスします。

import boto3

runtime_client = boto3.client(
    service_name='bedrock-runtime',
    region_name='us-east-1'
)


続いて、プロンプト・style_preset・シード値用の変数に値を格納します。シード値はランダムな値を格納します。今回はプロンプトには「anime style」といった画風を指定する文言を入れずに、代わりにstyle_presetを「anime」にします。

import random

prompt_data = "A dog running in the park."
style_data = "anime" # ["3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]

seed = random.randint(0,4294967295)


続いて、モデルに渡すためのbody部分とモデルIDを変数に格納します。

import json

modelId = "stability.stable-diffusion-xl-v1"
body = json.dumps({
    "text_prompts": [
        {
            "text": prompt_data,
            "weight": 1.0
        },
        {
            "text": "artifact",
            "weight": -0.5
        }
    ],
    "samples": 1,
    "cfg_scale": 7,
    "seed": seed,
    "steps": 30,
    "style_preset": style_data,
    "height": 512,
    "width": 512,
})

プロンプトはリスト型になっており、複数指定することが可能です。また、プレイグラウンドには無かった要素として、「weight(重み)」があります。weightは-1.0~1.0の範囲で指定可能で、負の値にすることで上述の「負のプロンプト」にすることが可能です。weightが-1.0の場合、そのプロンプトは生成されません。-0.5等の値にすると、完全に生成されないわけではないようです。このように、プレイグラウンドと比べてより柔軟な制御が可能となっています。今回は「artifact(人工物)」というプロンプトを-0.5のweightで設定してみました。


続いて、bodyとモデルIDを指定して、モデルを呼び出します。

response = runtime_client.invoke_model(
    body=body,
    modelId=modelId
)

responseの中身を見ると、下図のようにjson形式となっており、body部分はbotocore.response.StreamingBodyとなっています。

このStreamingBodyから実際のデータを取り出すにはread()というメソッドを使用します。詳細は以下ドキュメントを参照ください。

botocore.amazonaws.com

実際に取り出したレスポンスは、SDXLモデルの場合、以下の書式となっています。

{
    "result": string,
    "artifacts": [
        {
            "seed": int,
            "base64": string,
            "finishReason": string
        }
    ]
}

Stability.ai Diffusion 1.0 によるテキストからの画像生成 - Amazon Bedrock


上記の「base64」の部分に、Base64エンコードされた画像データが入っています。そのため、このデータをデコードし、ファイルとして保存します。また、Jupyterノートブック上で画像を表示するために、HTMLコードも記載します。具体的なコードは以下です。

import base64
from datetime import datetime
from IPython.display import display, HTML

# StreamingBodyからbodyコンテンツを取得し、JSONとして抽出
response_body = json.loads(response.get("body").read())

# 抽出したJSONから、Base64エンコードされた画像データを取り出し
base64_data = response_body.get("artifacts")[0]['base64']

# 画像データをBase64デコード
binary_data = base64.b64decode(base64_data)

# 現在時刻のファイル名でファイル保存
dt_str = str(datetime.now())
with open(f"{dt_str}.png", "wb") as f:
  f.write(binary_data)

# Jupyterノートブック上に画像を表示
html_code = f'<img src="data:image/png;base64,{base64_data}">'
display(HTML(html_code))

実行結果が下図です。プロンプトでは特に何も指定していませんが、アニメ調の画像となりました。また、負のプロンプトで指定した人工物の表現はやや控えめになったかと思います。(街灯が無くなったので。まあ道も人工物といえば人工物ですが。。)ファイルが保存されていることも確認できました。

プロンプトでの画風指定とstyle_presetを併用してみる

今度は、プロンプトで画風を指定したうえで、style_presetで全く別の画風を指定し、どうなるのか試してみます。

import random

prompt_data = "A dog running in the park, anime style."
style_data = "origami" # ["3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"]

seed = random.randint(0,4294967295)

プロンプトではアニメ調を指定しつつ、style_presetには折り紙を指定します。それ以外のパラメータは先ほどと同じです。

結果は下図のようになりました。

見事に折り紙調ですね。style_presetの指定の方が強く反映されているように見えます。

今度はパラメータを少し変更してみます。「cfg_scale」という、プロンプトにどれだけ忠実に従うかを決めるパラメータを変更します。(値が大きいほどプロンプトに忠実になる)デフォルト値は7ですが、最大の35にしてみます。

import json

modelId = "stability.stable-diffusion-xl-v1"
body = json.dumps({
    "text_prompts": [
        {
            "text": prompt_data,
            "weight": 1.0
        },
        {
            "text": "artifact",
            "weight": -0.5
        }
    ],
    "samples": 1,
    "cfg_scale": 35,  #最大値に変更
    "seed": seed,
    "steps": 30,
    "style_preset": style_data,
    "height": 512,
    "width": 512,
})

実行結果が下図です。

やっぱり折り紙調ですね。というか、なんかカオスになってしまいました。。公園感もどっかにいっちゃったし。。

折り紙だとクセが強すぎるのかもしれないので、style_presetを変えてみることにします。まずはphotographic。

続いて、pixel-art。

どんどんおかしな感じになってますね。。もはやどこに犬の要素があるのかも分かりません。。

(結論)スタイルはケンカさせない方がよい

今回はプロンプトが非常に単純でしたし、パラメータも大雑把にしか変えていないので、かなり雑な検証ではあるのですが、今回試した限りでは、以下の所感を持ちました。

  • プロンプトでの画風指定とstyle_presetでは、style_presetの方が強く反映されているように感じた。
  • プロンプトとstyle_presetはケンカさせない方がよい

正直、画像生成に関する実践的なノウハウはあまり身に付きませんでしたがw、とりあえずBoto3でBedrockを扱う練習は出来たので良しとします。
あまり参考になるような内容の無いブログになってしまいましたが、誰かの参考になれば幸いです。

【Amazon Bedrock】モデルの「長さ」の設定値を変えて、応答の変化を確認してみた

個人ブログに記事を書くのは何と2年半ぶりです。。!! ここ2年間は会社のエンジニアブログにブログを書いていたのですが、転職に伴い、再び個人ブログに記事を書くことにしました。

さて、世間では生成AIが大盛り上がりですが、ブームにかなり乗り遅れつつ、ようやく私も以下の本を読みながら、Amazon Bedrockを使って勉強を開始しました。

https://amzn.asia/d/65IQ63S

そこで、基盤モデルの設定値である「長さ」について学習したので、Bedrockのプレイグラウンドを使って、実際に挙動を確認してみたいと思います。

「長さ」について

基盤モデルの「長さ」は、その名の通り、モデルが返すレスポンスの長さを調整するための設定値です。今回は、以下二つの設定値を取り上げます。

設定値 内容
最大長 生成された応答で返されるトークンの最大長
停止シーケンス モデルがそれ以上トークンを生成しないようにする文字シーケンス

詳細は、以下の公式ドキュメントも参照ください。

docs.aws.amazon.com

実際に挙動を確認してみる

ここからは、実際に長さの設定を変えながら、モデルのレスポンスがどのように変わるか確認してみたいと思います。

まずはデフォルト値で利用してみる

テキストのプレイグラウンドで挙動を確認します。モデルはClaude 3 Haikuを使用します。最大長のデフォルト値は2000で、停止シーケンスにはデフォルトで「Human:」が指定されているようです。

「徳川歴代将軍を古い順に答えてください。」と質問を投げると、15代将軍まで回答してくれました。最後が間違ってるようですが、、w

最大長を縮小してみる

次に、最大長を2000から150に減らして、同じ質問を投げてみました。すると、回答が途中で終わってしまいました。トークンが最大長に達してしまったためです。

停止シーケンスを設定してみる

今度は、改めて最大長を2000に戻したうえで、停止シーケンスに「徳川綱吉」を追加し、同じ質問を投げてみました。すると、「徳川綱」まで出力したところで、回答が終わりました。

確認してみた分かったこと

最大長の指定は、「〇〇文字以内で回答してください」と同等ではない

回答をシンプルにしたい場合、プロンプトで「〇〇文字以内に回答してください」と指定する方法があります。この場合、それなりに高性能なモデルであれば、指定した文字数(あるいはそれに近い文字数)でまとまるように回答するかと思います。

それに対し、最大長を指定しただけでプロンプトで何も指示しないと、回答が途中で途切れてしまいました。モデル自身が最大長を意識しているわけではないので、回答としてキチンと完結させるためには、ユーザー側が最大長を意識しながら、プロンプトで明確に指定する必要があるようです。

停止シーケンスで指定した文字は途中まで出力された

先ほど停止シーケンスに「徳川綱吉」と指定した際には、「徳川綱」まで出力されたところで停止しました。
試しに、停止シーケンスを「吉宗」と指定して再度試してみたところ、今度は「徳川吉」まで出力されたところで停止しました。

サンプルが少ないので断言は出来ませんが、停止シーケンスで指定した文字が全て出力されてから止まるのではなく、見た目上は直前で止まっているように見えました。



以上、モデルの「長さ」に関する動作確認でした。生成AIやBedrockを使い慣れている方からしたら初歩的な内容かもしれませんが、私はこのパラメータについて何も知らなかったので、実際に挙動を確認して理解が深まりました。プレイグラウンドは簡単に確認が出来て便利ですね。
上述のBedrock本はまだ2章までしか進められていないので、3章以降も進めて、気になった点はまた検証等してブログに書きたいと思います。

Route53のルーティング方式毎のクエリ応答切り替わりを確認する - 加重+フェイルオーバールーティング編

はじめに

前回のブログから随分と時間が経ってしまいました。 その間に、AWS Certified Developer - Associateに合格したり、転職のための準備などをやっていました。
転職のことについては、気が向いたらその内ブログにまとめようかと思います。

さて、今更ではありますが、以前Route53のシンプルルーティングの挙動を確認したので、今回はその続きとして、加重+フェイルオーバールーティングの挙動を確認したいと思います。

今回の構成

今回は、下図のように「プライマリリソース2台、セカンダリリソース2台」の構成にし、リソースのダウン状態に応じてアクセス結果がどうなるか見ていきたいと思います。
実務ではこのような構成は採用しないと思いますが、あくまで動作検証目的なのでご容赦ください。

f:id:YuY_83:20211107213547p:plain

今回はプライベートホステッドゾーンを使用し、VPC内の踏み台サーバからWEBサーバにアクセスすることにします。
NATゲートウェイは、プライベートサブネットのEC2にパッケージをインストールするために使用します。

環境構築の方法

今回は、VPC内の環境はCloudFormationで構築し、Route53の設定は手動で行います。
CloudFormationのテンプレートは以下のものを使用します。
Route53_Failover_Routing.yml

環境構築

VPC内構築(CloudFormation)

まずは上述のテンプレートを使ってVPC内の環境を構築します。

[cloudshell-user@ip-10-0-175-26 ~]$ ls -l
total 3000
-rw------- 1 cloudshell-user cloudshell-user 3489792 Sep 25 08:20 core.3704
-rw-rw-r-- 1 cloudshell-user cloudshell-user   18077 Nov  6 16:31 Route53_Failover_Routing.yml
[cloudshell-user@ip-10-0-175-26 ~]$ 
[cloudshell-user@ip-10-0-175-26 ~]$ 
[cloudshell-user@ip-10-0-175-26 ~]$ 
[cloudshell-user@ip-10-0-175-26 ~]$ aws cloudformation validate-template --template-body file:///home/cloudshell-user/Route53_Failover_Routing.yml
{
    "Parameters": [
        {
            "ParameterKey": "KeyName",
            "NoEcho": false,
            "Description": "Name of an existing EC2 KeyPair to enable SSH access to the instances"
        },
        {
            "ParameterKey": "EnvironmentType",
            "DefaultValue": "test",
            "NoEcho": false,
            "Description": "The environment type"
        },
        {
            "ParameterKey": "ClientIP",
            "DefaultValue": "0.0.0.0/0",
            "NoEcho": false,
            "Description": "Client IP Address"
        }
    ],
    "Description": "EC2 WEB Server Deploy for Route53 Failover Routing"
}
[cloudshell-user@ip-10-0-175-26 ~]$ 
[cloudshell-user@ip-10-0-175-26 ~]$ 
[cloudshell-user@ip-10-0-175-26 ~]$ 
[cloudshell-user@ip-10-0-175-26 ~]$ aws cloudformation create-stack \
>  --stack-name EC2deploy-for-Route53Failover \
>  --template-body file:///home/cloudshell-user/Route53_Failover_Routing.yml \
>  --parameters \
>  ParameterKey=KeyName,ParameterValue="xxx" \
>  ParameterKey=ClientIP,ParameterValue="114.xxx.xxx.xxx/32" \
>  ParameterKey=EnvironmentType,ParameterValue="test"
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/EC2deploy-for-Route53Failover/888ef8d0-3f1f-11ec-8a07-069142138e3f"
}
[cloudshell-user@ip-10-0-175-26 ~]$ 
[cloudshell-user@ip-10-0-175-26 ~]$
[cloudshell-user@ip-10-0-175-26 ~]$ aws cloudformation describe-stacks --stack-name EC2deploy-for-Route53Failover
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/EC2deploy-for-Route53Failover/888ef8d0-3f1f-11ec-8a07-069142138e3f",
            "StackName": "EC2deploy-for-Route53Failover",
            "Description": "EC2 WEB Server Deploy for Route53 Failover Routing",
            "Parameters": [
                {
                    "ParameterKey": "KeyName",
                    "ParameterValue": "xxx"
                },
                {
                    "ParameterKey": "EnvironmentType",
                    "ParameterValue": "test"
                },
                {
                    "ParameterKey": "ClientIP",
                    "ParameterValue": "114.xxx.xxx.xxx/32"
                }
            ],
            "CreationTime": "2021-11-06T16:35:21.031000+00:00",
            "RollbackConfiguration": {},
            "StackStatus": "CREATE_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Outputs": [
                {
                    "OutputKey": "PublicIPaddress",
                    "OutputValue": "18.xxx.xxx.xxx",
                    "Description": "PublicIpaddress for Bastion"
                },
                {
                    "OutputKey": "InstanceSecurityGroup1",
                    "OutputValue": "sg-xxxxxxxxxxxxxxxxx",
                    "Description": "InstanceSecurityGroup1",
                    "ExportName": "EC2deploy-for-Route53Failover-InstanceSecurityGroup1"
                },
                {
                    "OutputKey": "PublicSubnet1",
                    "OutputValue": "subnet-xxxxxxxxxxxxxxxxx",
                    "Description": "PublicSubnet1",
                    "ExportName": "EC2deploy-for-Route53Failover-PublicSubnet1"
                }
            ],
            "Tags": [],
            "EnableTerminationProtection": false,
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}
[cloudshell-user@ip-10-0-175-26 ~]$ 
[cloudshell-user@ip-10-0-175-26 ~]$ 



Route53設定

次はRoute53の設定です。加重+フェイルオーバールーティングの場合、先にヘルスチェックの作成をする必要があります。
ただし、今回WEBサーバにはパブリックIPを割り当てていないので、IPアドレスによるヘルスチェックは出来ません。詳細は以下のリンクを参照してください。

docs.aws.amazon.com


そのため、今回はCloudWatchアラームを使用してヘルスチェックを行います。

CloudWatchアラームの作成

というわけで、まずCloudWatchアラームを作成します。

f:id:YuY_83:20211107222911p:plain
EC2インスタンスの「StatusCheckFailed_Instance」メトリクスを使用します。

f:id:YuY_83:20211107223047p:plain
インスタンス毎にアラームを作成します。

Route53ヘルスチェックの作成

続いて、Route53ヘルスチェックを作成します。

f:id:YuY_83:20211107223357p:plain
まずはヘルスチェック作成ボタンを押します。


f:id:YuY_83:20211107223429p:plain
続いて、諸々の情報を入力します。なお、今回はアラームが不足状態の時は異常扱いとしました。理由は、疑似障害として対象インスタンスを手動で停止した所、CloudWatchアラームが「NG」ではなく「データ不足」になってしまったためです。


f:id:YuY_83:20211107223820p:plain
Route53ヘルスチェックも、インスタンス毎に作成します。

DNSレコードの追加

続いて、DNSレコードを追加していきます。フェイルオーバーのプライマリリソース、セカンダリリソースが複数ある場合、エイリアスレコードを併用する必要があります。詳細は以下のリンクを参照してください。

docs.aws.amazon.com



まずはインスタンスのAレコードを加重ルーティングで登録します。最初はEC2Aです。

f:id:YuY_83:20211107224811p:plain
レコード名は「failover-primary」としています。先ほど作成したヘルスチェックと紐づけます。TTLは図では300秒になっていますが、後で10秒に変更しました。(TTLが長いと、短時間のアクセスでは想定通り加重されない場合がありました。)EC2Bも同様に設定します。


f:id:YuY_83:20211107224937p:plain
EC2C、EC2Dはレコード名を「failover-secondary」としました。


続いて、名前解決したいホスト名「www.example.com」のエイリアスレコードを、フェイルオーバールーティングで作成します。

f:id:YuY_83:20211107225121p:plain
「failover-primary」と紐づけ、プライマリリソースとします。


f:id:YuY_83:20211107225503p:plain
もう一つ「www.example.com」のレコードを作成します。こちらは「failover-secondary」と紐づけ、セカンダリリソースとします。


f:id:YuY_83:20211107225557p:plain
最終的にレコードは上図のようになりました。

アクセス確認

今回のアクセス確認方法

前述通り、今回は踏み台EC2からアクセス確認します。簡便なスクリプトを使い、10秒おきに「www.example.com/index.html」宛てに100回curlして、応答したインスタンスの数をカウントします。(※各WEBサーバにはCloudFormaitonでindex.htmlを配置しています。index.htmlのBodyに自身の名前が記述されているので、それを抜き出します。)

踏み台EC2で使用するスクリプトの中身は以下です。これもCloudFormationで事前に配置しています。

#!/bin/bash

for ((i=1; i<=100; i++))
do
  curl -s http://www.example.com/index.html | grep -o "EC2." >> ./curlresult
  sleep 10
done

cat ./curlresult | sort | uniq -c

echo "curl done!!"



アクセス確認結果

インスタンスの正常時

インスタンスの正常時は、プライマリリソースの2台で加重ルーティングされました。

[ec2-user@ip-10-100-0-78 ~]$ 
[ec2-user@ip-10-100-0-78 ~]$ ./curlrepeat.sh
     70 EC2A
     30 EC2B
curl done!!
[ec2-user@ip-10-100-0-78 ~]$ 
[ec2-user@ip-10-100-0-78 ~]$ 



f:id:YuY_83:20211107213547p:plain

EC2Aの異常時

EC2Aに異常がある場合、もう1台のプライマリリソースであるEC2Bに全アクセスが集中しました。

[ec2-user@ip-10-100-0-78 ~]$ ./curlrepeat.sh
    100 EC2B
curl done!!
[ec2-user@ip-10-100-0-78 ~]$ 



f:id:YuY_83:20211107232225p:plain

EC2A、EC2Bの異常時

プライマリリソースの全台に異常がある場合、セカンダリリソースの2台で加重ルーティングされました。

[ec2-user@ip-10-100-0-78 ~]$ ./curlrepeat.sh
     17 EC2C
     83 EC2D
curl done!!
[ec2-user@ip-10-100-0-78 ~]$ 



f:id:YuY_83:20211107233209p:plain

EC2A、EC2B、EC2Cの異常時

プライマリリソースの全台+セカンダリリソースの1台に異常がある場合、セカンダリリソースの残り1台に全アクセスが集中しました。

[ec2-user@ip-10-100-0-78 ~]$ ./curlrepeat.sh
    100 EC2D
curl done!!
[ec2-user@ip-10-100-0-78 ~]$



f:id:YuY_83:20211107233541p:plain

結論

というわけで、以下のような結果となりました。

  • プライマリリソースが全異常にならない限り、プライマリリソースの正常なレコードで加重ルーティングされる。
  • プライマリリソースが全異常になっている間は、セカンダリリソースの正常なレコードで加重ルーティングされる。

ログの記載は省略しますが、EC2Bのみ異常の場合や、EC2A、EC2B、EC2Dに異常がある場合も、上記ルールに則った結果となりました。

なお、今回はプライマリ、セカンダリ両方にヘルスチェックを設定していましたが、ヘルスチェックを設定していない場合は挙動が変わるようです。詳細は以下リンクを参照ください。

docs.aws.amazon.com

Route53ヘルスチェックについての補足

もしヘルスチェックをIPで行う場合、Route53ヘルスチェッカーからのアクセスをセキュリティグループ等で許可する必要があります。Route53ヘルスチェッカーはVPC外に存在しているためです。詳細は以下のリンクを参照してください。

docs.aws.amazon.com



また、Route53ヘルスチェッカーのIPアドレスはリージョン毎に異なります。アドレス範囲については以下のリンクを参照してください。

docs.aws.amazon.com

おわりに

というわけで、前回のシンプルルーティングから2ヶ月も経ってしまいましたが、ようやく加重+フェイルオーバールーティングの設定と動作確認が出来ました。

今回もCloudFormationの設定で色々躓いたうえ、複数リソースでのフェイルオーバールーティング設定でも苦戦したため、予想以上に時間を使ってしまいました。
ただ、おかげでCloudFormationやRoute53に少しずつ慣れてきたので、今後も試行錯誤しながら色々試していきたいと思います。

CloudFormation初心者が色々ハマった話

はじめに

前回のブログで記載した通り、慣れないCloudFormationで環境構築をしようとしたところハマってしまい、解決までに結構手間取ってしまいました。今後同じようなミスをしないように、備忘としてブログに残したいと思います。

今回ハマったこと

今回、主に以下の3つのポイントでハマってしまいました。

ファイルパスの先頭にfile://をつけていなかった

CLIでCloudFormationのスタックを作成する場合、aws cloudformation create-stackコマンドを使用し、--template-body file://<ファイルパス>という形式でテンプレートファイルのパスを指定します。ポイントは、ファイルパスの前に「file://」をつけることなのですが、これをつけていませんでした。なぜかスッポリ意識から抜け落ちていました。「CLIで引数にファイルを指定する時はファイルパス」という思い込みがあったのかもしれません。

そうして「file://」をつけずに実行しようとすると、以下のようなエラーが表示されます。

[cloudshell-user@ip-10-0-87-215 ~]$ aws cloudformation create-stack \
> --stack-name EC2-WEB-deploy \
> --template-body /home/cloudshell-user/ec2_web.yml \
> --parameters \
> ParameterKey=KeyName,ParameterValue="XXX" \
> ParameterKey=AmiId,ParameterValue="ami-0a1c2ec61571737db" \
> ParameterKey=ClientIP,ParameterValue="114.XXX.XXX.XXX/32" \
> ParameterKey=ServerName,ParameterValue="www.XXXXXXXXXX.com:80"

An error occurred (ValidationError) when calling the CreateStack operation: Template format error: unsupported structure.
[cloudshell-user@ip-10-0-87-215 ~]$


aws cloudformation validate-templateコマンドでも同様のエラーが表示されます。

[cloudshell-user@ip-10-0-87-215 ~]$ aws cloudformation validate-template --template-body /home/cloudshell-user/ec2_web.yml

An error occurred (ValidationError) when calling the ValidateTemplate operation: Template format error: unsupported structure.
[cloudshell-user@ip-10-0-87-215 ~]$ 


「テンプレートフォーマットエラー:サポートされていない構造」という表記だったので、まさかコマンドの書式が間違っているとは思いもしませんでした。特に今回は初めてヘルパースクリプトやユーザーデータを使っていて、テンプレートの記載が正しいか自信がなかったので、真っ先にテンプレートの中身を疑ってしまいました。

そうして暫くテンプレートと格闘していたのですが、エラーメッセージでググったら、そのものズバリな回答が記載されているサイトがすぐ出てきました。。

sqlazure.jp

大文字小文字の記述ミス

こうしてテンプレートフォーマットエラーを解消して、aws cloudformation create-stackコマンドは通るようになったのですが、スタック作成が途中で失敗してロールバックしてしまいました。そこで、aws cloudformation describe-stack-eventsコマンドで、スタックのイベントをチェックしてみました。

[cloudshell-user@ip-10-0-87-215 ~]$ aws cloudformation create-stack \
> --stack-name EC2-WEB-deploy \
> --template-body file:///home/cloudshell-user/ec2_web.yml \
> --parameters \
> ParameterKey=KeyName,ParameterValue="XXX" \
> ParameterKey=AmiId,ParameterValue="ami-0a1c2ec61571737db" \
> ParameterKey=ClientIP,ParameterValue="114.XXX.XXX.XXX/32" \
> ParameterKey=ServerName,ParameterValue="www.XXXXXXXXXX.com:80"
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/EC2-WEB-deploy/8af162a0-0fe7-11ec-a7df-0a0e301349e7"
}
[cloudshell-user@ip-10-0-87-215 ~]$ 
[cloudshell-user@ip-10-0-87-215 ~]$ 
[cloudshell-user@ip-10-0-87-215 ~]$ 
[cloudshell-user@ip-10-0-87-215 ~]$ aws cloudformation describe-stack-events --stack-name EC2-WEB-deploy
{
    "StackEvents": [
        {
          ----- 中略 -----
        },
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/EC2-WEB-deploy/8af162a0-0fe7-11ec-a7df-0a0e301349e7",
            "EventId": "EC2A-CREATE_FAILED-2021-09-07T14:51:54.021Z",
            "StackName": "EC2-WEB-deploy",
            "LogicalResourceId": "EC2A",
            "PhysicalResourceId": "",
            "ResourceType": "AWS::EC2::Instance",
            "Timestamp": "2021-09-07T14:51:54.021000+00:00",
            "ResourceStatus": "CREATE_FAILED",
            "ResourceStatusReason": "Encountered unsupported property Userdata"
        },
        {

最後の行に、何やら「Userdataというサポートしていないpropertyに遭遇した」という表記が出てきました。「EC2はユーザーデータをサポートしていない?いや、そんなはずない。。」と悩みつつ、ユーザーデータの中身をチェックし直してみますが、おかしそうな所は見当たりません。

困惑しつつ、見本にしたテンプレートを自分のテンプレートを何度も見比べて、ようやく気付きました。「Userdata」ではなく「UserData」が正しいことに。。

日本語の文字化け

propertyの表記も修正して、ようやく環境構築が完了したので、早速WEBページにブラウザでアクセスしてみたところ、今度はWEBページが文字化けしていました。。 f:id:YuY_83:20210908005044p:plain

文字コードUTF-8にしてテンプレートにしたのに何故。。」と思ってググったところ、以下のページに詳しい解説がありました。

dev.classmethod.jp


CloudFormationの組み込み関数Fn::Base64で日本語を一度ASCII文字に変換してから、ユーザーデータ上のスクリプトでデコードする必要があるようです。

ただ、環境構築を開始したのが深夜で、これに気付いた時点ですでに夜が明けかかっており、文字変換まで実装する気力がなかったので、今回はWEBページを英語表記にして逃げました。。

今回の一番の反省点

以上、つらつらとハマったポイントをまとめてみました。最初の二つは「不注意」と言われればそれまでなんですが、今回四苦八苦したおかげで、金輪際「file://」と「UserData」を忘れることはないでしょう。

日本語WEBページの表示は、また今度、機会を作って挑戦したいと思います。

そして何より、今回の一番の反省ポイントは「寝不足状態で作業しない」ですw
寝不足だと本当にしょうもないミスが多くて、以前にも、しっかり寝た後で見直して「なんでこんなミスを」と呆れた事がありました。
手を動かしての検証は楽しいのでつい時間を忘れて取り組んでしまいますが、要反省ですね。

(オマケ)今回のCloudFormationの環境構築について

最後に、あまり本題とは関係ないのですが、今回CloudFormationで構築した構成や、テンプレートの中身などについてまとめました。

今回構築した構成

今回は、下図の赤点線部分をCloudFormationで構築しました。

f:id:YuY_83:20210906223623p:plain


Route53のパブリックホストゾーンは既に存在していたものを使用しました。

cfn-init、ユーザーデータによる設定

cfn-init、ユーザーデータを使い、EC2に対して以下の設定も実施してみました。

  • httpdのインストール
  • /var/www/html/index.htmlへのコンテンツ格納
  • /etc/httpd/conf/httpd.confのServerNameの値を変更
  • SSHのListenポートを22から51512に変更


/etc/httpd/conf/httpd.confの変更は、CloudFormationのParameterで入力した値を、ユーザーデータでシェル変数として使うために参照させました。
Parameterの値をユーザーデータで変数として利用できるのは便利ですね。

最後のSSHのポート変更は今回の趣旨と関係ありませんが、以前のブログでユーザーデータを扱った際にやった事があったので、今回CloudFormationでもやってみました。

今回使用したCloudFormationテンプレート

上記の構築・設定のために使用したCloudFormationテンプレートはこちらです。

CloudFormationテンプレートの作成にあたっては、以下のページを大いに参考にさせていただきました。

dev.classmethod.jp


dev.classmethod.jp


blog.serverworks.co.jp


CloudFormationの実行方法

冒頭でも記載した通り、今回、CloudFormationのスタック作成はマネコンではなくCLIで実施しました。

Route53のルーティング方式毎のクエリ応答切り替わりを確認する - シンプルルーティング編

はじめに

前回のブログで記載した通り、AWS Certified Advanced Networking - Specialtyに合格することが出来ました。

試験対策中は座学が中心だったのですが、一区切りついたので、勉強した内容について実際に挙動を確認してみたいと思います。

とはいえDirectConnectなどは構築のハードルが高いので、Route53の各ルーティング方式毎の挙動(クエリ応答の切り替わり)を見ていくことにしました。その中で今回は、最も基本的なシンプルルーティングの挙動を見ていきたいと思います。

Route53シンプルルーティングについて

シンプルルーティングについては以下の公式ページに説明があります。

docs.aws.amazon.com

「複数の値を 1 つのレコードに指定すると、Route 53 はすべての値をランダムな順序で再帰的リゾルバーに返し」と記載があるので、ラウンドロビンではないようです。

今回の構成

今回は図のような構成を作りました。 f:id:YuY_83:20210906220351p:plain

通常であれば、WEBサーバはプライベートサブネットに置いて、ELBをパブリックサブネットに置くのがベタな構成ですが、今回は検証目的なので直接パブリックサブネットに置いてしまいます。

2台のWEBサーバに同じホスト名を割り当て、そのホスト名に対するAレコードを、Route53パブリックホストゾーンに登録します。シンプルルーティングによって、2つのWEBページがランダムに表示されることを確認します。

WEBページについて

2つのWEBページがランダムに表示されていることを確認するために、ページの内容は若干変えました。「Hello」とだけ表示されるページとかでも良かったのですが、それだと少し寂しいので、無駄にリンクなどをつけて、以下のような感じにしました。

f:id:YuY_83:20210906001010p:plain

この時点ではIPアドレスを直接叩いてアクセスしています。

Route53作業

それでは、Route53のパブリックホストゾーンにAレコードを登録します。

f:id:YuY_83:20210906213347p:plain まずは目的のゾーンに移動して、「レコードを作成」を選択

f:id:YuY_83:20210906213441p:plain ルーティングポリシーで「シンプルルーティング」を選択

f:id:YuY_83:20210906213528p:plain ホスト名を入力し、レコードタイプでAレコードを選択。値/トラフィックのルーティング先には「レコードタイプに応じたIPアドレスまたは別の値」を選択し、二つのWEBサーバのIPアドレスを登録。TTLを適当に短い時間(今回は10秒)に変更し、「シンプルなレコードの定義」を選択。

f:id:YuY_83:20211102233242p:plain 内容に問題がないことを確認して、「レコードを作成」を選択。

f:id:YuY_83:20210906213859p:plain シンプルルーティングのAレコードが登録されたことを確認。

ページ閲覧・クエリ応答確認

ホスト名でのページ閲覧

それでは、ホスト名でWEBページにアクセスし、適当にブラウザを更新してみます。

f:id:YuY_83:20210906215533p:plain 同じホスト名で、ランダムで二つのWEBページが表示されました。

クエリ応答確認

続いて、クライアントPCからnslookupでクエリを飛ばし、応答を確認してみます。

C:\Users>echo %date% %time%
2021/09/05 16:18:12.85

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
DNS request timed out.
    timeout was 2 seconds.
名前:    www.XXXXX.com
Addresses:  18.XXX.XXX.XXX
          54.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:19:02.34

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  18.XXX.XXX.XXX
          54.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:19:11.60

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  54.XXX.XXX.XXX
          18.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:19:19.88

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  54.XXX.XXX.XXX
          18.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:19:25.38

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  54.XXX.XXX.XXX
          18.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:19:32.73

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  18.XXX.XXX.XXX
          54.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:19:39.71

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  54.XXX.XXX.XXX
          18.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:19:47.60

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  18.XXX.XXX.XXX
          54.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:19:53.42

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  18.XXX.XXX.XXX
          54.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:20:04.39

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  18.XXX.XXX.XXX
          54.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:20:10.62

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  18.XXX.XXX.XXX
          54.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:20:17.89

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  18.XXX.XXX.XXX
          54.XXX.XXX.XXX


C:\Users>echo %date% %time%
2021/09/05 16:20:23.82

C:\Users>nslookup www.XXXXX.com
サーバー:  UnKnown
Address:  2404:1a8:7f01:b::3

権限のない回答:
名前:    www.XXXXX.com
Addresses:  54.XXX.XXX.XXX
          18.XXX.XXX.XXX


C:\Users>

ラウンドロビンではなく、ランダムで応答が返ってきていることが確認できました。

おわりに

というわけで、Route53のシンプルルーティングの挙動確認でした。こんな感じで、次はフェイルオーバールーティング、加重ルーティングあたりの確認をしようかと思います。位置情報ルーティングや地理的近接性ルーティングも気になりますが、その辺はうまい確認方法があれば試してみたいと思います。

実は今回、Route53の設定と挙動確認は一瞬で終わったのですが、Route53以外の部分を慣れないCloudFormationで構築してみたところ、色々失敗してかなり手間取り、ほとんどの時間をそこに費やしました。ただ、おかげでCloudFormationの扱いには多少慣れました。

せっかくなので、CloudFormationで躓いた箇所についても、備忘として別途ブログに残したいと思います。

AWS Certified Advanced Networking - Specialty試験の振り返り

はじめに

先日、AWS Certified Advanced Networking - Specialty(以下、ANS)に合格しました。(スコアはギリギリでしたが。。)

f:id:YuY_83:20210905052439p:plain

試験対策として何をやったか、受けてみてどうだったか等を振り返り、備忘録として残したいと思います。「これさえやれば合格間違いない!」というものではありませんが、誰かにとって何らか参考になる事があれば幸いです。

なお、試験内容について記載することは規約違反のため、「具体的にこういう問題が出た」みたいな事はここでは記載しません。

(前提)私のスキル・知識

AWSを業務で使ったことはありません。2021年3月くらいからAWSの勉強を開始し、以下の資格を取得しました。

  • Solutions Architect - Associate(以下、SAA)
  • SysOps Administrator - Associate(以下、SOA

ネットワークに関しては、6,7年くらい業務で関わっていました。(最近は自分で手を動かす機会がめっきり減っていましたが。。)資格はネットワークスペシャリストCCNPを取得していました(CCNPはすでに失効)。そのため、ネットワークに関する基本的な知識はある状態でした。

試験対策期間

SOA合格後の2021年7月中旬から勉強を開始し、2021/9/2に受けたので、期間としては大体1.5ヵ月くらいです。

平日は仕事終わりに勉強していたため、仕事の繁忙によって1日の勉強時間は異なりますが、平均1~1.5時間くらいかなーと思います。

休日も予定の有無や体調、やる気で大分差がありますが、対策期間の前半は1日2~3時間、終盤は1日5~6時間くらいだったかと思います。

試験対策としてやったこと

試験対策としては主に以下を実施しました。

  1. AWS WEB問題集で学習しよう」で問題を解く。
  2. ネットワーク関連のBlackBelt資料を読む。


UdemyやAWS公式模擬試験は利用しませんでした。

AWS WEB問題集で学習しよう」

aws.koiwaclub.com

AWS WEB問題集で学習しよう」は、SAA、SOAの試験勉強でも利用しました。問題を解いて解説を読み、解説を読んでもよく分からない所はググったりBlackBert資料を読んだりして理解を深めました。

間違えた問題や、ちゃんと理解できていなかった問題は番号をメモしておき、2周目はメモした問題だけ解きました。さらに復習した方が良さそうな問題をメモして、合計3周しました。

これまでいくつかの資格試験を受けてきましたが、問題を繰り返し解くと記憶に定着しやすいと感じています。有料ですが、個人的には使って損はありませんでした。

BlacBelt資料

aws.amazon.com

AWS WEB問題集で学習しよう」はANSの問題がそこまで多くはないので、(全部で150問程度で、SAAやSOAと比べると大分少ない)BlackBelt資料も読むようにしました。
BlackBelt資料では、Networking & Content Deliveryカテゴリの内、以下の資料を読みました。


上記のサービスを選んだ理由は、カテゴリの中でも特にメジャーなサービスなので、出題頻度も多いかな、と思ったためです。

BlackBeltの内容はYouTubeで解説が聴けるものもありますが、私は自分のペースで読み進めたかったのでPDFを読んでいました。

また、読むだけだとなかなか頭に入らないので、自分でBlackBeltの内容から選択問題を作成し、それを解いたりしました。

こういったアウトプットは多少時間がかかりますが、記憶の定着が良いので、出来るだけインプットだけではなくアウトプットしながら学習したいと思ってはいます。

試験当日

試験は自宅で受験しました。SAA、SOAも自宅受験で今回3回目だったので、さすがに慣れてきていて、セッティングで焦ることはありませんでした。

ただ、試験時間をちゃんと確認しておらず、120分の試験だと思い込んでいたら実際には180分の試験で、これにはちょっと焦りました。。

というのも、その日は平日で仕事を抜けられる時間に限りがあり、試験開始の120分後には上司との1on1ミーティングが設定されていました。しかも試験を開始してしまっているので上司に連絡も出来ないので、もうとにかく120分以内に終わらせることにしました。

結果的には見直しも含めてギリギリ120分で終わりましたが、前半で結構時間を使ったため、途中はかなり焦りました。時間はちゃんと確認しとけって話ですね。。

終わった時は正直あまり自信はありませんでした。択一式なら大体2択には絞れるのですが、最後どっちだっけ?と悩む問題が結構あったような気がします。「合格」の2文字を見た時は思わず安堵のため息が出ました。

今回の反省点と良かった点

反省点

反省点は主に2点です。

  1. 試験時間を事前に把握しておくべきだった
  2. 試験ガイドの出題内容をもっとちゃんと確認しておきべきだった

1は当たり前の話ですね。。
2は、WEB問題集とBlackBeltを見れば何とかなるだろうと高を括ってあまりちゃんと確認しなかったのですが、自分があまり知らないサービスが出題内容になっていないか、くらいはもっとちゃんと見るべきだったなと思います。

良かった点

これは受かったから言えることかもしれませんが、「まだ準備が万全ではないかも」と思いつつ、思い切って受験してしまったのは良かったと思っています。

1.5ヵ月ANSの勉強をして、正直ちょっと飽きてきていたので、思い切って3日後くらいに試験をセッティングしてしまいました。

そこから当日までは気合を入れて勉強できたので、ダレないように締切を自分でセッティングするのも大事かな、と思いました。

今後の勉強について

今回の試験でスコアが悪かった分野

スコアレポートでは出題分野毎のスコアパフォーマンスが出ますが、今回は以下の2分野について「改善が必要」の判定でした。

  • 分野4:アプリケーションサービスとネットワークの連携を構成する
  • 分野5:ネットワークの管理、最適化、トラブルシューティングを行う

各分野の詳細な内容は以下ページの「試験ガイドのダウンロード」から確認できますので、そちらを参照してください。

aws.amazon.com

私は上記分野の中では、以下の内容についてあまり勉強してこなかったので、実際に使ったり調べたりして知見を増やしたいと思います。

  • VPCフローログ
  • CloudTrail
  • CloudWatch
  • 各種ヘルスチェック

比較的新しいネットワークサービス

ネットワークに関しては、比較的最近に以下のようなサービスが登場していますが、試験範囲には含まれていなそうだったので勉強していませんでした。

とはいえ、今後業務でAWSに携わるようになれば使う必要も出てくるかもしれないので、別途勉強したいと思います。

次に狙う資格

次はDVAを取って、アソシエイト3冠を達成したいと思います。

(オマケ)自宅受験について

自宅受験の際は、事前のシステムテストをちゃんとやった方が良い、と今回改めて思いました。

私は今回3回目の自宅受験で、過去2回も大きなトラブルはありませんでしたが、念のため、今回も事前にシステムテストを実施しました。
すると、「mDNSResponderというバックグラウンドプロセスが動いている」とのことでシステムエラーが出ました。(知らない人のために説明しておくと、自宅受験の際には余計なバックグラウンドプロセスを停止させる必要があるのです。)
しかし、タスクマネージャーをいくら確認しても、mDNSResponderというプロセスが見つからないのです。

そこでググってみると、mDNSResponderはWindows10のタスクマネージャーではBonjourという名前で表示されていることが分かりました。

もし事前にシステムテストをやっていなかったら、当日にこのエラーが出てきてもっとバタバタしていたに違いないし、最悪、試験が受けられなかったかもしれ ないと思うとゾッとしました。。

おわりに

やや取り留めのない振り返りになってしまいましたが、以上です。またDVAに受かったら振り返りを行いたいと思います。