はじめに
AWSでサーバレスの開発をするにはSAMを使うという記事や話を聞いたことがある人は多いと思います。じゃあ、自分もSAMでやってみようと思ってやってはみたものの、SAMのテンプレートが書けない!って挫折した人が少なからずいると思います。私もその一人でした。おそらく、そのような人は、AWS CloudFormation のテンプレートを書いたことがない人だと思います。
実は、SAMのテンプレートは、CloudFormationテンプレートの拡張です。AWS SAM Template Basicsに、このように書かれています。
AWS SAM templates are an extension of AWS CloudFormation templates. That is, any resource that you can declare in an AWS CloudFormation template you can also declare in an AWS SAM template. In addition, you can use the additional resource types provided by AWS SAM—for instance, the resources described in Declaring Serverless Resources—as shortcuts for some components of your serverless application.
Google翻訳してもらうと、こうなります。
AWS SAMテンプレートは、AWS CloudFormationテンプレートの拡張です。つまり、AWS CloudFormationテンプレートで宣言できるリソースであれば、AWS SAMテンプレートでも宣言できます。さらに、AWS SAMが提供する追加のリソースタイプ(サーバーレスリソースの宣言で説明されているリソースなど)を、サーバーレスアプリケーションの一部のコンポーネントのショートカットとして使用できます。
また、このすぐ下にもこのように記述があります。
For an introduction to AWS CloudFormation templates, see Learn Template Basics.
Learn Template Basics
のリンク先が、CloudFormationのページにリンクが貼ってあるのです。CloudFormationのテンプレートが書ければ、SAMのテンプレートもかけるでしょう!ということで、AWS SAMを使う前にCloudFormationテンプレートを書こうと題して、私が、CloudFormationのテンプレートを書き始めた時のことを纏めてみました。
事前にやっておくこと
まずは以下のページを読んで雰囲気をつかみましょう
- Back Belt
- 【CloudFormation入門1】5分と6行で始めるAWS CloudFormationテンプレートによるインフラ構築
- (2017年12月時点) 私的 CloudFormation ベストプラクティス
権限があることを確認しよう
- AWSアカウントの管理をしてない人は管理者に確認しましょう。もし、権限がもらえない場合はここで終了です
- 権限については、BlackBeltの82〜84スライドを参照しましょう
テンプレートを記述する環境を整えます
インストールする必要があるもの
- AWS CLI
- VS Code
- 別のエディタでもよいですが、みんなが使っていると思うので。。。
- VS Code 拡張機能:CloudFormation
そのほかにやっておくこと
- CloudFormationで管理したいサービスをConsole(GUI)で弄っておきましょう。一度も触ったことがないサービスをCloudFormationのテンプレートを書くのは難しいと思います。
- CloudFormationのテンプレートは、YAMLもしくはJSONで記述できますが、YAMLのほうが書きやすいと思います。もし、YAMLの書式を知らない場合はぐぐっておきましょう。
まず簡単に作れるサービスから書いてみる
-
準備ができたら、まずはテンプレートを書いてみましょう。Lambda FunctionをCloudFormationテンプレートで記述するとちょっと面倒です。なので、まずはS3のように簡単に作れるサービスから記述するとよいと思います。(どのサービスも最初に細かい設定をするとどれもめんどいです。そこを誤解しないでくださいね)
-
VSCodeで新規ファイルを作成し、言語モードをYAMLにしておきます。もしくは、sample.ymlで保存しておきます。
このように候補が出てくるので、s3-bucket
を選択します。そうすると、以下のようになります。機能拡張さまさまです。
- 初回なのでまずは必須のところだけにしてみます
AWSTemplateFormatVersion: 2010-09-09
Description: >
Sample template
Resources:
s3Bucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: BucketOwnerFullControl
BucketName: (ここは一意になる名前を入力)
機能拡張は、Bucketname
で書き出されますが、BucketName
が正解なのでご注意ください。
デプロイしてみます
デプロイは簡単です。
aws cloudformation deploy --template-file template.yml --stack-name sample-s3-0121
テンプレートファイルとスタック名を指定するだけです。
これで問題がなければ、
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - sample-s3-0121
と表示されます。ここで、バケットの一覧を確認してみると、作成できていることが確認できると思います。
テンプレートを書くために最低限知っておくべきこと
戻り値
サービスによっては、他サービスのARNを指定するようなことがあります。そのような場合は戻り値を使います。例えば、Lambda FunctionをRoleを指定するようなときは、Role: !GetAtt iamRole.Arn
のように指定します。「iamRole」部は、論理 IDで指定したIDになります。
戻り値で何が取得できるのかは、AWS リソースプロパティタイプのリファレンスに記述があるので、そこを参照しましょう
組み込み関数
テンプレート内で関数を使うことができます。最低でも、!Sub
と!Ref
、!GetAtt
は使うことになると思います。
# Lambda関数名が展開される
LogGroupName: !Sub /aws/lambda/${lambdaFunction}
# パラメータを取得する
Bucket: !Ref LogBucket
# 属性値を取得する
DomainName: !GetAtt S3Bucket.DomainName
最初のうちはこの3つがわかっていればなんとかなると思います。
パラメータ
固有の値はテンプレートに書くべきではありません。再利用する際に変更が必要だし、Githubにあげた時などに事故につながることが考えられます。そのような値にはパラメータを使いましょう。
Parameters:
MyBucketName:
Type: String
Environment:
Type: String
AllowedValues:
- dev
- stg
- prod
Default: dev
このように定義を行い、
aws cloudformation deploy --parameter-overrides MyBucketName="hogehoge"
というようにパラメータを渡しましょう
ハマるポイントと解決策
ここまでできれば、後は、テンプレートをいろいろ書いてみるだけです!
ここからは、私が書いた時にハマったポイントです。
初回のdeployからエラーとなり、テンプレートを更新してからdeployしたけど、以下のエラーが表示される
An error occurred (ValidationError) when calling the CreateChangeSet operation: Stack:arn:aws:cloudformation:ap-northeast-1:***:stack/sample-s3-0121/5ffdf040-1d69-11e9-9f4f-0ec110ab8a1e is in ROLLBACK_COMPLETE state and can not be updated.
こんな時は、stackを削除してからdeployしましょう。削除するには、aws cloudformation delete-stack --stack-name hogehoge
で削除できます。
UPDATE_FAILEDになるけど、テンプレートのどこが悪いのかわからない
CloudFormationのステータスをコンソールから確認している場合、FAILになった理由は表示されるけど、どこが悪いのかわからないことがあります。よくあったのが、関数を多用していて、関数が処理された後のテンプレートは見れないためどこが悪いんだよ〜という場合です。このような時には、コマンドを叩いて、関数が処理されたテンプレートを確認しましょう。
aws cloudformation describe-stack-events --stack-name {stack名} | grep "UPDATE_FAILED"
grepをかけないと、ROLLBACKされた正しいテンプレートも表示されるので注意しましょう。
何を指定していいのかわからない
同じサービスで既に動かしているものがあれば、コマンドでconfigを表示してみるとわかると思います。例えば、ClooudFrontのテンプレートを書いていてわからない時には、aws cloudfront get-distribution-config --id hogehoge
です。
それでもわからない場合は、以下は参照しましょう
- 各サービスのAPIリファレンス
- ActionsとData Typesは参照する場合があります。
- ガイドとAPIリファレンス
- グーグル先生で検索
- 検索すればいろいろとでてきます。それらを参照しましょう。
テンプレートのチェックがOKでも、FAILすることがある
テンプレートの文法がOKでも、deployした時にFAILすることがあります。そういうものです。
aws cloudformation validate-template --template-body file://template.yaml
validate-template
に過度な期待をしないようにしましょう。
参照するページ
私がよく見るページをまとめました
リファレンス
- テンプレートリファレンス
- テンプレートの分析
- CloudFormationの条件関数を利用する
-
AWS ドキュメント | AWS
- 各サービスのAPIリファレンス
サンプルやTips
更新情報
-
Release History
- 日本語のページは更新が遅いようなので、最新情報は英語版のページで確認しましょう
最後に
CloudFormationテンプレートの書き始めるために必要な点だけまとめました。書き慣れてないうちは、試行錯誤が続くことがありますが、検索すればいろいろと出てきます。皆さんの情報を参考しつつ、根気よく書き続けましょう。
AWS CDK
まだ使ったことがありませんが、AWS CDKというものがあります。これにより、テンプレートを書く必要がなくなるかもしれませんね。。。