きっかけ
terraformは少々触ったことあるけど、AWSならCloudFormationがあり、どっちが良いんだろう?という素朴な疑問が出てきて、そもそもCloudFormation経験0じゃどうしようもないから触ってみようと思いました。
想定読者
自分です。人の記事を読んで備忘と整理のためにメモっております (`・ω・´)
ゴール
CloudFormationの雰囲気を知る。
入門する場所さがし
エンジニアとしては公式ドキュメントを最初にみるべきでしょ、というスタンスで見たのがココ。うーん、入門しづらい...。サンプルコードやCloudFormation Designerへのリンクがあるのは有り難いけど、結局英語ページでGetting Startedを読むことになるよこれだと。
できれば最初は母国語の入門記事を読みたいと思って最初に読んだのが 【CloudFormation入門1】5分と6行で始めるAWS CloudFormationテンプレートによるインフラ構築です。Googleの検索結果としてはCloudFormation超入門の方が上に来ていたけれど、記事として新しいし、何より"5分と6行"って具体的な数字が提示されていると読む気になりますよね。
入門し始めた
という訳で【CloudFormation入門1】5分と6行で始めるAWS CloudFormationテンプレートによるインフラ構築を読みつつ手を動かします。執筆者の濱田孝治さんの小粋な文章のおかげでサクサク読めますし、想定読者とゴールを文章の初めに出してくる所など、良い記事のお手本としても勉強になります。
まずはブラックベルトを読めということらしい
「まずは基本のBlackBeltから。」のコメントともにAWS Black Belt Online Seminar 2016 AWS CloudFormationへのリンクが大きく貼られているのでとりあえずクリックして開くと、90ページもある長大なスライドに少々気圧されますが、「ここでは基本的なCloudFormationの特徴(p4〜p19)あたりをみていただければ十分です。」と親切で優しいコメントでホッとしながらスライドを読みます。
スライドはAWSジャパンの益子直樹さんが作成されたとのこと。基本部分をざっと読んでいくと冒頭(p4-p10)だけで以下のことが分かってきます。
- 大規模環境作るならInfrastructure-as-codeでしょ
- AWSでそれ(Infra-as-code)やるならCloudFormationがあるぜ
- JSONやYAMLでテンプレートを作るんだ
- ベストプラクティスが盛り込まれたテンプレートが利用できるよ
- CloudFormation自体の利用は無料だよ
興味深いのはp11の"AWSから提供されているデプロイ&マネージメント関連サービス"という図。 いわゆるCode3兄弟(Code Commit,Code Pipeline,Code Deploy)やBeanstalkなども並べた上で、CloudFarmationの位置付けが"Provision"であることが明確に分かります。この図を見ることが出来ただけでも僕としては大満足な資料でした。
さらにProvisionという位置での比較も行われており、
- 導入の容易さ
- Elastic Beanstalk > OpsWorks > CloudFormation
- フレキシビリティ
- Elastic Beanstalk < OpsWorks < CloudFormation
CloudFormationが「簡単じゃないけど柔軟性がパない」サービスらしいことが分かります。そのままp90までスライドを読み進めるたくなりましたが、何はともあれ手を動かせよという心の声に従い濱田さんの記事に戻ります。
濱田さんの解説でCloudFormationを理解していく
記事では益子さんのスライドのポイント部分を引用しながら解説されています。「サービスごとの位置づけが俯瞰できるこういうスライドは、頭が整理されて非常にありがたい。」というコメントには何度も頷きつつ、テンプレートとスタックという用語について理解を進めます。
この時点では理解しました。
いざ初めてのCloudFormationでのデプロイ!
「一昔前は、テンプレートはJSONのみ対応で人間が編集するには辛いものがあったのですが、YAML対応により、簡単に人間の手でも設定ファイルを編集できるようになりました。素晴らしい!」とありますので、今後はYAML一択なんだと納得しつつサンプルファイルをコピペします。※引用元
AWSTemplateFormatVersion: '2010-09-09' Resources: FirstVPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16
ここでタイトルの6行のテンプレートを放り込みます。ぽちぽちと5クリックほどでVPCを作成することができました。
テンプレートの中身を理解する
6行のVPC作成テンプレートの解説を読みます。6行なので怖くありませんし、モチベーションも下がらずありがたいです。公式ドキュメントへのリンクもあり、この時点でやっと日本語公式ドキュメントの存在を知ります。(日本語のCloudFormation紹介ページから日本語CloudFormationユーザガイドへの導線が無いんじゃ...?)
AWSTemplateFormatVersion
AWSTemplateFormatVersionについてはお作法とのことで、そういうものとして納得します。任意項目のようですが将来バージョン更新が入る可能性を考えると記載しておいたほうが良さそうです。これで6行の中の1行について理解できました。
Resouces
Resourcesが利用したいAWS上のサービスを記載するところです。6行の中の5行を占めていますからメインの部分であることは間違いありません。※引用元
Resources: <Logical ID>: Type: <Resource type> Properties: <Set of properties...>
Logical ID
Logical IDにはテンプレート内でユニークな名前を記載します。このあたりは企業・プロジェクトの文化に依存するところですね。 なおここでいうテンプレート内というのは1つのyamlファイル内という意味のようで、試しに別ファイルへ同名のLogical IDを利用しても競合はしませんでした。
Resource type
Resource typeに具体的なサービスを書いていくそうです。 AWS リソースプロパティタイプのリファレンスへのリンクが紹介されています。以下のようなリソースが大量に(この時点では241個)記載されており、今後もサービス増加に合わせて増えて行くことでしょう。
ネーミングルールは「AWS::<サービス名>::<サービス要素(正しい言葉が不明)>」という形のようですね。
せっかくなのでサービスごとにいくつの要素があるかを確認してみました。
> awk -F':' '{print $3}' cf-resouces.txt | uniq -c 18 ApiGateway 2 ApplicationAutoScaling 1 Athena 5 AutoScaling 3 Batch 1 CertificateManager 7 CloudFormation 3 CloudFront 1 CloudTrail 2 CloudWatch 1 CodeBuild 1 CodeCommit 3 CodeDeploy 2 CodePipeline 7 Cognito 3 Config 1 DataPipeline 3 DAX 2 DirectoryService 6 DMS 1 DynamoDB 38 EC2 1 ECR 3 ECS 2 EFS 6 ElastiCache 4 ElasticBeanstalk 1 ElasticLoadBalancing 5 ElasticLoadBalancingV2 1 Elasticsearch 5 EMR 1 Events 3 GameLift 9 Glue 8 IAM 6 IoT 1 Kinesis 3 KinesisAnalytics 1 KinesisFirehose 2 KMS 5 Lambda 5 Logs 7 OpsWorks 9 RDS 5 Redshift 4 Route53 2 S3 1 SDB 3 SNS 2 SQS 7 SSM 2 StepFunctions 7 WAF 8 WAFRegional 1 WorkSpaces
ダントツで38個も要素を持つEC2が多いですね。次点は18個のApiGatewayでした。EC2でできること沢山あるんだなぁという小並感を持ちます。
Resource properties
前述した各Resourceに指定するプロパティです。「公式ドキュメントとにらめっこしながら、指定していきます。」とのことです。
あれこれって?Ansibleでやったことあるやつじゃん?
ここまでやって強烈な既視感を覚えます。そう、Ansibleでさんざんやってきたことと同じなのです。
僕は日頃からサーバ構成をAnsibleで行っています。AnsibleではplaybookというこれまたYAMLファイルを利用しており、運用の流れとしては
- やりたいことを決める(ファイルコピー、パッケージインストール等)
- モジュールを選ぶ
- モジュールの公式ドキュメントを見ながら必要なパラメタを選ぶ
- YAMLにひたすら落とし込む
- テスト機で検証
- 本番機へデプロイ
となります。この流れがCloudFormationにもそのまま適応できそうです。つまり重要なのはCloudFormationに詳しい云々の前に、AWS上で何をしたいか(プロビジョンしたいか)をちゃんと決めるということで、AWSの知識が前提とされていることがよくわかりました。(今更)
ちょっとそれっぽい構成をデプロイ
入門3 「VPCにサブネットやルーティングテーブルやインターネットゲートウェイを構築する」 でVPCだけではなく、VPCに必要なインターネットゲートウェイなども含むテンプレートをデプロイします。構成図もきちんと載せてくれていますのでイメージもしやすいです。濱田さんマジありがとう。以下がコードになります。※引用元
AWSTemplateFormatVersion: '2010-09-09' Resources: FirstVPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 Tags: - Key: Name Value: FirstVPC InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: FirstVPC-IGW AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref FirstVPC InternetGatewayId: !Ref InternetGateway FrontendRouteTable: Type: AWS::EC2::RouteTable DependsOn: AttachGateway Properties: VpcId: !Ref FirstVPC Tags: - Key: Name Value: FirstVPC-FrontendRoute FrontendRoute: Type: AWS::EC2::Route DependsOn: AttachGateway Properties: RouteTableId: !Ref FrontendRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway FrontendSubnet: Type: AWS::EC2::Subnet DependsOn: AttachGateway Properties: CidrBlock: 10.0.1.0/24 MapPublicIpOnLaunch: 'true' VpcId: !Ref FirstVPC Tags: - Key: Name Value: FirstVPC-FrontendSubnet FrontendSubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref FrontendSubnet RouteTableId: !Ref FrontendRouteTable
6行から50行に大幅ボリュームアップしていますが、Ansibleで鍛えたYAML力を発揮して読んでいきます。僕自身への読み方のコツを備忘でメモしておくと、
- とりあえずType行だけ抜いて(grepして)全体構成を把握
- 各リソースの構成はTypeで何のリソースに記述しているかを確認
- Resouce IDは任意の文字列を人間が決めているのでWhyやwhatを読み取る(できれば)
- 落ち着いて(必要なら公式ドキュメントを開き)プロパティを読んでいく
というところです。今後本格的にCloudFormationを使っていくうちに変わるかもしれないですが、Type行だけ抜くのは初めて読むテンプレートを理解するのに良いやり方じゃないかなと思ったりします。50行が7行に一旦落とし込めるし。
Type: AWS::EC2::VPC Type: AWS::EC2::InternetGateway Type: AWS::EC2::VPCGatewayAttachment Type: AWS::EC2::RouteTable Type: AWS::EC2::Route Type: AWS::EC2::Subnet Type: AWS::EC2::SubnetRouteTableAssociation
わおシンプル><
組み込み関数
6行サンプルには無かったものとして、組み込み関数"!Ref"についての解説がされています。
... AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref FirstVPC #<-コレ InternetGatewayId: !Ref InternetGateway ...
構築するまでは分からないリソースIDを!Ref <Logical ID>
という形で表現するそうです。濱田さんも 「こういうふうに関連するリソースが多々あるものについては、一つのテンプレートファイルにまとめて、リソースIDを!Refで参照させるのが、CloudFormationテンプレートを作成するときの重要なお作法。」 と書いておりました。他にもいくつかの組み込み関数があるそうですので公式ドキュメントをご参照くださいとのこと。現在の組み込み関数は以下の通り。
- Fn::Base64
- 条件関数(And,Equals,if,Not,Orなど)
- Fn::FindInMap
- Fn::GetAtt
- Fn::GetAZs
- Fn::ImportValue
- Fn::Join
- Fn::Select
- Fn::Split
- Fn::Sub
- Ref
上のFn::hoge
という書き方は、YAMLの場合は短縮形の!hoge
と書くこともでき、サンプルは専ら短縮形なので混乱しないよう注意しましょう。(僕は混乱した)
DependsOnで依存関係を明示
続いてDependsOn属性についての説明があります。!Refを使用すると暗黙的な依存関係が適用されるそうですが、DpendsOn属性を使えば明示的に宣言できるとのこと。
FrontendRouteTable: Type: AWS::EC2::RouteTable DependsOn: AttachGateway #<-コレ Properties:
「記事のまとめと、今後の学習指針」を読んでのまとめ
サブネットやルーティングを備えたちゃんとしたVPCを作成できた達成感に浸りながら(濱田さん製サンプルYAMLを流し込んだだけですが)濱田さんのまとめを読みます。
最小構成で始めて基礎を理解していくことがオススメと理解しました。効率の良い学び方も提示されていて大変ありがたい。(具体的な項目は今日何度目かわかりませんが元記事を参照)
そしてDevelopers.IOのCloudFormation関連のカテゴリへのリンクがあり、興味深い記事が多くあることを知りました。それらの記事も目を通して行きたいと思いましたし、続編の 【CloudFormation入門2】テンプレート作成を効率化するバリデーション機能と自動実行シェルの紹介の記事があることも発見しました。益子さんのブラックベルトスライドもきちんと読んで理解したいところ。
今後も「俺のCloudFormation道は始まったばかりだぜ!」な意気込みで触りながら理解を深めて行きたいと思います。そして最後に濱田孝治さんの【CloudFormation入門1】5分と6行で始めるAWS CloudFormationテンプレートによるインフラ構築は本当に良記事なのでCloudFormation入門者は皆読んで幸せになって欲しい!おすすめですよ。