15
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

簡単なインフラ環境をAWS Cloud Formationを使って構築してみた

Posted at

はじめに

AWSで環境構築したいけど、マネジメントコンソールぽちぽちは手順書の作成めんどくさいよね、ということで、CloudFormationを使用して、シンプルな構成のシステムを自動で構築してみました。
YAML(もしくはJSON)でテンプレートを作成するだけで、マネジメントコンソールをぽちぽちしなくても自動で環境を作ってくれて超便利です!

環境の自動化がなぜ重要か

  • 環境構築での人為的ミスを減らせる→信頼性の向上
  • 開発速度を上げることができる
  • DevOps(開発と運用の一体化)とCI/CD(継続的デリバリー)での開発を実現できる

AWSにおける環境を自動化するための主なサービス

  • Codeシリーズ(Git上のコードのコミット・実行・デプロイの自動化)
  • Cloud Formation
  • ECS(Dockerコンテナによる環境構築の自動化)
  • Elastic Beanstalk(Webアプリケーションのデプロイ自動化)
  • OpsWorks(サーバの設定、デプロイ、管理の自動化)
    など

今回は、Cloud Formationでの環境構築の自動化をやっていきます。

Cloud Formationとは

  • インフラストラクチャリソースのテンプレートを利用して自動で構築することができる環境自動設定サービス
  • AWS内の全てのインフラリソースをテンプレート化することができる
  • テンプレートはJSONかYAMLで記述する
  • Code Piplineと組み合わせることで、テンプレートの変更、実行、展開を自動化できる
  • Cloud Formationデザイナーを使うことで、視覚的にテンプレートを作成することも可能

Cloud Formationを使う利点

  • 環境構築を効率化できる
  • いつでも同じ設定の環境を構築することができる(標準化)
  • ソフトウェアと同じように構成管理ができる

テンプレートについて

AWS公式ドキュメントのテンプレートリファレンスに全て情報が載っているので、こちらを見ながら作成していきます。

sample.yaml

AWSTemplateFormatVersion: '2010-09-09'
Description: A sample template
Metadata:
Parameters:
Mappings:
Conditions:
Resources:
  MyEC2Instance:
    Type: AWS::EC2::Instance
# 省略
  • AWSTemplateFormatVersion: 必ず頭に記述する
  • Description: テンプレートの説明
  • Metadata: メタデータ
  • Parameters: 共通で使いたい要素を参照値として記述
  • Mappings: Parametersの値が複数バージョン
  • Conditions: リソース作成時の条件内容を記述
  • Resources: 実際に作りたいリソースの内容を記述

Cloud Formationで環境構築をしてみる

どんな環境を作るか

以下の構成の環境を、Cloud Formationを使って構築していきます。
CloudFormation.001.jpeg

VPCの作成

YAMLファイルの記述

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Description: A sample template
Parameters:
Resources:
  MyVpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: '10.10.0.0/16'
      Tags:
        - Key: 'Name'
          Value: 'sample-vpc'
  • MyVPC: 任意のリソース名
  • Type: 作成するリソースを記載。VPCのリソース名は、"AWS::EC2::VPC"
  • Properties: プロパティ
  • CiderBlock: 任意のCIDRブロックを設定する。"10.10.0.0/16"を設定することで、このVPC内では10.10.0.0~10.10.255.255までのIPアドレスが使用可能になる。
  • Tags: タグをつけるときに使用する

サブネットの作成

パブリックサブネットを1つ、プライベートサブネットを2つ作成します。

YAMLファイルの記述

template.yaml
# 省略

Resources:
  # 省略
  MyPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVpc
      CidrBlock: '10.10.11.0/24'
      MapPublicIpOnLaunch: true
      Tags:
        - Key: 'Name'
          Value: 'sample-public-subnet'
  MyPrivateSubnet1A:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVpc
      CidrBlock: '10.10.21.0/24'
      AvailabilityZone: 'ap-northeast-1a'
      Tags:
        - Key: 'Name'
          Value: 'sample-private-subnet1a' 
  MyPrivateSubnet1C:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVpc
      CidrBlock: '10.10.22.0/24'
      AvailabilityZone: 'ap-northeast-1c'
      Tags:
        - Key: 'Name'
          Value: 'sample-private-subnet1c'   
  • VpcId: このサブネットが所属するVPCのIDもしくはリソース名を記述する
    • Ref関数: 指定したパラメータまたはリソースの値を返す(ここではMyVpcを返す)
  • MapPublicIpOnLaunch: このサブネットで起動されたインスタンスがパブリックIPアドレスを受け取る場合はtrueにする(デフォルトはfalse)

