Webエンジニアの日常とリーグオブレジェンド

Webエンジニアとして働いている猫のブログ。EmacsとMySQLとリーグオブレジェンド(LoL)が好物。主に技術的な記事かLoLの記事を書く。

CloudFormationでEC2サーバー1台の最も簡単な構成を建ててみる

f:id:yoshiki_utakata:20190404013604p:plain

はじめに

CloudFormationがよくわからんという人

この記事は下記記事の続きの記事です。

www.utakata.work

「CloudFormationの基本的な文法を知りたい」「CloudFormationの使い方がわからん」といった場合は、↑の記事を読むことをおすすめする。

EC2とかVPCとかサブネットがよくわからんという人

こんな場合はこっちの記事を読むと良い。

  • EC2やVPCやサブネットがよくわからない
  • EC2はわかるけどなんでVPCやサブネットが必要なのかわからない

www.utakata.work

この記事の対象者

CloudFormationの基本的な文法や、やEC2, VPC, サブネットについては理解しているが、EC2インスタンスを立てるのにどうやって書いていったらいいのかわからーんという人。

CloudFormationでEC2サーバー2台の構成を建てる

AWSで何かサービスを建てる時、最も簡単なのは「EC2インスタンスを1台建てて、そこでアプリケーションを動かす」構成だ。これをCloudFormationで構成しようと思う。*1

CloudFormationとは?(わかっていれば読まなくて良い)

AWSのサーバー構成を記述すると、その通りにサーバーを建ててくれるというものだ。例えば「Webサーバーが1台でポート80を開ける。CPUのスペックはこんなもん。DBサーバーが1台あってWebサーバーからのMySQL接続だけを許可」といったことが記述できる。

CloudFormationを利用しなくても、WebのUIでボタンを押していけばサーバーを建てること自体は可能だ。しかし、「もう一回同じ構成を作ってくれ」と言われた場合に *2、は大変だ。しかしCloidFormationならAnsibleの用に設定ファイルを流し込むだけて全く同じ構成のものが作れる。これがCloudFormationを利用するメリットである。

構築してみる

今回は development.yml として、Dev環境を構築するというシナリオで行う。

VPCを作成する

