虎の穴開発室ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

本番で使えるFargate環境構築

qiita.com

こんにちは、はじめまして。虎の穴ラボのはっとりです。

虎の穴ラボ Advent Calendar 2020 - Qiita - Qiita 7日目の記事になります。

6日目はT.MさんのSaaSに関する記事です。

toranoana-lab.hatenablog.com

8日目は、礒部さんの画像判別ボットに関する記事です。

toranoana-lab.hatenablog.com

新規サービスに携わることになり、その際AWS Fargateを使った環境構築を担当したので構築方法を共有します。

この記事で話さないこと

  • アプリケーション側の作り
    • こちらはまた別の機会に紹介したいと思います。
  • 構成管理ツールなどによる環境構築
    • 特定のツールによる環境構築ではなくGUIでもできる手順にしています。

全体構成

今回紹介する範囲での全体構成は下記の通りです。

アプリケーションはfront と backに分けており、frontは画面HTMLを返し、backはAPIを返します。

front,back共にLB経由でインターネットからのアクセスを受け付けますが、 front側でSSRする場合は Route53 の名前解決を利用してLBを経由せずにbackのAPIへアクセスします。

f:id:toranoana-lab:20201203210536p:plain
全体構成

本番環境で構築するということで、可用性を重視し下記のことを達成できる構成にしています。

  • MultiA-Z構成である
  • オートスケールできる

構築手順

VPC作成

サービス > VPC > VPC >「VPCを作成」

まずVPCを作成します。

ここでは IPv4 CIDR ブロック: 10.0.0.0/16 として作成しました。

以降の手順でVPCの項目がある場合はこれを設定します。

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

サービス > VPC > インターネットゲートウェイ

適当な名前を付けて作成します。 ここではmy-igwという名前で作ります。

作成後、「アクション」>「VPC にアタッチ」で先程作成したVPCを選択します。

ルートテーブル作成

サービス > VPC > ルートテーブル

先程作成したVPCに3つのルートテーブルを作成します。 ここでは、それぞれpublic,dbという名前で2つのルートテーブルを作ります。

public は直接インターネットに接続するLBに、 dbは文字通りRDBやRedisなどに使用します。

※実はappというルートテーブルも作りますが後述

作成したら public を選び ルートの編集 を行います。

ルートの追加 を押し、 送信先には 0.0.0.0/0 を設定 ターゲットは「Internet Gateway」を選ぶと先程作成したインターネットゲートウェイが表示されるのでそれを選びルートの保存をします。

f:id:toranoana-lab:20201204092523p:plain

dbの方は初期値のままです。

サブネット作成

サービス > VPC > サブネット

3種類のサブネット作成します。各役割は下記です。

名前 説明
public-** LBなどインターネットから直接繋ぐものに割当
app-** アプリケーションに割当
db-** DBなど外部から直接接続しないものに割当

MultiA-Z構成にしたいので各アベイラビリティーゾーン(AZ)に1つずつ作成します。 今回は ap-northeast-1a と ap-northeast-1c の2つのAZを使用します。(もちろん3つのAZを使うのもありです。)

サブネット名 アベイラビリティーゾーン IPv4 CIDR ブロック
public-01 ap-northeast-1a 10.0.0.0/24
public-02 ap-northeast-1c 10.0.1.0/24
app-01 ap-northeast-1a 10.0.50.0/24
app-02 ap-northeast-1c 10.0.51.0/24
db-01 ap-northeast-1a 10.0.100.0/24
db-02 ap-northeast-1c 10.0.101.0/24

サブネット名以外が間違っていた場合は、一度削除して作成し直しする必要があるため、 今のうちにアベイラビリティーゾーン や IPv4 CIDR ブロック が計画どおりに作成されているか確認しておきましょう。

各サブネットを作成したらルートテーブルと関連付けします。 サブネット、ルートテーブルどちらからでも関連付けの設定はできますが、 ルートテーブルからサブネットの関連付けをした方がまとめて設定できるので楽です。

