シンプルなネットワークとサーバーをCloudFormationで構築する 〜1. ネットワーク構築〜
新規にVPCを作成して、Webサーバーを公開するテンプレートを作成します。
今回は、パブリックサブネット内に1つのWebサーバーを立てる、シンプルな構成とします。(APサーバー、DBサーバーは無し)
テンプレートを目的ごとに分けます。
- ネットワーク構築
- セキュリティ設定
- サーバー構築
今回は、ネットワーク構築についてです。
ネットワーク構築用のテンプレート
作成したテンプレートは以下になります。
network.template.yaml
AWSTemplateFormatVersion: 2010-09-09 Parameters: ProjectCode: Type: String Description: Enter your project code VPCCidr: Type: String Description: IP Address range for the VPN connected VPC ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. MinLength: 9 MaxLength: 18 Default: 10.0.0.0/16 AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) SubnetCidr: Type: String Description: IP Address range for the VPN connected Subnet ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. MinLength: 9 MaxLength: 18 Default: 10.0.1.0/24 AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2}) Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VPCCidr Tags: - Key: Name Value: !Ref ProjectCode Subnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: !Ref SubnetCidr Tags: - Key: Name Value: !Ref ProjectCode InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Ref ProjectCode AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway RouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Ref ProjectCode Route: Type: AWS::EC2::Route DependsOn: AttachGateway Properties: RouteTableId: !Ref RouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway SubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref Subnet RouteTableId: !Ref RouteTable Outputs: VPC: Description: VPCId of the newly created VPC Value: !Ref VPC Export: Name: !Sub ${ProjectCode}-vpc Subnet: Description: SubnetId of the VPN connected subnet Value: !Ref Subnet Export: Name: !Sub ${ProjectCode}-subnet
パラメータ
パラメータを3つ用意しました。
パラメータ | 説明 |
---|---|
ProjectCode | プロジェクトコードを指定します。 各リソースの名前とテンプレート連携(クロススタック参照)で利用します。 |
VPCCidr | VPC用のCIDRブロックを指定します。 デフォルトは 10.0.0.0/16 です。 |
SubnetCidr | サブネット用のCIDRブロックを指定します。 デフォルトは 10.0.1.0/24 です。 |
リソース
リソースのプロパティは最低限に留めています。オプション項目は公式ドキュメントを参照してください。
1. VPCの作成
選択しているリージョンに、新しいVirtual Private Cloud (VPC) を作成します。 パラメータのVPC CIDRブロックを指定します。
VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VPCCidr
2. サブネットの作成
作成したVPC内にサブネットを作成します。
パラメータのサブネット CIDRブロックを指定します。
この時、デフォルトのルートテーブルが作成されます。
デフォルトのルートテーブルは、宛先がVPC内のみで、それ以外のパケットは破棄されます。
Subnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: !Ref SubnetCidr
3. インターネットゲートウェイの作成と割り当て
VPCがインターネットとやり取りできるように、まずはインターネットゲートウェイを作成し、VPCに割り当てます。
InternetGateway: Type: AWS::EC2::InternetGateway AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway
4. ルートテーブルの作成と設定、割り当て
インターネットと接続するためには、ルートテーブルに宛先にインターネットゲートウェイを追加する必要があります。 デフォルトのルートテーブルに追加すると他に影響が出る場合があるため、新規にルートテーブルを作成・設定し、サブネットに割り当てます。
RouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Route: Type: AWS::EC2::Route DependsOn: AttachGateway Properties: RouteTableId: !Ref RouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway SubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref Subnet RouteTableId: !Ref RouteTable
出力
後続のテンプレート用にリソースIDをエクスポートします。
パラメータ | 説明 |
---|---|
VPC | VPC IDの参照用に、エクスポート名を {プロジェクトコード}-vpc にします。 |
Subnet | サブネットIDの参照用に、エクスポート名を {プロジェクトコード}-subnet にします。 |
スタック間の連携については、下記のエントリを参照してください。 oreout.hatenablog.com
スタックの作成
ではスタックを作成してみましょう。
スタックの名前、パラメータを指定します。
スタック作成完了後に、出力を確認します。
サービス [ネットワーキング & コンテンツ配信] - [VPC] を選択し、各リソースが作成されていることを確認します。
- VPC
- サブネット
- ルートテーブル
- インターネットゲートウェイ
参考
サンプルテンプレート(JSON)をCloudFormation DesignerでYAMLに変換する
テンプレートを一から全て作成するのは面倒です。
そのような場合、AWS公式のサンプルテンプレートから目的に近いものをベースに作成すると、手間が省けます。
サンプルテンプレート
サンプルテンプレートは各リージョンごとに用意されています。
今回はAsia Pacific (Tokyo) Regionを選択します。
- サンプルソリューション
- SharePoint® Foundation 2010
- Microsoft Windows Server Active Directory
- Microsoft Windows Server の役割と機能
- 基本的な WordPress (単一インスタンス)
- スケーラブルで耐久性の高い WordPress
- Chef を使用した WordPress のデプロイ
- アプリケーションフレームワーク
- 基本的な LAMP スタック
- スケーラブルで耐久性の高い LAMP スタック
- Ruby on Rails の基本
- スケーラブルで耐久性の高い Ruby on Rails
- サービス
- Auto Scaling関連 (3)
- AWS Config関連 (1)
- Amazon DynamoDB関連 (2)
- Amazon EC2関連 (3)
- Amazon ElastiCache関連 (2)
- AWS Elastic Beanstalk関連 (3)
- Elastic Load Balancing関連 (4)
- AWS Identity and Access Management関連 (1)
- AWS OpsWorks関連 (2)
- Amazon Relational Database Service関連 (4)
- Amazon Redshift関連 (2)
- Amazon Route 53関連 (3)
- Amazon Simple Storage Service関連 (2)
- Amazon Simple Queue Service関連 (2)
- Amazon Virtual Private Cloud関連 (7)
各サンプルの[表示]リンクをクリックすると、JSON形式のテンプレートがブラウザで表示されます。
YAML形式が欲しい場合、CloudFormation Designer
を起動してJSONからYAMLへ変換します。
CloudFormation Designer
各サンプルの[デザイナーで表示]リンクをクリックすると、CloudFormation Designerが起動されます。
【重要】Canvasペイン内のコンポーネントは操作しないでください。操作すると、テンプレート内にMetadata情報が追加されます。
- テンプレートの言語の選択で
YAML
を選択 - 左上の[ファイル]アイコンをクリック
- メニューの[保存]をクリック
ローカルファイル
を選択、ファイル名を入力して[保存]ボタンをクリック- ブラウザによってはダウンロードされずにそのまま表示されます。その場合は、ページをローカルに保存してください。
これをベースに自分だけのテンプレートを作成してください。
断片的な書き方は、テンプレートスニペットが参考になります。
参考
- AWSドキュメント
- AWS Black Belt
Amazon Linux2にExtras Libraryからnginxをインストールする
Amazon Linux2 では、Extras Libraryを使用してメジャーなパッケージ(トピック)をインストールすることができます。
Extras Library
パッケージ(トピック)の種類、バージョンは定期的に更新されるため、amazon-linux-extras
コマンドで確認します。
(2018年8月現在)
$ amazon-linux-extras 0 ansible2 available [ =2.4.2 ] 1 emacs available [ =25.3 ] 2 memcached1.5 available [ =1.5.1 ] 3 nginx1.12 available [ =1.12.2 ] 4 postgresql9.6 available [ =9.6.6 =9.6.8 ] 5 postgresql10 available [ =10 ] 6 python3 available [ =3.6.2 ] 7 redis4.0 available [ =4.0.5 =4.0.10 ] 8 R3.4 available [ =3.4.3 ] 9 rust1 available [ =1.22.1 =1.26.0 =1.26.1 =1.27.2 ] 10 vim available [ =8.0 ] 11 golang1.9 available [ =1.9.2 ] 12 ruby2.4 available [ =2.4.2 =2.4.4 ] 13 nano available [ =2.9.1 ] 14 php7.2 available [ =7.2.0 =7.2.4 =7.2.5 ] 15 lamp-mariadb10.2-php7.2 available [ =10.2.10_7.2.0 =10.2.10_7.2.4 =10.2.10_7.2.5 ] 16 libreoffice available [ =5.0.6.2_15 ] 17 gimp available [ =2.8.22 ] 18 docker=latest enabled [ =17.12.1 =18.03.1 ] 19 mate-desktop1.x available [ =1.19.0 =1.20.0 ] 20 GraphicsMagick1.3 available [ =1.3.29 ] 21 tomcat8.5 available [ =8.5.31 ]
enabled
がインストール済、available
が未インストールの状態です。
初期状態ではphpやruby、Go言語、Python3系はインストールされていないことがわかります。(Python2系はインストールされています)
nginxのインストール
今回はnginxをインストールします。 nginxのバージョンを確認してインストールします。
$ sudo amazon-linux-extras install nginx1.12 -y
インストールされたか確認をします。
ステータスがenabled
になっているか確認をします。
$ amazon-linux-extras | grep nginx 3 nginx1.12=latest enabled [ =1.12.2 ]
nginxのバージョンを確認します。
$ nginx -v
nginx version: nginx/1.12.2
nginxの起動
nginxを起動します。
$ sudo systemctl start nginx
ローカル(EC2)上から確認
$ curl -I localhost HTTP/1.1 200 OK Server: nginx/1.12.2 Date: Tue, 14 Aug 2018 21:04:21 GMT Content-Type: text/html Content-Length: 3520 Last-Modified: Wed, 13 Dec 2017 18:36:55 GMT Connection: keep-alive ETag: "5a317347-dc0" Accept-Ranges: bytes
外部(ブラウザ)から確認
EC2インスタンスのパブリックIPアドレスをブラウザに指定して開きます。
ローカルから確認出来ており、接続出来ない場合はセキュリティーグループとネットワークACLを確認してください。
自動起動
EC2インスタンス起動時にnginxを起動する場合と確認方法は以下になります。
自動起動
$ sudo systemctl enable nginx
確認
$ systemctl is-enabled nginx enabled
参考
- AWSドキュメント
- Developers.IO
iperfを利用して東京〜USリージョン間のEC2ネットワークスループットを計測してみた
米国リージョンは、政府用を除くと、下記の4つがあります。(2018年8月現在)
- us-east-1: 米国東部(バージニア北部)
- us-east-2: 米国東部 (オハイオ)
- us-west-1: 米国西部 (北カリフォルニア)
- us-west-2: 米国西部 (オレゴン)
東京リージョンEC2から各リージョンEC2へ、どの程度のネットワークスループットがあるのか?
気になったので計測してみました。
計測にはオープンソースのiperf(アイパーフ)を利用し、EC2はAmazon Linux2
を選択しました。
EC2
各リージョンにEC2インスタンスを作成します。
- AMIの選択
- Amazon Linux2
- インスタンスタイプの選択
- t2.micro
- インスタンスの設定
- ネットワーク: デフォルトVPC
- サブネット: 優先順位なし(AZのデフォルトサブネット)
- セキュリティグループの設定
- インバウンド1行目(サーバー側の場合)
- タイプ: カスタムTCPルール
- ポート範囲: 5001
- ソース: 任意の場所
- インバウンド2行目
- タイプ: SSH
- ポート範囲: 22
- ソース: 任意の場所
- インバウンド1行目(サーバー側の場合)
iperf
インストール
Amazon Linux2にEPELリポジトリを追加してからインストールします。
sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm sudo yum install -y iperf
サーバー側(米国リージョン)
オプション-s
を付けてリッスン状態にします。
デフォルトではTCP 5001番を利用します。
$ iperf -s ------------------------------------------------------------ Server listening on TCP port 5001 TCP window size: xx.x KByte (default) ------------------------------------------------------------
クライアント側(東京リージョン)
サーバー側をリッスン状態にした後に、クライアント側からコマンドを叩きます。
オプションは-c
で、サーバー側のIPアドレスを指定します。
$ iperf -c xxx.xxxx.xxx.xxx(サーバー側のIPアドレス)
接続出来ない場合は、サーバー側のTCP 5001番(デフォルト)が利用出来るか、セキュリティグループ、ネットワークACLを見直してください。
計測結果
参考にシンガポールも計測しました。
それぞれ10回計測し、上位2値と下位2値を取り除いた値の平均値を取っています。
計測値は時間帯やAZ、経路など、状況によって変わるため、参考程度に見てください。
リージョン | AZ | Mbits/sec |
---|---|---|
バージニア北部 | us-east-1b | 68.82 |
オハイオ | us-east-2b | 73.42 |
北カルフォルニア | us-west-1b | 108.66 |
オレゴン | us-west-2b | 111.8 |
シンガポール | ap-southeast-1b | 160.5 |
参考
リージョン間で同じEC2キーペアを利用する
EC2キーペアはリージョン単位で管理されます。
他リージョンで同じキーペアを利用したい場合、既に利用しているキーペアの公開鍵をインポートします。
EC2キーペアおさらい
- 公開鍵暗号方式
- ローカル側で秘密鍵を管理
- 公開鍵をAWS側(リージョン単位)で管理
- EC2 Linuxインスタンス作成時、(AWS側が)公開鍵を
~/.ssh/authorized_keys
にコピーして起動 - ローカル側はパスワードなしにSSH接続
前提条件
- ローカル上に公開鍵(*.pem.pub) または秘密鍵(*.pem)のファイルがある
ssh-keygen
が利用できる環境である
キーペアのインポート
マネジメントコンソールからインポートします。
- インポートしたいリージョンを選択
- サービス [コンピューティング] - [EC2] を選択
- ナビゲーションペインから [ネットワーク & セキュリティ] - [キーペア] を選択
- [キーペアのインポート]ボタンをクリック
公開鍵の場合
[パブリックキーをファイルからロードする] で、公開鍵(*.pem.pub)ファイルを選択します。必要に応じて、キーペア名を変更します。
[インポート]ボタンをクリックするとキーペアが作成されます。
秘密鍵の場合
秘密鍵(*.pem)から公開鍵を取得します。
ssh-keygen -y -f 秘密鍵(*.pem)ファイルのパス
パスワードがある場合は入力します。
$ ssh-keygen -y -f test.pem Enter passphrase: ******** ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDOlCcrzRabj2k5F5SO9w43Vij10u7NJFS略
ssh-rsa以降をコピーして、パブリックキーの内容にペーストします。
キーペア名を入力して、[インポート]ボタンをクリックするとキーペアが作成されます。
参考
- AWSドキュメント
- AWS Black Belt
CloudFormationスタック完了時だけメールを受信する
前回のエントリで、スタックイベントをメールで受信できるようになりました。
しかし、全てのイベントを受信するため、大量のメールが届きます。
完了時だけひょっこりメールを受け取りたい!!
最初は、メッセージのフィルタリング機能を使えばできると思ったのですが、メッセージ属性
に対してのフィルタリングであって メッセージ本文
ではできません。
そこで、間に AWS Lambda
を挟んで、完了イベントのみ再通知する仕組みを検討します。
概要
大まかな流れは以下になります。
- ユーザーがスタックを作成
- CloudFormationがスタックイベントをLambdaに送信
- Lambdaでメッセージをチェック、スタックの完了メッセージならSNSメール送信
- ユーザーがメールを受信
トピックの作成
Lambda用とMail用の2つのトピックを作成します。
サービス [アプリケーション統合] - [Simple Notification Service] を選択して、Lambda用のトピックを作成します。
Lambda用
- トピック名:
cloudformation_filter
- サブスクリプション
- ここでは作成しません。(Lambda作成時に作成される)
Mail用
- トピック名:
cloudformation
- サブスクリプション
- プロトコル:
Email
- エンドポイント:
送信したいメールアドレス
- プロトコル:
Mail用は前回の記事を参照してください。
AWS Lambdaの作成
次にLambdaを作成します。
サービス [コンピューティング] - [Lambda] を選択し、[関数の作成]ボタンをクリックします。
関数の作成
- 設計図を選択
- テキストボックスに
sns
と入力してEnterキー、設計図をフィルタリング sns-message
を選択- [設定]ボタンをクリック
基本的な情報
- 名前:
filterMessage
- ロール:
テンプレートから新しいロールを作成
- ロール名:
lambda_send_sns
- ポリシーテンプレート:
SNN 発行ポリシー
SNSトリガー
- SNSトピック:
cloudformation_filter
- トリガーの有効化:
ON
問題なければ、[関数の作成]ボタンをクリックします。
Designer
Lambdaの左側に SNS
、右側にAmazon CloudWatch
とAmazon SNS
が表示されていることを確認します。
関数コード
以下のコードを入力します。
************は自身のAWSアカウントを指定してください。
var aws = require('aws-sdk'); var sns = new aws.SNS(); let result = {}; exports.handler = async (event, context) => { try { const mail = event.Records[0].Sns; const found = mail.Message.match(/^(?=[\s\S]*ResourceStatus='CREATE_COMPLETE')(?=[\s\S]*ResourceType='AWS::CloudFormation::Stack')/); if (found) { result = await sns.publish({ Subject: mail.Subject, Message: mail.Message, TopicArn: "arn:aws:sns:ap-northeast-1:************:cloudformation" }).promise(); } } catch (err) { console.log(err); return err; } return result; };
補足
- デフォルトのランタイムは
Node.js 8.10
です。async, await, promiseを利用しています。 - 改行を含む文字列、メッセージ内に
ResourceStatus='CREATE_COMPLETE'
かつResourceType='AWS::CloudFormation::Stack'
を含む正規表現でチェックしています。 - メールの件名と本文は、受信したメールをそのまま設定しています。わかりやすい内容に変更してください。
Lambdaの保存
右上の[保存]ボタンをクリックします。
「保存されました。」と表示されれば正常です。
Lambdaのテスト
メールが受信できるか確認をします。
[テスト]ボタンをクリックして、テストイベントの設定をします。
- 新しいテストイベントの作成:
ON
- イベントテンプレート:
SNS
- イベント名:
myEvent
JSON文字列内の "Message" 値を変更します。
"Message": "ResourceStatus='CREATE_COMPLETE' ResourceType='AWS::CloudFormation::Stack'"
[作成]ボタンをクリック、テストイベントmyEvent
が選択されている状態で、再度[テスト]ボタンをクリックします。
メールが届けば成功です。これで準備が整いました。
CloudFormationスタックの作成
スタックの作成時にLambda用のトピックを指定します。
既存のAmazon SNSトピックでLambda用のcloudformation_filter
を選択します。
スタック作成後、メールが1件だけ届いたでしょうか?
まとめ
AWS Lambdaを挟むことによって、メールをフィルタリングすることが出来ました。 今回はメール通知ですが、Slackに通知したりするのも面白そうです。
参考
- AWSドキュメント
- AWS Compute Blog
CloudFormationスタックイベントをSNSでメール通知する
スタック作成時に通知オプション
を設定すると、スタックイベントの内容を通知することができます。
トピックの作成
マネジメントコンソールから、サービス [アプリケーション統合] - [Simple Notification Service] を選択します。
トピックを選択して、[新しいトピックの作成]ボタンをクリック
トピック名を入力して[トピックの作成]ボタンをクリック
トピックが作成されます。
サブスクリプションの作成
トピック一覧から作成したトピックのARN
リンクをクリックして、トピックの詳細を開きます。
[サブスクリプションの作成]ボタンをクリック
プロトコルとエンドポイントを入力します。
- プロトコル:
Email
- エンドポイント:
送信したいメールアドレス
[サブスクリプションの作成]ボタンをクリックすると、確認用のメールが送信されます。
メール内のConfirm subscription
リンクをクリックすると確認済となり、これで利用可能となります。
メールの確認
メールが受信できるか確認します。
トピックの詳細画面、左上の[トピックに発行]ボタンをクリック
件名とメッセージを入力して[メッセージの発行]ボタンをクリック
メールが届いたら成功です。
スタックの作成
CloudFormation スタック作成時に、スタックイベントがメール通知されるか確認をします。
テンプレートの選択
サンプルテンプレートの選択で、LAMP Stack
を選択します。
通知オプションの設定
[オプション] - [アドバンスト] の通知オプション 既存のAmazon SNSトピック
で、作成したトピックを指定します。
メールの確認
スタックを作成した後、メールが届いているか確認をします。イベントの件数とメール件数が一致していれば成功です。
スタック作成時だけでなく、更新、削除時もメール通知されます。
まとめ
スタックイベントをメールで受信できるようになりました。
全てのイベントを受信するため、結構な量になります。フィルタリング機能はないのでしょうか?
参考
- AWSドキュメント
- Amazon Simple Notification Service の使用開始