はじめに
これは社内勉強会用に作成した資料です。
内容は口頭で説明することを前提として作りになっているので、内容が不足している部分があります。
目次
- IaCについて
- CloudFormationに取り組むモチベーション
- CloudFormation ? Terraform ? AWS CDK ?
- CloudFormationについて
- 今回作った環境
- 現状の設定の課題
- 注意事項
- 実際に構築する
- まとめ
IaCについて
IaCとは
簡単に言えばインフラ構成を設定ファイルやプログラミング言語等で表現すること
通常のコードと同様にバージョン管理する
基本的に再利用可能である
通常のコードのデプロイと同様、変更を反映する手順が単一になり、誤りが起きにくくなる
CloudFormationに取り組むモチベーション
- 単純に何回も同じ作業することを減らしたい
- 自分以外の人でも環境構築できるようにしたい
- よくある環境や設定の消し忘れとかなくしたい
- コード管理することでレビューしやすくして、インフラ担当以外にも触れる機会を増やしたい
- AWS自身が提供しているのでなくなることはなさそう
CloudFormation ? Terraform ? AWS CDK ?
単純にIaCにAWS環境で取り組む場合、いくつかのツールがある
- CloudFormation
- Terraform
- AWS CDK
CloudFormation
- aws cliを利用する
- 設定をjson / yamlで記載し、その内容を元にインフラを構築する
- yamlで記載すればコメントも残せる
- 本家にマニュアルがあるので困ったときに情報を探しやすい
- 最近一部の設定は既存リソースをimportできるようになった
Terraform
- HashiCorpが提供しているツール (https://www.terraform.io/)
- AWS意外にもGCPやAzureなどにも対応できる
- jsonのような形のtfファイルで設定を記載する
- 既存リソースの状況を取得して設定ファイルにすることができる
- 事前にどのような変更が行われるかcliで確認できる
- workspaceの概念で環境(prod/stage/dev)を分けることができそう
AWS CDK
- AWSから提供されているTypescript/javascriptやPythonでインフラを構築できるツール
個人的に使ってみた感想ではTerraformのほうが使い勝手がよかったように感じるが、
今回はCloudFormationを使ってみる。
CloudFormationについて
- stackという単位で設定を管理する
- 1つの設定(yaml)に対して1つ以上のstackが対応する
- stackは複数作成でき、異なるstackの内容を参照することができる
- stack A の設定をstack Bが使用している場合、内容に変更があると、stack Aは更新できない(クロススタック(後述)の場合連動して変更してはくれない)
設定ファイル例(yaml)
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
Project:
Type: String
Default: "Test"
Mappings:
RegionMap:
ap-northeast-1:
AZ: ['ap-northeast-1a','ap-northeast-1c']
ap-northeast-2:
AZ: ['ap-northeast-2a','ap-northeast-2c']
Resources:
VPC:
Type: AWS::EC2::VPC
DeletionPolicy: Retain
Properties:
CidrBlock: 10.10.0.0/16
Tags:
- Key: Name
Value: !Sub "${Project}vpc"
実行方法
aws cloudformation create-stack --stack-name test-stack \
--template-body file://./network.yaml
パラメータの指定
aws cloudformation **** --parameters ParameterKey=Name,ParameterValue=Hoge
設定ファイル内のパラメータの設定
Parameters:
Project:
Type: String
Default: "cfn-test-" # Defaultがない場合はコマンドラインで値を指定しないとエラーになる
AllowedValues: ["cfn-test-","hogehoge"]#許可する値
Mappings: #リージョンごとに異なるAMIの設定
RegionMap:
us-east-1:
"HVM64": "ami-0ff8a91507f77f867"
us-west-1:
"HVM64": "ami-0bdb828fd58c52235"
Metadata: #設定テンプレート
Instances:
Description: "Information about the instances"
他のstackで利用できるようにする
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.10.0.0/16
Output:
VPC:
Value: !Ref VPC
Export: { "Name" : !Sub "output-vpc"}
#{'Fn::ImportValue': !Sub "output-vpc"}で他のstackから参照できる
- 出力した値はManagementConsoleのcloudformationの出力で確認できる
設定ファイル内に出てくる関数
- Fn::GetAtt
- リソースの属性を指定するために使用.例) Arnなど
RoleArn: !GetAtt XXXRole.Arn
- Fn::FindInMap
- Mappingで定義した内容を参照するために使用
Mappings:
BuildNames:
Web:
Name: web
App:
Name: app
{ Value: { "Fn::FindInMap" : [ "BuildNames", "Web", "Name"]}}
- Fn::Sub
- sprintf的な感じで使える。またparameterの指定などの際にも利用する
Parameters:
Project:
Type: String
Default: "cfn-test-"
RoleName: !Sub "${Project}build-role" # cfn-test-build-role
Value:
!Sub
- "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ImageName}"
- { "ImageName": {'Fn::ImportValue': !Sub "${Project}ecr-web-image"}}
- Fn::ImportValue
- 他の設定ファイルで指定した値を参照する
Value: {'Fn::ImportValue': !Sub "${Project}test-output-value"}
ほかにもあるので詳しくは、、 https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
- Fn::Select
- リストから指定した添字の番号の値を参照する
AvailabilityZone: !Select
- 0
- Fn::GetAZs: !Ref 'AWS::Region'
** Fn::GetAZsは指定したリージョンのAZのリストを取得する関数
設定の構成例
- 単一のyaml
- 単一のyaml,パラメータの指定
- 複数のyaml(クロススタック)
- 複数のyaml(スタックのネスト)
単一のyaml
単一のyaml,パラメータの指定
複数のyaml(スタックのネスト)
- 今回試しに環境を作ってみて、スタックのネストが管理はしやすいと感じた
- ファイルを分割できること
- 他のスタックの内容を参照できる
- 指定したParameterをそれぞれのスタックに引き渡せること
実際に環境を作ってみる
今回試しに作る環境
デモ
今後の課題
-
CloudFormationで出来なかったDeploymentGroupの作成をCloudFormationで
-
ECS Serviceを更新すると、影響がデプロイの設定にもあるので同じstackにするなど連動するようにする
-
CodeBuild内でECS ClusterやServiceの指定を環境変数で行っているが、無理やり感があるのでスマートなやり方を探して改善
-
prod/staging/devなどの環境を分けることを考慮した内容にする(スタックのネストかな)
わかったこと
わかったこと
-
実際に自分でGUIでも構築してみること
- 当然だけど、、MangementConsoleとかで実際に構築したことがないと設定内容が理解できない
-
新しいリソースは対応していないので、全てをCloudFormationで管理しようとしない
-
updateする際にstack名を誤ると、もとの内容が消えるので注意
- Conditionで条件分岐させたときも同様
-
間違って消えると困るリソースはDeletionPolicyを指定すること
-
DeletionPolicyを設定していると、他のstackとの依存関係で削除できないこともある
わかったこと(続き)
-
本番で構築するときはupdate-stackではなく、create-change-set => execute-change-setで差分を確認して反映すること(terraformでいうplanで変更を確認すること)
-
構築時のエラー情報を確認するためには、結局ManagementConsoleみた方が早い
-
最初は手動であとから柔軟に対応するならTerraformのほうが便利そう
-
実際に構築したことないと、特に権限の設定の確認は難しい
-
バージョン管理できるので差分の確認(レビュー)がしやすくて良い
- コードを見れば内容がわかるのでManagementConsoleをみなくても良い
わかったこと(続き2)
-
リソースによって条件があるので要注意
- ECS Service名を指定している場合、CloudFormationではUpdateはできない??
-
他のstackで使用している出力の内容が変わる場合、updateはできない
- 更新するたびに内容がかわるようなものに関しては1つのCloudFormation stackにする
-
Parametersで名前を指定する場合でも、stackは別名にする必要がある。同名を指定すると上書きされる。
まとめ
まとめ
-
変更予定の確認等、正直terraformのほうがやりやすい部分がある
-
CloudFormationで全てやろうとしてもできない場合があるので、固執しない
- ECS (blue/greenデプロイ)はCloudFormation対応していない??参照
-
prod/staging/devを何でわけるのがベストかは要検討(region?vpc?アカウント?)
-
実際に自分でGUIで構築して内容を理解してからCloudFormationを使ったほうが理解しやすい
- 初めて触る場合はVPCやSubnetの設定で試すとやりやすい
-
最初に準備するのは大変(特に権限周り)だけど、1回準備してこまごまと修正するだけならそこまで大変ではないはず。。
-
いろいろ面倒はあるけど、レビューしやすい、共有しやすいなどメリットがあるので導入する価値はある