サブネット名 関連付けするルートテーブル
public-01 public
public-02 public
app-01 public
app-02 public
db-01 db
db-02 db

NAT ゲートウェイ作成

※こちらはアプリケーションに固定IPを付けたい場合に行いますが、 結構いいお値段するので固定IPが不要ならこの手順は飛ばしてください。

サービス > VPC > NAT ゲートウェイ

NAT ゲートウェイは使用するAZ分作成します。

NAT ゲートウェイ名 サブネット
nat-gw-01 public-01
nat-gw-02 public-02

作成時に「Elastic IP の割り当て」を押すか、作成済み Elastic IPを紐付けます。

Elastic IPもNATゲートウェイ数分必要になります。

Elastic IPは作成上限があるので気をつけてください。(申請で増やせるようですが)

NAT ゲートウェイを使用するルートテーブル作成

※固定IPが不要な場合は飛ばしてください。

サービス > VPC > ルートテーブル

作成したNATゲートウェイを使用するルートテーブルを作成し、それをサブネットに割り当てます。

まず、作成したNATゲートウェイ数分、ルートテーブルを作成します。ここでは名前をrt-app-01,rt-app-02とします。

作成したら rt-app-01を選び「ルートの編集 」からルートの追加 を押し、 インターネットゲートウェイのときと同じ要領で 送信先には 0.0.0.0/0 を設定します。

ターゲットは「Nat Gateway」を選ぶと先程作成したNATゲートウェイが表示されるので、その中からnat-gw-01を選びルートの保存をします。

同じ手順でrt-app-02にnat-gw-02を設定するようにします。

ルートの設定が終わったらapp-**のサブネットの紐付けを変えます。

サブネット名 関連付けするルートテーブル
app-01 rt-app-01
app-02 rt-app-02

セキュリティグループ

サービス > EC2 > セキュリティグループ

いろいろなやり方や方針があるとは思いますが、ここではサブネットの役割で分けることにします。

セキュリティグループ名
public
app
db

アウトバウンドルールはデフォルトのままで、 インバウンドルールを以下のように設定していきます。

セキュリティグループpublicの設定内容

HTTP、HTTPSを一般公開します

タイプ ソース
HTTP 0.0.0.0/0
HTTPS 0.0.0.0/0

セキュリティグループappの設定内容

LBからのアクセスとアプリケーション同士の通信のためポートを開けます。

タイプ ポート範囲 ソース
カスタムTCP (※) セキュリティグループ public
カスタムTCP (※) セキュリティグループ app

※Dockerコンテナがlistenしているポートを指定する必要があります。

セキュリティグループdbの設定内容

アプリケーションからDBへアクセスするため、MySQLとRedisのポートを開けます。

タイプ ポート範囲 ソース
MYSQL/Aurora 3306 セキュリティグループ app
カスタムTCP 6379 セキュリティグループ app

AuroraDB作成

DBサブネットグループ作成

サービス > RDS > サブネットグループ

適当なサブネットグループ名を付け、VPCを選択します。

アベイラビリティーゾーンは ap-northeast-1a と ap-northeast-1c を選択し、 それぞれのrds用サブネットを選択します。 (付けた名前が出ないのでIPで判別しましょう。)

パラメータグループ

サービス > RDS > パラメータグループ

主にこちらを参考にさせていただきました。 https://qiita.com/C_HERO/items/4929502c2641b2406475

データベース作成

サービス > RDS > データベース

「データベース作成」から下記の項目を設定しました。 載せていない部分はデフォルトのままにしています。

