What's CloudFormation?
AWSのクラウドリソースをコードで表現してプロビジョニングできるようにする仕組み。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/Welcome.html
要するに Infrastructure as Code(IaC)。記述形式は JSON or YAML。
似たようなサービスには terraform, cdk などがある。
利点
- インフラストラクチャをコードとして扱える
- コードとして扱えればメンテナンス性が向上する
- ちょっと頑張ればデプロイを自動化できる
主なテンプレート解説
超入門なので一部割愛。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-anatomy.html
# フォーマットのバージョン(yyyy-mm-dd)を指定する
AWSTemplateFormatVersion: "version date"
# Stack 作成・更新時に受け取る値
Parameters:
set of parameters
# リソースの定義(EC2,RDS...etc
Resources:
set of resources
# リソースの生成結果等をエクスポートする
Outputs:
set of outputs
Sample
事前準備
あとで動作確認するためにEC2にSSHしたいので KeyPair を事前に作っておくこと。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-services-ec2-keypairs.html
Stack作るときにも参照する。
やること
- VPC作成
- VPC内にEC2を立ち上げてインターネットに接続できるようにする
- EC2に強めの Instance Profile をアタッチする
- なんとなくS3
モノリシックな定義
※!Ref と Ref: が混在してるけど同じなので気にしない。
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
KeyPairParam:
Type: AWS::EC2::KeyPair::KeyName
Default: thorikoshi
ImageId:
Type: AWS::EC2::Image::Id
Default: ami-0064e711cbc7a825e
InstanceTypeParam:
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- m1.small
- m1.large
Description: Enter t2.micro, m1.small, or m1.large. Default is t2.micro.
S3BucketNameParam:
Type: String
Default: thorikoshi
Resources:
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: "10.0.0.0/16"
InstanceTenancy: "default"
Tags:
- Key: Name
Value: MyVPC
MyInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: "MyInternetGateway"
MyVpcGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref MyInternetGateway
VpcId: !Ref MyVPC
MyRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: "MyRouteTable"
MyRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref MyRouteTable
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref MyInternetGateway
MySubnet:
Type: AWS::EC2::Subnet
Properties:
MapPublicIpOnLaunch: True
AvailabilityZone: "ap-northeast-1a"
CidrBlock: "10.0.1.0/24"
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: MySubnet
MySubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyRouteTable
SubnetId: !Ref MySubnet
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: MySecurityGroup
GroupName: MySecurityGroup
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
SecurityGroupEgress:
- IpProtocol: -1
FromPort: -1
ToPort: -1
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: MySecurityGroup
VpcId: !Ref MyVPC
MyRole:
Type: AWS::IAM::Role
Properties:
RoleName: MyRoleToInstanceProfile
AssumeRolePolicyDocument:
Statement:
- Effect: "Allow"
Action: "sts:AssumeRole"
Principal:
Service:
- "ec2.amazonaws.com"
Policies:
- PolicyName: MyPolicy
PolicyDocument:
Statement:
- Sid: MyUserStmt
Effect: Allow
NotAction: "iam:*"
Resource: "*"
MyAccessPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: MyAccessPolicy
PolicyDocument:
Statement:
- Sid: MyRoleStmt
Effect: Allow
Action: "*"
Resource: "*"
Roles:
- Ref: MyRole
MyInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: "/"
Roles:
- Ref: MyRole
MyInstance:
Type: AWS::EC2::Instance
Properties:
IamInstanceProfile: !Ref MyInstanceProfile
ImageId:
Ref: ImageId
InstanceType:
Ref: InstanceTypeParam
SecurityGroupIds:
- Ref: MySecurityGroup
SubnetId: !Ref MySubnet
KeyName:
Ref: KeyPairParam
Tags:
- Key: Name
Value: MyInstance
MyEIP:
Type: AWS::EC2::EIP
Properties:
InstanceId: !Ref MyInstance
MyS3:
Type: AWS::S3::Bucket
Properties:
BucketName:
Ref: S3BucketNameParam
Stack の作成
$ aws cloudformation create-stack \
--stack-name {{ Your stack name }} --template-body file://$PWD/main.yaml \
--parameters ParameterKey=S3BucketNameParam,ParameterValue={{ Your bucket name }}
--capabilities CAPABILITY_NAMED_IAM
もしくは
aws cloudformation deploy \
--template $PWD/main.yaml \
--stack-name {{ Your stack name }} \
--capabilities CAPABILITY_NAMED_IAM
もしくは Web コンソールから...。
動作確認
$ ssh -i /path/to/secret-key.pem ec2-user@{{ Created EIP }}
$ aws s3 ls
// Output your backet name
Stack 間のリソース参照
Cross Stack Reference
Outputs で Export した結果を参照する。
以下は Export した IAM Role を使用して Instance Profile を定義する Stack 間参照
IAM Role の Stack
AWSTemplateFormatVersion: "2010-09-09"
Resources:
MyRole:
Type: AWS::IAM::Role
Properties:
RoleName: MyRole
AssumeRolePolicyDocument:
Statement:
- Effect: "Allow"
Action: "sts:AssumeRole"
Principal:
Service:
- "ec2.amazonaws.com"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonRoute53FullAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
MyFullAccessPolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: MyFullAccessPolicy
PolicyDocument:
Statement:
- Sid: MyRoleStmt
Effect: Allow
Action: "*"
Resource: "*"
Roles:
- Ref: MyRole
# Instance Profile の Name を Export
Outputs:
MyRoleName:
Description: The name of My Role
Value:
Ref: MyRole
Export:
Name: MyRole:NAME
Instance Profile の Stack
AWSTemplateFormatVersion: "2010-09-09"
Resources:
# !importValue KeyName で参照
MyProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: "/"
Roles:
- !ImportValue MyRole:NAME
Note
試してないがパラメータストアにあらかじめ登録された値を参照するという作戦もあるらしい。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/dynamic-references.html
テンプレートの再利用
AWS::CloudFormation::Stack
AWS::CloudFormation::Stack
というリソース定義がある。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-stack.html
S3にテンプレート配置しておいてそれを Stack の定義として再利用できる仕組み。
分割した Stack の統合が可能になる。
あと始末
作成した Stack はいらないなら消しましょう(差もないと請求が来るでしょう)。
$ aws cloudformation delete-stack --stack-name {{ Your stack name }}