知っておきたかったAWS SAM の小ネタ4選

Pocket

これは TECHSCORE Advent Calendar 2018 の7日目の記事です。

こんにちは、土屋です。
今年1月に AWS Lambda が Go のサポートを開始しましたね。
Gopher たちが賑わう中、私も Go のアプリを Lambda で作りたいなあと思い、 AWS SAMを使って環境構築をしてみました。

環境構築はチャチャッと終わらせたい!と思いつつも、実際にSAMを使ってみると、自分がやりたいことを実現する方法がわからず、調べるのに意外に時間がかかってしまいました。

そこで今回は「先に知ってればもっと工数削減できたなー」と思った、AWS SAM に関する小ネタを4つをまとめました。

※AWS SAM は公式ドキュメントの Benefits of Using AWS SAM に書かれている通り、AWS CloudFormation の拡張です。本記事の内容は、CloudFormation にも当てはめることができます。

1. テンプレート内で環境ごとに異なる値を渡したい

開発環境と本番環境はできるだけ同じ条件にしたいものですが、どうしても環境ごとに異なる値を渡したいこともありますよね。
「環境ごとにテンプレートファイルを作る!」という方法でも解決できますが、ほぼ同じファイルの内容をいくつも管理することになりますし、開発環境のテンプレートで行った変更を本番環境のテンプレートに反映し忘れていた...などのリスクを考えるとあまり嬉しくないです。
そんな時は ParametersMappings を使うと便利です。

ざっくりとした使い方は

  1. Parameters で環境のリストを作成
  2. Mappings でリストごとにマップを定義
  3. マップの値を使いたい箇所で埋め込み
  4. 環境を指定してデプロイ

という流れになります。

例として環境ごとに異なるアラートの通知先を SNS に設定してみます。
まず Parameters を使った環境のリストは次のように定義します。ここでは開発環境、ステージング環境、本番環境を用意してみました。

Mappings は次のように定義します。ここでは環境ごとに通知先を設定しています。

使いたい箇所に FindInMap を使って値を埋め込みます。ここでは SNS のエンドポイントとして、アラート先を設定しています。

あとはデプロイ時に --parameter-overrides を使って環境を指定すればOKです。

2. テンプレート内でAWSのアカウントIDを埋め込みたい

環境ごとにAWSアカウントを作成して、1つのテンプレートファイルで管理したい時、サービスの名前を同じにしておけば、AWSのアカウントIDを変更するだけでアクセスすることができます。

例) AとBのアカウントでそれぞれ sample.fifo という名前のSQSを定義した場合

  • https://sqs.ap-northeast-1.amazonaws.com/[AのアカウントID]/sample.fifo
  • https://sqs.ap-northeast-1.amazonaws.com/[BのアカウントID]/sample.fifo

でアクセスすることできます。

このような場合のテンプレート内のアカウントIDの指定方法として、公式ドキュメントのマッピングなしの Fn::Subにスッキリと書く方法が紹介されています。
環境ごとに異なる sample.fifo という SQS にアクセスするなら、次のように指定します。

ただしアカウントIDは、デプロイ前に設定する aws configure で指定したIAMユーザーのアカウントに依存するため、環境ごとにデプロイ用のIAMユーザーを作成し、 aws configure でデプロイ前に設定する必要があります。
デプロイ用のIAMユーザーとは異なるアカウントIDを指定したい場合は、先に紹介した Parameters と Mappings を使って、アカウントIDを埋め込む方法が良いと思います。

3. テンプレート内でロール名を指定してロールを定義したい

実際にハマったことなのですが、テンプレートでロールを定義する際にロール名を指定してデプロイすると、設定は間違えていないのに、なぜかデプロイできなかったことがありました。
原因はデプロイ時に --capabilities の値に "CAPABILITY_NAMED_IAM" を指定していなかったからでした。

公式ドキュメントのAWS CloudFormation テンプレートでの IAM リソースの承認を見ると、CloudFormation の仕様として、AWSアカウントのアクセス権限に影響するリソース(Roleの作成など)を含む可能性があるテンプレートを指定する場合、明示的に --capabilities を使ってテンプレート機能の承認を行う必要があります。
渡す値は、通常 "CAPABILITY_IAM" で問題ないのですが、今回のように自分でRole名をつける場合、 "CAPABILITY_NAMED_IAM" を渡さなければなりません。

公式ドキュメントの RoleName の説明に CAPABILITY_NAMED_IAM を指定するよう記載があり、完全に見逃していただけなのですが、ググるとロールの定義でハマった記事が多くヒットしたので、意外にここの設定を忘れている人は多いのかもしれません...

4. デプロイ失敗時のログを見やすくしたい

例えば sample という stack 名を指定してデプロイした際に、デプロイに失敗すると "aws cloudformation describe-stack-events --stack-name sample" というメッセージがターミナルに表示されます。
「このコマンドを実行して stack のイベントを見て原因を見つけてね」ということなのですが、そのまま実行すると、次のように全てのイベント情報が表示されます。

デプロイに失敗した時(上記の例では CREATE_FAILED した時)だけの理由だけを知りたいのに、情報が多すぎて見るのが少し辛いですね...

そこで、次のように jq を使って失敗した箇所だけ表示されるよう実行すると、いい感じに表示されます。

※--stack-name と ResourceStatus で指定する値(上記の sample や CREATE_FAILED)は、実行時の状態に応じて変更してください。

最後に

今回の記事では

  • Parameters と Mappings を使用した値の渡し方
  • マッピングを使わない Fn::Sub の使い方
  • ロール名を指定したロール定義のデプロイ方法
  • デプロイ失敗時にのエラーメッセージだけ表示する方法

を紹介しました。
実際に AWS SAM を使ってみて、テンプレートの書き方など、慣れるまでに少し時間がかかってしまいましたが、一度慣れると気軽に設定を変更できて使いやすいと思いました。
リリースノートを見ると、執筆している現在もどんどんアップデートされていますし、環境構築でAWS SAMを使ったことがない人は、試しに使ってみてはいかがでしょうか。

最後まで読んでいただきありがとうございました。

Pocket

Comments are closed, but you can leave a trackback: Trackback URL.