☝️

EC2の冗長構成をクリック一発で作りたい【AWS CloudFormation】

2021/01/25に公開

環境構築はCloudFormationで自動化だ!

AWSで環境をつくっていて、今どういったインスタンスがどの設定で動いているのか気がつけばわからなくなることがザラにあります。
このEC2何者?とか、このサブネット何用?とか

でも、CloudFormationなら大丈夫!

環境とテンプレートがイコールなので「こいつ何者?」がなくなる。
非インフラエンジニアからしてみればプログラム感覚で作れるので飲み込みやすいし(個人的な感覚)、AWSドキュメントを眺めるとコンソール上で見たことない(または見逃している)設定などもあって新たな発見もある。

ということで、冗長構成をCloudFormationで作る。

※時間の関係でテンプレートはシングルスタック。DBは無しの状態です。また時間ができたら作ります。

構成

アプリケーション用のサーバーがprivate subnetへ配置され、AutoScalingするという構成。
AWSCloudTech内のハンズオン「冗長性のあるブログサービスを構築する」を参考にしています。)

個人的にログが見れないと嫌なのでcfnのログをCloudwatchで出力するようにしている。

CloudFormationとは

作る前にざっくりとCloudFormationとは
・テンプレートファイルを元にAWSの環境を構築してくれるAWSサービスの一つ

テンプレートファイルってどんなん?
・テンプレートファイルはYAMLまたはJSON形式で指定の書式がある
・簡単な関数や環境変数などが用意されていて使うことができる

書式ざっくり説明。

セクション 内容
AWSTemplateFormatVersion バージョン情報(2010-09-09が最新)
Description テンプレートの説明
Metadata 追加情報を定義できる。(よくわかってない)
Parameters パラメーターを定義できる。例えば、VPCの範囲など
Mappings キーバリューのリストみたいなものを定義できる。
Conditions 条件を定義できる。例えば、開発環境向けとか本番向けなど
Transform サーバレスアプリケーションのバージョン指定とかできる。
Resources リソースを定義できる。例えば、EC2をXXというImageIDで作成するとか
Outputs 情報を出力できる。単純なリソースの情報出力と、リソース自体を外部から参照できるように出力することができる。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-anatomy.html

作成準備

準備① 必要なパラメーターを検討(Parameters:)

パラメーター名(論理名) 内容
ProjectName プロジェクト名。タグにプロジェクト名+vpcとかで名前つけるためのもの
VpcCIDR VPCのIP範囲
aSubnetCIDR パブリックサブネットの範囲1
bSubnetCIDR パブリックサブネットの範囲2
aPrivateSubnetCIDR プライベートサブネットの範囲1
bPrivateSubnetCIDR プライベートサブネットの範囲2
NATGatewayCreate NATゲートウェイを作るか否か(お金かかるとことなので)
StepInstanceCreate 踏み台サーバーを用意するか否か(お金かかるとことなので)
WebAllowLocation Webサーバーが受け入れるIP範囲
StepAllowLocation 踏み台サーバーが受け入れるIP範囲
MyAMI Webサーバーが使用するAMI(未指定の場合はDefaultAMIが使用される)
DefaultAMI AmazonLinux2
WebKeyPair WebサーバーへのSSHアクセス用KeyPair
StepKeyPair 踏み台サーバーへのSSHアクセス用KeyPair
AutoScalingDesiredCapacity AutoScallingの希望キャパシティ(0にすればインスタンスを作らない)

自分用にある程度カスタマイズできるように色々と準備した。
これらのパラメーターを使用した構成でCloudFormationは動作する。

設定の例

パラメーター名・タイプ・説明・デフォルト値などを指定できる。

Parameters:
  MyAMI:
    Type: String
    Description: your ami id
    Default: 'ami-0000000000000000'

これをCloudFormationで読み込むとパラメータ入力画面で入力できるようになる。

準備② 必要なリソースをまとめる(Resources:)

リソース名(論理名) 内容ざっくり
VPC VPC
aSubnet パブルックサブネットA
bSubnet パブルックサブネットB
aPrivateSubnet プライベートサブネットA
bPrivateSubnet プライベートサブネットB
aRouteTable パブリックサブネットAのルートテーブル
bRouteTable プライベートサブネットBのルートテーブル
bPrivateRouteTable プライベートサブネットBのルートテーブル
aPrivateRouteTable プライベートサブネットAのルートテーブル
aSubnetRouteTableAssociation パブリックサブネットAとルートテーブルの紐づけ
bSubnetRouteTableAssociation パブリックサブネットBとルートテーブルの紐づけ
aPrivateSubnetRouteTableAssociation プライベートサブネットAとルートテーブルの紐づけ
bPrivateSubnetRouteTableAssociation プライベートサブネットBとルートテーブルの紐づけ
aRoute パブリックサブネットAのルート定義とルートテーブル紐付け
bRoute パブリックサブネットBのルート定義とルートテーブル紐付け
aPrivateRoute プライベートサブネットAのルート定義とルートテーブル紐付け
bPrivateRoute プライベートサブネットBのルート定義とルートテーブル紐付け
aEIP サブネットAのNATゲートウェイ用IPアドレス
bEIP サブネットBのNATゲートウェイ用IPアドレス
aNatGateway サブネットAのNATゲートウェイ
bNatGateway サブネットBのNATゲートウェイ
InternetGateway インターネットゲートウェイ
VPCGatewayAttachment インターネットゲートウェイ紐付け
WebServerSecurityGroup Webサーバ用のセキュリティグループ
LoadBalancer ロードバランサ
TargetGroup ロードバランサのターゲットグループ
Listener ロードバランサとターゲットグループの紐付け
LoadBalancerSecurityGroup ロードバランサ用のセキュリティグループ
AutoScalingGroup オートスケーリンググループ
Ec2LaunchConfiguration EC2の起動設定
CloudWatchParameter Cloudwatchでログを出力するための設定値
AutoScalingEC2Profile EC2にロールを紐付けるためのプロファイル。
AutoScalingEC2Role ロール(CloudWatchLogsとかを出力するためのロール)
StepEC2 踏み台サーバー
StepEIP 踏み台サーバー用のIPアドレス
StepSecurityGroup 踏み台サーバー用のセキュリティグループ