インターネットゲートウェイの作成

YAMLファイルの記述

template.yaml
# 省略

Resources:
  # 省略
  MyInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: 'Name'
        Value: 'sample-igw'
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref MyVpc
      InternetGatewayId: !Ref MyInternetGateway  

AttachGatewayでVPCにインターネットゲートウェイをアタッチする

パブリックサブネットの作成

インターネットゲートウェイとパブリックサブネットをルートテーブルで紐付ける

YAMLファイルの記述

template.yaml
# 省略

Resources:
  # 省略
  MyRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      Tags:
        - Key: 'Name'
          Value: 'sample-rt'
      VpcId: !Ref MyVpc
  MyRoute:
    Type: AWS::EC2::Route
    DependsOn: MyInternetGateway
    Properties:
      RouteTableId: !Ref MyRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref MyInternetGateway
  MySubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref MyPublicSubnet
      RouteTableId: !Ref MyRouteTable

インターネットゲートウェイを指定したルート(MyRoute)をルートテーブル(MyRouteTable)に設定し、ルートテーブルをパブリックサブネットにMySubnetRouteTableAssociationで紐付けた

ここまでできました

CloudFormation.002.jpeg

EC2インスタンスを作成

パブリックサブネットにEC2インスタンスを設置する

YAMLファイルの記述

template.yaml
# 省略
Parameters:
  KeyPair:
    Description: Select KeyPair Name.
    Type: AWS::EC2::KeyPair::KeyName

Resources:
  # 省略
  MyEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: 'ami-xxxxxx' # xにはidがはいる
      InstanceType: t2.micro
      SubnetId: !Ref MyPublicSubnet
      BlockDeviceMappings:
        - DeviceName: '/dev/xvda'
          Ebs:
            VolumeType: 'gp2'
            VolumeSize: 8
      Tags:
        - Key: 'Name'
          Value: 'sample-ec2-instance'
      SecurityGroupIds:
        - !Ref MyEC2SecurityGroup
      KeyName: !Ref KeyPair
  MyEC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref MyVpc
      Tags:
        - Key: 'Name'
          Value: 'sample-ssh-sg'
      GroupDescription: Allow ssh
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: '22'
        ToPort: '22'
        CidrIp: 0.0.0.0/0
  • ImageId: 使用するAMIのIDを記述する
  • SubnetId: EC2インスタンスを設置するサブネットを指定
  • BlockDeviceMappings: インスタンスにアタッチするブロックデバイスを定義
  • KeyName: KeyPairはParameterで設定しており、マネジメントコンソールで指定する
  • SecurityGroupIngress: 受信規則を指定

DBインスタンスの作成

プライベートサブネットにDBインスタンスを設置する。RDSを使用する。マルチAZ構成にする。

YAMLファイルの記述

template.yaml
# 省略
Parameters: 
  # 省略
  MyRDSMasterUser:
    Type: String
    Default: admin
    MinLength: 1
    MaxLength: 16
    NoEcho: true
    AllowedPattern: '[a-z]+'
  MyRDSMasterPassword:
    Type: String
    Default: password
    MinLength: 8
    MaxLength: 16
    NoEcho: true
    AllowedPattern : '[^\/@"]+'

Resources:
  # 省略
  MyRDSSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: SubnetGroup for RDS
      SubnetIds:
        - !Ref MyPrivateSubnet1A
        - !Ref MyPrivateSubnet1C
  MyRDSSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SecurityGroup for DB
      SecurityGroupIngress:
        - IpProtocol: tcp
          CidrIp: 0.0.0.0/0
          FromPort: '3306'
          ToPort: '3306'
      VpcId: !Ref MyVpc
  MyRDSDBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      AllocatedStorage: '5'
      DBSubnetGroupName: !Ref MyRDSSubnetGroup
      VPCSecurityGroups: 
      - !Ref MyRDSSecurityGroup
      MultiAZ: true
      DBInstanceClass: db.t2.micro
      DBName: 'sample'
      Engine: MySQL
      EngineVersion: 5.7.22
      MasterUsername: !Ref MyRDSMasterUser
      MasterUserPassword: !Ref MyRDSMasterPassword
    DeletionPolicy: Snapshot
  • MyRDSMasterUser(Parameter): DBのユーザ名のバリデーションを設定(ユーザ名はマネジメントコンソールで設定する)
  • MyRDSMasterPassword(Parameter): DBのパスワードのバリデーションを設定(パスワードはマネジメントコンソールで設定する)
  • MultiAZ: マルチAZ構成にする場合はtrue(デフォルトはfalse)
  • Engine: DBエンジンを指定(今回はMySQL)
  • MasterUsername: マネジメントコンソールで設定したMyRDSMasterUserをユーザ名として使用
  • MasterUserPassword: マネジメントコンソールで設定したMyRDSMasterPasswordをパスワードとして使用
  • ハマりポイント: VPCSecurityGroupsは配列での指定じゃないとダメでした