項目名 設定内容
データベース作成方法を選択 標準作成(Default)
エンジンのタイプ Amazon Aurora(Default)
エディション MySQL との互換性を持つ Amazon Aurora(Default)
キャパシティータイプ プロビジョニング済み(Default)
レプリケーション機能 シングルマスター(Default)
バージョン Aurora (MySQL5.7) 2.09.0 ※当時の最新
テンプレート 本番稼働用(Default)
DB クラスター識別子 ※ユニークな名前
マスターユーザー名 ※任意の名前
パスワード自動生成 チェック
DBインスタンスサイズ db.t3.medium ※価格を確認し最適なものを選びましょう
可用性と耐久性 別の AZ で Aurora レプリカ/リーダーノードを作成する (可用性のスケーリングに推奨)(Default)
Virtual Private Cloud (VPC) 作成したもの
サブネットグループ 作成したもの
パブリックアクセス可能 なし(Default)
VPC セキュリティグループ セキュリティグループdb
データベースポート 3306(Default)
データベース認証 パスワード認証(Default)
最初のデータベース名 (※アプリ名)_(※環境名)
DB クラスターのパラメータグループ 作成したもの
DB パラメータグループ default.aurora-mysql5.7
フェイルオーバー優先順位 指定なし(Default)
RDSバックアップ保持期間 1日(Default)
ログのエクスポート 監査ログ,エラーログ,スロークエリログ

オートスケールも設定できますが、今回の紹介では省略します。

Elastic Cache (Redis)作成

サブネットグループ作成

サービス > ElasticCache > サブネットグループ

適当なサブネットグループ名を付け、VPCを選択します。

アベイラビリティーゾーンは ap-northeast-1a と ap-northeast-1c を選択し、 それぞれのredis用サブネットを選択します。

Redis作成

サービス > ElasticCache > Redis

「作成」から下記の項目を設定しました。 載せていない部分はデフォルトのままにしています。

項目名 設定内容
名前 ※任意の名前
エンジンバージョンの互換性 6.x(Default)
ポート 6379(Default)
パラメータグループ default.redis6.x(Default)
ノードのタイプ cache.m3.medium (3GiB) ※価格を確認し最適なものを選びましょう
レプリケーション数 2
マルチAZ チェックつける
サブネットグループ 作成済みのもの
アベイラビリティーゾーンの配置 指定なし(Default)
セキュリティグループ セキュリティグループdb
保管時の暗号化 チェックつける
暗号化キー デフォルト
送信中の暗号化 チェックつける
アクセスコントロールオプション Redis AUTH デフォルトユーザー
Redis 認証トークン ※ランダムなものを生成し設定

ターゲットグループ

front-app, back-app 2つのターゲットグループを作成します。

front-app

項目名 設定内容
名前 ※任意の名前
Choose a target type IP adresses
Target group name front-app
Protocol / Port HTTP / (※)
VPC 作成済みのもの
Protocol version HTTP1
ヘルスチェック ※frontアプリが正常起動時に200を返すパス

back-app

項目名 設定内容
名前 ※任意の名前
Choose a target type IP adresses
Target group name back-app
Protocol / Port HTTP / (※)
VPC 作成済みのもの
Protocol version HTTP1
ヘルスチェック ※backアプリが正常起動時に200を返すパス

※Dockerコンテナがlistenしているポートを指定する必要があります。

LB作成

サービス > EC2 > ロードバランサー

「ロードバランサーの作成」からロードバランサーの種類選択に行くので「Application Load Balancer」の「作成」を押します。

下記の項目を設定。また 「リスナーの追加」でHTTPSを追加します。

項目名 設定内容
名前 ※任意の名前
スキーム インターネット向け
IPアドレスタイプ ipv4
VPC 作成済みのもの
アベイラビリティーゾーンap-northeast-1a チェックをつけpublic-01を選択
アベイラビリティーゾーンap-northeast-1c チェックをつけpublic-02を選択

次の手順に行き、証明書の登録または選択をします。

次の手順に行き、セキュリティグループを選択します。セキュリティグループはpublicを選択します。

次の手順に行き、ルーティングの設定をします。 後でもっと細かい設定をしますが、ここでは以下を設定するだけにしておきます。

項目名 設定内容
ターゲットグループ 既存のターゲットグループ
名前 front-app

次の手順に行き、ターゲットの登録は何もせず 次の手順に行きます。