設定の例

Parameters:
  ProjectName:
    Type: String
    Default: "aws-cloud-tech"
  VpcCIDR:
    Type: String
    Default: "192.168.0.0/16"
Resources:
  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      # Fn::Refという関数を使用して、パラメーターで入力された値が取得できる。
      CidrBlock: !Ref VpcCIDR
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      InstanceTenancy: default
      Tags:
        - Key: Name
	  # Fn::Subという関数を使用して文字列を作っている。
          Value: !Sub "${ProjectName}-vpc"

  aSubnet:
    Type: "AWS::EC2::Subnet"
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      CidrBlock: !Ref aSubnetCIDR
      # Fn::Refという関数を使用して、上で定義されているVPCのIDが取得できる。返却される値はTypeによって異なる。
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-subnet-a"
# yamlだとコメントかけるからいいよね!

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html

準備③ アウトプットする内容を決める(Outputs:)

とりあえずLBのアクセスURLを出しておく。

Outputsではテンプレート内で定義されたリソースの情報を出力できる。

クロススタックの場合はリソースの内容をもっと出力する必要がある。
クロススタックの分割ルールは、ライフサイクルの長短、依存関係の大小で分割を決めるといいらしい。(AWS Black Belt Online Seminarのセミナーの内容)
ちなみに、出力名変えたいなと思っても別テンプレートで使ってるから無理とか言われるので出力する場合は、名前をきちんと考えた方が良いっぽい。
https://aws.amazon.com/jp/blogs/news/webinar-bb-aws-cloudformation-2020/

設定の例

Resources:
  LoadBalancer:
    Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "${ProjectName}-elb"
      Name: !Sub "${ProjectName}-elb"
      Subnets:
        - !Ref aSubnet
        - !Ref bSubnet
      SecurityGroups:
        - !Ref LoadBalancerSecurityGroup
Outputs:
  URL:
    Value: !Join
      - ''
      - - 'http://'
        - !GetAtt LoadBalancer.DNSName
        - /

出力はこんな感じ

テンプレートを作ってみる

...おらっ!

テンプレートを使ってスタック作成

リージョンは東京(ap-northeast-1)

事前準備
・SSH接続用のKeyPairの準備
・CloudFormationを実行するIAM(※)
(※)VPC,EC2,IAM,SSMパラメーターなどの作成権限を持ったIAMが必要。権限が足りなければCloudFormation実行時にエラーが出るので都度追加していけばいつかは成功するはず!

事前準備(Option:独自のEC2イメージを使いたい場合)
・EC2イメージ(AMI)のImageId

スタックの作成

デザイナーでテンプレートを作成

コードをアップロード(デザイナーの場合)

次へ

パラメーターを入力して

次へ

オプションをデフォルトのまま

次へ

レビューして

IAM作成承認にチェック入れてからスタックの作成

イベントがゴリゴリ進む

タイムは4分25秒

出力を確認

URLへアクセスしてみる。OK!

AutoScallingのインスタンスも良好

ログも2台分きちんと取得できてる

まとめ

CloudFormationいいところ
・設計変更に強い
・環境を複製できる
・AWSリソース間の関連性がわかるようになる
・コンソール上だけだと表面上気が付かなかったリソースの存在に気がつけるようになる
・インフラエンジニアでなくてもとっつきやすい(個人的な感覚ですが、プログラムを書いて何かが出力されてっていうのが吸収されやすいからなのかも)

CloudFormationわるいところ
・AWS以外で使えない
・勉強コストがそれなりに必要

CloudFormationまだわかってないところ
・テンプレートのバージョン管理(ドキュメント見てもなんのことだかよくわからない。。まさかとは思うけどテンプレートを別途バージョン管理使って管理してねということじゃないよね。わからん。)
 https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/best-practices.html#code
・テンプレートのネスト
 関連性のあるテンプレートをネストすることができるらしいのだが、詳しく調べていない。

感想

アウトプットめちゃ大変。

Discussion