完成!

CloudFormation.001.jpeg

完成したテンプレート

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: A sample template
Parameters:
  KeyPair:
    Description: Select KeyPair Name.
    Type: AWS::EC2::KeyPair::KeyName
  MyRDSMasterUser:
    Type: String
    Default: admin
    MinLength: 1
    MaxLength: 16
    NoEcho: true
    AllowedPattern: '[a-z]+'
  MyRDSMasterPassword :
    Type: String
    Default: password
    MinLength: 8
    MaxLength: 16
    NoEcho: true
    AllowedPattern : '[^\/@"]+'

Resources:
  MyVpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: '10.10.0.0/16'
      Tags:
        - Key: 'Name'
          Value: 'sample-vpc'
  MyPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVpc
      CidrBlock: '10.10.11.0/24'
      MapPublicIpOnLaunch: true
      Tags:
        - Key: 'Name'
          Value: 'sample-public-subnet'
  MyPrivateSubnet1A:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVpc
      CidrBlock: '10.10.21.0/24'
      AvailabilityZone: 'ap-northeast-1a'
      Tags:
        - Key: 'Name'
          Value: 'sample-private-subnet1a' 
  MyPrivateSubnet1C:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVpc
      CidrBlock: '10.10.22.0/24'
      AvailabilityZone: 'ap-northeast-1c'
      Tags:
        - Key: 'Name'
          Value: 'sample-private-subnet1c' 
  MyInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: 'Name'
        Value: 'sample-igw'
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref MyVpc
      InternetGatewayId: !Ref MyInternetGateway
  MyRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      Tags:
        - Key: 'Name'
          Value: 'sample-rt'
      VpcId: !Ref MyVpc
  MyRoute:
    Type: AWS::EC2::Route
    DependsOn: MyInternetGateway
    Properties:
      RouteTableId: !Ref MyRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref MyInternetGateway
  MySubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref MyPublicSubnet
      RouteTableId: !Ref MyRouteTable

  MyEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: 'ami-xxxxxx' # xにはidがはいる
      InstanceType: t2.micro
      SubnetId: !Ref MyPublicSubnet
      BlockDeviceMappings:
        - DeviceName: '/dev/xvda'
          Ebs:
            VolumeType: 'gp2'
            VolumeSize: 8
      Tags:
        - Key: 'Name'
          Value: 'sample-ec2-instance'
      SecurityGroupIds:
        - !Ref MyEC2SecurityGroup
      KeyName: !Ref KeyPair
  MyEC2SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref MyVpc
      Tags:
        - Key: 'Name'
          Value: 'sample-ssh-sg'
      GroupDescription: Allow ssh
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '22'
          ToPort: '22'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '80'
          ToPort: '80'
          CidrIp: 0.0.0.0/0

  MyRDSSubnetGroup:
    Type: AWS::RDS::DBSubnetGroup
    Properties:
      DBSubnetGroupDescription: SubnetGroup for RDS
      SubnetIds:
        - !Ref MyPrivateSubnet1A
        - !Ref MyPrivateSubnet1C
  MyRDSSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SecurityGroup for DB
      SecurityGroupIngress:
        - IpProtocol: tcp
          CidrIp: 0.0.0.0/0
          FromPort: '3306'
          ToPort: '3306'
      VpcId: !Ref MyVpc
  MyRDSDBInstance:
    Type: AWS::RDS::DBInstance
    Properties:
      AllocatedStorage: '5'
      DBSubnetGroupName: !Ref MyRDSSubnetGroup
      VPCSecurityGroups: 
      - !Ref MyRDSSecurityGroup
      MultiAZ: true
      DBInstanceClass: db.t2.micro
      DBName: 'sample'
      Engine: MySQL
      EngineVersion: 5.7.22
      MasterUsername: !Ref MyRDSMasterUser
      MasterUserPassword: !Ref MyRDSMasterPassword
    DeletionPolicy: Snapshot

参考資料

15
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?