Y_Yamashitaのブログ

勉強したことのアウトプット・メモ中心。たまに日記とか。

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で実施しました。