概要
ServerlessFrameworkを利用する中で、内部的にCloudFormationを利用していたので改めて調べてみたり、自分なりに「ここめっちゃいい!」と思ったところをまとめました
触り部分が多いので初心者向けの記事ですが読んでもらえればと思います
CloufFormationって
CloudFormationで利用するテンプレート(JSONもしくはYAML)にAWSリソースを記述することでテンプレートにしたがってリソースの作成・更新削除といった管理ができるサービスです
たとえばEC2を作成して、Apacheサーバーを建てて、ユーザーからもアクセスできるように...といった内容をAWSコンソールを利用せずにCloudFormationテンプレートを作成し、そのテンプレートファイルをデプロイすることで実行できます
個人的に感じるメリット
これはCloudFormationに限った話ではありませんが、CloudFormationはIaC(Infrastructure as Code)なのでそれらで述べられている特徴を持っています
特筆して感じるメリットとしては
「インフラ変更差分に対してメッセージを残しやすい」ことです
具体的な仕事の例を上げると
前提: EC2を利用してWebアプリケーションを管理している
一般ユーザーからも閲覧できる本番環境と
本番環境と同じ構成で社内アクセスのみを許可したステージング環境が存在する
対応依頼: 新しく入った開発パートナーさんにもステージング環境にアクセスできるようにしたい
対応方針: セキュリティグループに許可するIPアドレスを追加する
CloudFormationならコード管理できるため、Gitなどのバージョン管理でコメントや変更意図を含めて管理できます
そのため数年後に「このIPアドレスって誰が使っているものなのか」と発見したときにgit log
などから追跡が可能です
また再現性が持てるところも素晴らしいです
大量のユーザーアクセスを捌けるようなAPIGateway + SQS + LambdaといったようなServerless構成を自分がCloudFormationを利用して作成しました
友人にも同様のシステムを提供しようと思ったときにCloudFormationのテンプレートを共有するだけで各々のアカウントで同一のAWS構成が作られます
この再現性の部分をAWSコンソールで行おうとしたときに1つのミスもなく、まったく同一の構成にするのはとても難しいです
これはメモを用いずに居酒屋の10人席へ注文を伺い1つの誤りもなく注文を聞き取り、伝えるくらい難易度が高いです
また各種CloudFormationのテンプレートを利用してデプロイする単位はスタックといいます
(スタックは複数のAWSリソースを管理する単位のようなものと認識するほうが考えやすい)
どうやって使うのか
このスタックを作成する方法は大きく3つあります
- CloudFormationのテンプレートを自分で作成する
- サンプルテンプレートを利用する
- CloudFormationのデザイナーを利用してGUIで構成を作成する
個人的には1の自身でテンプレートを作成することが多いかと思います
実際に書いてみる
今回はサンプルとしてEC2上にapacheサーバーを建てて自分のパソコンからアクセスできるようにしてみましょう
下記のようなテンプレートを定義します
行っていることとしては
- Resourcesセクション内でAWSのリソースを作成している
- MyVPC
MySubnet
MyInternetGatewayなど...
- MyVPC
- 各種リソース名配下では[リソースタイプ名][リソースのプロパティ]を定義
- リソースタイプ名はドキュメントにすべて書いてある
- またリソースのプロパティはリソースごとに異なるのでこちらもドキュメントを見るのが一番良い
- Outputsセクション内でスタックが出力する項目について出力している
- 今回は MyVPCのvpcid MySubnetのsubnetIdを出力
-
!Ref
と記載することで同じテンプレート内で定義している他のリソースを参照-
VpcId: !Ref MyVPC
とすることでMyVPCのvpcIdに置き換わる - Ex)
VpcId: !Ref MyVPC
→VpcId: vpc-xxxxxxxx
-
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template to deploy an Apache server with a VPC.
Resources:
MyVPC:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: MyVPC
MySubnet:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.1.0/24
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: MySubnet
MyInternetGateway:
Type: 'AWS::EC2::InternetGateway'
GatewayAttachment:
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
VpcId: !Ref MyVPC
InternetGatewayId: !Ref MyInternetGateway
MyRouteTable:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref MyVPC
MyRoute:
Type: 'AWS::EC2::Route'
Properties:
RouteTableId: !Ref MyRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
SubnetRouteTableAssociation:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref MySubnet
RouteTableId: !Ref MyRouteTable
Outputs:
VPCId:
Description: The ID of the VPC
Value: !Ref MyVPC
SubnetId:
Description: The ID of the subnet
Value: !Ref MySubnet
実際にデプロイしてみる
# create-stack で template-bodyにあるファイルを元にCloudFormationでスタックを作成
$ aws cloudformation create-stack --stack-name VPCStack --template-body file://vpc-template.yaml
AWSコンソール上ではどのリソースがどんなステータスでどういう状況となっているかが確認できます
create-stackが成功するとスタックのステータスがCREATE_COMPLEATE
になり、コンソール上もしくはdescribe-stacks
の実行結果で確認できます
続いてEC2のデプロイを行いますがVPCのIDとSubnetのIDがほしいのでメモしておきます
describe-stacks
を実行してOutputsするように設定した各種IDを控えておきます
VPCIdはvpc-AAAAAAAAA
SubnetIdはsubnet-BBBBBBB
だとわかります
$ aws cloudformation describe-stacks --stack-name VPCStack
{
"Stacks": [
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:XXXXXX:stack/VPCStack/XXXX-YYY3-XXXX-XXXX-ZZZZZ",
"StackName": "VPCStack",
"Description": "CloudFormation template to deploy an Apache server with a VPC.",
"CreationTime": "2023-12-04T14:41:46.862000+00:00",
"RollbackConfiguration": {},
"StackStatus": "CREATE_COMPLETE",
"DisableRollback": false,
"NotificationARNs": [],
"Outputs": [
{
"OutputKey": "VPCId",
"OutputValue": "vpc-AAAAAAAAA",
"Description": "The ID of the VPC"
},
{
"OutputKey": "SubnetId",
"OutputValue": "subnet-BBBBBBB",
"Description": "The ID of the subnet"
}
].....
続いてApache用のCloudformationのテンプレートファイルを作成します
VPCのテンプレートと異なる点としてはParametersセクションが追加されています
これはコマンド実行時のオプションに値を渡せます
今回はVPCId
としているので --parameters ParameterKey=VPCId,ParameterValue=vpc-AAAAAAAAA
とすることで!Ref
で参照できます
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template to deploy an Apache server with restricted access.
Parameters:
VPCId:
Description: The ID of the VPC
Type: String
SubnetId:
Description: The ID of the subnet
Type: String
AllowedIPAddress:
Description: IP address allowed to access the Apache server.
Type: String
Resources:
MyInstance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: ami-012261b9035f8f938
InstanceType: t2.micro
SubnetId: !Ref SubnetId
SecurityGroupIds:
- Ref: InstanceSecurityGroup
UserData:
Fn::Base64: !Sub |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<html><body><h1>Welcome to Apache Server</h1></body></html>" > /var/www/html/index.html
InstanceSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: Enable SSH and HTTP access on the configured port
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref AllowedIPAddress
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: !Ref AllowedIPAddress
VpcId: !Ref VPCId
実際にデプロイしてみましょう
aws cloudformation create-stack \
--stack-name ApacheServerStack \
--template-body file://apache-server-template.yaml \
--parameters ParameterKey=VPCId,ParameterValue=vpc-AAAAAAAAA \
ParameterKey=SubnetId,ParameterValue=subnet-BBBBBBB \
ParameterKey=AllowedIPAddress,ParameterValue=127.0.0.1/32 # ここだけ自分のIPアドレスに変更する
デプロイが完了したらブラウザからEC2にアクセスするかcurlなどを叩いて確認しましょう
またCloudFormationのテンプレートを変更した場合はupdate-stack
, スタックで管理していたリソースが不要になったらdelete-stacks
を実行して適宜削除しましょう
終わり
ServerlessFramework経由でCloudFormationを利用することはありましたが、改めて確認してみました
各種templateはサンプルコードとして↓のリポジトリに載せています