VPCを作るだけならすごく簡単なので、まずはVPCを構築してみる。 [AWSをはじめてみる2 - CloudFormationでのプロビジョニング・構成管理 - WebエンジニアのLoL日記 の方も、VPCの作成を題材にしているので参考にしてもらいたい。

AWSTemplateFormatVersion: '2010-09-09'
Description: "Create dvelopment environment"
Resources:
  DevelopmentVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
      - Key: Name
        Value: Development-VPC

今後は、Resources 以下のみ書いていくので注意してもらいたい。

  • DevelopmentVPC: と書き始める。ここの名前は何でもいいが、他と被らない名前にする必要があるので、今回は DevelopmentVPC とした
  • Properties 以下の VPC の設定を書いていく

CidrBlock

CIDRというのは x.x.x.x/16 のような書き方のこと。このVPCで利用するIPの範囲を指定する。10.0.0.0/1610.0.0.010.0.255.255 の範囲を利用することを示す。*3 ふつうはVPC/16 にしてサブネットを /24 とかにするので、それに習って今回は /16 とした。((サーバーの台数によってはIPが足りなくなったりするので適宜いい感じに設定してあげてください。わからなければ思考停止で /16 でいいと思います。))

Tags

      Tags:
      - Key: Name
        Value: Development-VPC

高こう定するとここのNameのところに Development-VPC と表示される。付けなくても良いのだが、Webのコンソールから見た時かなり見づらいので、設定したほうが良い。完全にWebの見た目だけのための設定なので好きに設定して良い。この設定に限らない話だが、日本語を使うとAWSのWeb上で文字化けするので英語を推奨する。

f:id:yoshiki_utakata:20190408112258p:plain

ここまででVPCの作成は終わりなので、一度CloudFormationを流してみて正しくVPCができていることを確認するとよい。次回以降は「スタックの更新」を行えば差分だけが適用されるし、「スタックの削除」を行えば今回作ったVPC, EC2などはすべて削除できるので、切りの良いところまでできたら流してみて文法ミスがないかなどをチェックしてほしい。*4

インターネットゲートウェイの設置

VPCを作成したらインターネットゲートウェイを設置してやる必要がある。VPC内に設置されたEC2インスタンスはインターネットゲートウェイを経由しなければインターネットにアクセスできない。逆に外からVPC内にアクセスする場合もインターネットゲートウェイを通る。インターネットゲートウェイの主な役割はVPC内外でのアドレス変換である。 *5

このインターネットゲートウェイは結構複雑だ。長いので適宜コメントで補足しているので見てほしい。以下の設定が書かれている。

  • Gatewayを作成
  • GatewayVPCに配置
  • ルートテーブルを作成。ルートテーブルとは「VPCの中から外に出る場合はGatewayを通ってアドレス変換してね」というのを記述するものである。
  • ルートテーブルの内容を設定
  # VPC内とインターネットをつなぐGatewayを作成
  DevelopmentInternatGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
      - Key: Name
        Value: Development-VPC-Gateway
  
  # GatewayをVPCに配置する
  # Gateway作成とは別に配置の設定が必要となる
  AttachDevelopmentGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      # VpcIdで指定されたVPCに、InternetGatewayIdで指定されたGatewayを配置する
      VpcId: !Ref DevelopmentVPC
      InternetGatewayId: !Ref DevelopmentInternatGateway

  # ルートテーブルを作成
  DevelopmentRouteTable:
    Type: AWS::EC2::RouteTable
    # このようにDependsOnを書くと、AttachGatewayが完了してから
    # ルートテーブルが作成される。
    # Proertiesの中でDevelopmentVPCを参照しているので、
    # DevelopmentVPCが作られたあとに実行されることは保証されているが、
    # AttachされているかどうかはわからないのでDependsOnで明記する必要がある
    DependsOn: AttachDevelopmentGateway
    Properties:
      VpcId: !Ref DevelopmentVPC
      Tags:
      - Key: Name
        Value: Development-RouteTable
  
  # ルートテーブルの設定
  DevelopmentGatewayRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      # VPC内から外へのすべての通信はInternetGatewayを通るようにする設定を
      # DevelopmentRouteTable に入れる。
      RouteTableId: !Ref DevelopmentRouteTable
      # 0.0.0.0/0 はすべてのIPを表す(VPC内のアドレスは除く)
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref AsadaigakuDevInternetGateway

ちょっと複雑だったがこれでVPCの中とインターネットが接続できるようになった。これを行わないと、VPC内のサーバーはインターネットにアクセスできないし、*6 外から中にhttpでアクセスしたりSSHしたりすることもできない。

サブネットの作成

サブネットの作成はVPCと同じでシンプルだ。

  # ユーザー(開発者)がインターネット経由でアクセスできるサブネット
  DevelopmentPublicSubnet:
    Type: AWS::EC2::Subnet
    DependsOn: AttachGateway
    Properties:
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: true
      VpcId: !Ref DevelopmentVPC
      Tags:
      - Key: Name
        Value: Development-Public-VPC

ここまで読めたならもうこれは読めるだろう。IPアドレス帯としては 10.0.1.010.0.1.255 をこのサブネット用のものとして定義する。((これも先程のVPCと同様、特にこだわりがなければ /24 で良いだろう))

DevelopmentPublicSubnet という名前をつけているが、これはインターネットからポート80または443でアクセスできるという意味で付けていますので、 DevelopmentWebServerSubnet でもなんでも、なんかいい感じの名前を付けてください。

EC2インスタンスしか作らない場合、サブネットの意義はあまり感じられませんが、EC2インスタンスを作成する際にサブネットは必要になるので、作る必要があります。

セキュリティグループの作成

セキュリティグループはEC2インスタンスに設定するセキュリティの設定です。「ここからここへはポート22のアクセスを許可」などの情報を書きます。

SSH用セキュリティグループの作成

まずは「SSH可能とするEC2インスタンスに設定するためのセキュリティグループ」を作成します。

  # 開発環境EC2インスタンスにSSHするためのセキュリティグループ
  DevelopmentSSHSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref DevelopmentVPC
      GroupDescription: Enable SSH
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: 0.0.0.0/0

これももう読んでもらえればだいたい分かるかと思いますが、ポート22に来たtpcのアクセスを、アクセスもとがどこかにかかわらず常に許可する設定です。 VpcId が設定されていますが、これは別にPC内部のすべてのインスタンスのポート22への接続を許可する わけではありません 。このセキュリティグループをEC2インスタンスに付与すると、そのインスタンスへのSSH接続が可能になります。

GroupDescription は必須要素なので注意してください。

HTTP/HTTPS用セキュリティグループの作成

上記とほぼ同様です

  # Webアプリケーションにアクセスできるようにするセキュリティグループ
  # VPNからのアクセスのみ許可する
  DevelopmentWebSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable web traffic to Instance
      VpcId: !Ref DevelopmentVPC
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
      - IpProtocol: tcp
        FromPort: 443
        ToPort: 443

EC2インスタンスを立てる

ようやくEC2インスタンスを建てられます。

DevelopmentWeb:
    Type : AWS::EC2::Instance
    Properties:
      # Amazon Linux 2
      ImageId: ami-0f9ae750e8274075b
      InstanceType: t2.micro
      SubnetId: !Ref DevelopmentPublicSubnet
      SecurityGroupIds:
      - !Ref DevelopmentSshSecurityGroup
      - !Ref DevelopmentWebSecurityGroup
      KeyName: sakamoto
      Tags:
      - Key: Name
        Value:Development-Web

これももう見たらわかるかと思います。EC2について全然わからん!って人は下記の記事を見ながら一度EC2インスタンスを立ててみるといいと思います。

www.utakata.work

ImageIdはAMIってやつです。OSみたいなものです。KeyNameは初期設定されるSSH用のキーの名前です。AMIやキー、インスタンスタイプについては↑のブログを呼んでみるといいです。

他は見ての通り、先ほど作成したサブネットやセキュリティグループを設定します。CloudFormationでスタックを作成してみたら、EC2のコンソールからIPを調べてSSH接続してみましょう。Keyが正しく設定されていれば

ssh ec2-user@<IP Address>

で接続できるかと思います。

ポート80も空いていますが、まだWebアプリケーションが動いていないので、接続しようとしてもなにも応答はありません。

さいごに

RDSだったり、Elastic IPだったりDNSだったりプロビジョニングだったり、まだいろいろやるべきことはありますのですが、長くなったので次回以降にします。

*1:EC2を利用する際にセットでRDSを使うことが多いが、RDSは結構複雑なので、次回以降で扱う

*2:例えばOSのバージョンを上げたいのでインスタンスを作り直したい、サーバー台数を増やしたいのでもう一台同じ設定で建てたい、といった状況が考えられる

*3:CIDRの読み方については簡単なのでググって調べてほしい

*4:yamlにミスがある場合はCloudFormationが流れる前にエラーが表示される。yamlにミスは無いが設定内容にミスがあったりする場合は、更新中にエラーがでてロールバックされたり、更新されたものの思い通りに設定できていなかったりするので注意してみてほしい。

*5:詳しくはNATでググってほしい。長くなるので細かくは説明しない

*6:インターネットにアクセスできないと、yumのようなコマンドは動かない