設定内容を確認したら作成をします。

作成したロードバランサーを選択し、リスナータブを開きます。

http://へのアクセスをhttps://にリダイレクトする設定を入れます。

HTTPの「ルールの表示編集」を選択します。

デフォルトアクション以外の項目を削除し、デフォルトアクションについているアクションを一旦消してから「アクションの追加」を選択し、画像の用に設定します。 f:id:toranoana-lab:20201204131127p:plain

作成したロードバランサーのリスナータブに戻り、HTTPSの方の「ルールの表示編集」を選択します。 デフォルトアクションには front-app が設定されていると思うので ルールを追加します。

/api/* へのアクセスは、back-appの方に転送されるよう画像の通りに設定します。 f:id:toranoana-lab:20201204134257p:plain

Fargate環境作成

はい、やっと登場しました。

アプリケーションのイメージをECRへ登録

サービス > Elastic Container Service > (Amazon ECR)リポジトリ

「リポジトリを作成」からリポジトリ名を入力して作成します。

作成したリポジトリを選択し「プッシュコマンドの表示」を押すと、ローカルPCに作成したコンテナイメージを登録するためのコマンドが表示されるので、その通りに実施します。

front用、back用それぞれ登録します。

クラスター作成

サービス > Elastic Container Service > (Amazon ECS)クラスター

※Amazon EKSにもClustersがあるので間違えないように

クラスターの作成から「ネットワーキングのみ 〜 AWS Fargate を使用」を選択、次のステップでクラスター名だけ入力し作成します。

タスク定義作成(back用)

サービス > Elastic Container Service > (Amazon ECS)タスク定義

「新しいタスク定義の作成」を押すと起動タイプの互換性の選択が出るので「FARGATE」を選択し次のステップへ行きます。

下記の内容を設定します。

項目名 設定内容
タスク定義名 back-app
タスクの実行 IAM ロール ecsTaskExecutionRole ※ない場合は「新しいロールの作成」を選択
タスクメモリ 2GB ※価格や必要なスペックを確認し設定しましょう
タスクCPU 1 vCPU ※価格や必要なスペックを確認し設定しましょう

「コンテナの追加」から下記の内容を設定します。

項目名 設定内容
コンテナ名 ※任意の名前
イメージ 作成済みのECRのURI
ポートマッピング ※アプリケーションのポート
環境変数 ※データベース接続先設定などはここで設定

サービス作成(back用)

サービス > Elastic Container Service > (Amazon ECS)クラスター > 作成済みクラスター

サービスのタブから「作成」を開きます。

サービス設定を下記のように設定します。記載がない場合はデフォルトのままにしています。

項目名 設定内容
起動タイプ FARGATE
タスク定義 作成済みのback用のものを選択
サービス名 back-app
タスクの数 ※MultiA-Z構成にする場合は2以上で

次へ行き、ネットワーク構成の設定を下記のように設定します。

項目名 設定内容
クラスターVPC 作成済みのものを選択
サブネット app-01,app-02を選択
セキュリティグループ ※「編集」から「既存のセキュリティグループの選択」> セキュリティグループappを選択
パブリック IP の自動割り当て ※固定IPの設定(NAT ゲートウェイの設定)をした場合はDISABLE、そうでない場合はENABLE
ロードバランシング Application Load Balancer
ロードバランサー名 作成済みのものを選択
ロードバランス用のコンテナ ※最初にアクセスを受け取るコンテナを選択後、「ロードバランサーに追加」
プロダクションリスナーポート 443:HTTPS
ターゲットグループ名 back-app
サービスの検出の統合の有効化 チェックする
名前空間 新しいプライベート空間の作成
名前空間名 local
サービス検出サービスの設定 新しいサービス検出の作成
サービスの検出名 back-app

名前空間を設定しておくとLBを経由しない通信用のエンドポイントが作成されます。 エンドポイントは(サービスの検出名).(名前空間名)として作成され、 今回の場合だと back-app.local になります。

次へ行き、Auto Scalingを下記のように設定します。

項目名 設定内容
タスクの最小数 サービス設定のタスク数と同じ数
タスクの必要数 サービス設定のタスク数と同じ数
タスクの最大数 サービス設定のタスク数より大きい数
ポリシー名 ※任意の名前
ECS サービスメトリクス ECSServiceAverageCPUUtilization
ターゲット値 60

とりあえず、CPUが60%を超えたらスケールアウトする設定にしていますが、最適値にするためには検証が必要です。

最後に「サービスの作成」を押して完了です。

タスク定義作成(front用)

back用アプリ設定ができたので、front用の設定をしていきます。

サービス > Elastic Container Service > (Amazon ECS)タスク定義

基本的にはback用と同じですが、違うのはコンテナ名とイメージのURIくらいです。

あとは、back用のアプリにLB経由しないアクセスをする場合のエンドポイント(今回の場合はback-app.local)の値を環境変数に設定する必要があります。

サービス作成(front用)

サービス > Elastic Container Service > (Amazon ECS)クラスター > 作成済みクラスター

サービスのタブから「作成」を開きます。

サービス設定を下記のように設定します。記載がない場合はデフォルトのままにしています。

項目名 設定内容
起動タイプ FARGATE
タスク定義 作成済みのfront用のものを選択
サービス名 front-app
タスクの数 ※MultiA-Z構成にする場合は2以上で

次へ行き、ネットワーク構成の設定を下記のように設定します。

項目名 設定内容
クラスターVPC 作成済みのものを選択
サブネット app-01,app-02を選択
セキュリティグループ ※「編集」から「既存のセキュリティグループの選択」> セキュリティグループappを選択
パブリック IP の自動割り当て ※固定IPの設定(NAT ゲートウェイの設定)をした場合はDISABLE、そうでない場合はENABLE
ロードバランシング Application Load Balancer
ロードバランサー名 作成済みのものを選択
ロードバランス用のコンテナ ※最初にアクセスを受け取るコンテナを選択後、「ロードバランサーに追加」
プロダクションリスナーポート 443:HTTPS
ターゲットグループ名 front-app
サービスの検出の統合の有効化 チェックする
名前空間 新しいプライベート空間の作成
名前空間名 local
サービス検出サービスの設定 新しいサービス検出の作成
サービスの検出名 front-app

次へ行き、Auto Scalingを下記のように設定します。

項目名 設定内容
タスクの最小数 サービス設定のタスク数と同じ数
タスクの必要数 サービス設定のタスク数と同じ数
タスクの最大数 サービス設定のタスク数より大きい数
ポリシー名 ※任意の名前
ECS サービスメトリクス ECSServiceAverageCPUUtilization
ターゲット値 60

最後に「サービスの作成」を押して完了です。

CodePipeline

継続的にデプロイさせるためにこちらを参考に設定しました。

dev.classmethod.jp

あとがき

Fargate環境構築といいつつ、本番用を考慮するとFargate以外の部分の設定をしっかりやっていかないといけないです。

今まで本番環境用インフラ構築を担当したことがなかったため、 サブネットやルートテーブルなど概念もよくわかっていない状態から始めたのでとても苦労しましたが、 何とかここまで構築することができました。

qiita.com

以降も続々記事が公開されますので、ご期待ください。

P.S.

カジュアル面談

弊社エンジニアと1on1で話せます、カジュアル面談も現在受付中です!こちらも是非ご検討ください。 yumenosora.connpass.com

その他採用情報

虎の穴ラボでの開発に少しでも興味を持っていただけた方は、採用説明会やカジュアル面談という場でもっと深くお話しすることもできます。ぜひお気軽に申し込みいただければ幸いです。 カジュアル面談では虎の穴ラボのエンジニアが、開発プロセスの内容であったり、「今期何見ました?」といったオタクトークから業務の話まで何でもお応えします。 カジュアル面談や採用情報はこちらをご確認ください。 yumenosora.co.jp