「お前には n 日間でAWSを学んでもらう」 #6 です.  #2, #4とAWSのインスタンスの起動は様々な方法でやっていきましたが, 今度はAWS CloudFormationを用いた方法を試してみます.

この記事のスコープ

  • AWSリソースを記述するテンプレートを作成する
  • テンプレートからリソースをプロビジョニングする

AWS CloudFormation

手軽に「いつもの構成」を実現するための便利なサービスといったところだと思います.

#2でやったようなVPC作ってサブネット作ってその中にインスタンスたてて...といったこと, その他起動したインスタンス内で最初にやってほしいことなどを記述することができるので, 同じような環境を複製することが実現できるはずです.

S3, RDSなどとも結びつけてやればこのサービスの力強さが実感できるのかもしれませんね.

テンプレートとスタック

テンプレートはAWSリソースとそのプロパティを記述したものです. このテンプレートに基づいてCloudFormationはリソースをいい感じに起動してくれます.

テンプレートで定義されたCloudFormationによって作成される関連リソースをまとめて「スタック」と呼びます.  

テンプレートの作成

#2 同様にネットワーク関連の設定をしてからインスタンスを起動するということを行おうとしています. よって実現する構成も#2と同じく次のようなものになります:

この「ネットワーク部分」と「インスタンス部分」とは, 同じスタックにおいておくよりも分けておいた方が管理しやすいので, それぞれ別のスタックに置いておきます. インスタンススタックはネットワークスタックのリソースを使用します.

ネットワークスタックのテンプレート

AWSTemplateFormatVersion: "2010-09-09"

Description:
  Network Configuration

Parameters:
  VpcCidrBlock:
    Description:
      Input Cidr Block of VPC
    Type: String
    Default: 10.1.0.0/16
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})

  PublicSubnetACidrBlock:
    Description:
      Input Cidr Block of Public Subnet A
    Type: String
    Default: 10.1.0.0/18
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      EnableDnsSupport: true
      EnableDnsHostnames: true
      CidrBlock:
        Ref: VpcCidrBlock

  PublicSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId:
        Ref: VPC
      CidrBlock:
        Ref: PublicSubnetACidrBlock

  InternetGateway:
    Type: AWS::EC2::InternetGateway

  VPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId:
        Ref: VPC
      InternetGatewayId:
        Ref: InternetGateway

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId:
        Ref: VPC

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: VPCGatewayAttachment
    Properties:
      RouteTableId:
        Ref: PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId:
        Ref: InternetGateway


  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId:
        Ref: PublicSubnetA
      RouteTableId:
        Ref: PublicRouteTable

  SSHSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH Ingress
      VpcId:
        Ref: VPC
      SecurityGroupIngress:
        IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: xxx.xxx.xxx.xxx/32

Outputs:
  VPCId:
    Description:
      VPC ID
    Value:
      Ref: VPC
    Export:
      Name:
        !Sub '${AWS::StackName}-VPCID'

  PublicSubnetA:
    Description:
      SubnetA ID
    Value:
      Ref: PublicSubnetA
    Export:
      Name:
        !Sub '${AWS::StackName}-SubnetID'

  WebServerSecurityGroup:
    Description:
      Security Group ID
    Value:
      !GetAtt SSHSecurityGroup.GroupId
    Export:
      Name:
        !Sub '${AWS::StackName}-SecurityGroupID'
TestNetworkCrossStack.yaml

各項目は#2と同じなので特に説明しませんが, ParametersとOutputsの部分が特徴的かもしれません.

Parametersの部分ではユーザー入力できる項目について書いています. この例だとVPC, SubnetのCIDRブロックを定義できるようにしており, このテンプレートを使いまわしていくつもの仮想ネットワーク環境を作ることができるようにしています.

Outputsの部分では他のスタックがこのスタックのリソースを使えるようにするため, 値を出力させています.

インスタンススタックのテンプレート

AWSTemplateFormatVersion: "2010-09-09"

Description:
  Instance Configuration

Parameters:
  NetworkStackName:
    Description:
      Name of the Stack related network configuration
    Type: String
    MinLength: 1
    MaxLength: 255
    AllowedPattern: ^[a-zA-Z][-a-zA-Z0-9]*$
    Default: TestNetworkCrossStack

Resources:
  Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t2.micro
      ImageId:
        ami-0a1c2ec61571737db
      KeyName:
        testKey
      NetworkInterfaces:
        - GroupSet:
          - Fn::ImportValue:
              !Sub '${NetworkStackName}-SecurityGroupID'
          AssociatePublicIpAddress: true
          DeviceIndex: 0
          DeleteOnTermination: true
          SubnetId:
            Fn::ImportValue:
              !Sub '${NetworkStackName}-SubnetID'
TestInstanceCrossStack.yaml

上記ネットワークスタックのリソースを使っていることがわかります. 例えばセキュリティグループ, サブネットですね.

リソースのプロビジョニング

AWS CloudFormationのCloudFormation スタックの作成というところでスタックを作成します.

AWS CloudFormation スタックの作成

前提条件は特にいじらす、テンプレートの指定で「テンプレートファイルのアップロード」に変更し,  まずはネットワークのテンプレートをアップロードしましょう.

アップロードされたら, スタックの名前とパラメータを決める画面に進みます.

スタックの名前は好きに決めて構いませんが覚えておいてください. TestNetworkCrossStack という名前にしておくとあとで楽です.

パラメータは変更してもしなくても構いません.

あとは何度か次へを押してスタックを作成するだけです.

スタックが完成したら次はインスタンススタックを作成してください. こちらのパラメータはネットワークスタックの名前と同じでなければいけません.

2つのスタックが無事に完成すれば #2 で作ったような自分の家からだけSSH接続できるインスタンスが無事起動できたことになります!

おわり!

VPCのIDは...とかサブネットのIDは...とか#2では色々メモする羽目に遭ったのですがCloudFormationを使うとその辺がすごく楽に解決しますね!

次はインスタンスを起動するときの「ユーザーデータ」という部分にも触れていきたいと思います.

お疲れさまでした!