🐼

AWS FargateにExpress.jsをデプロイする手順

2022/02/07に公開

はじめに

expressをfargateにデプロイしてみたので、備忘録としてまとめます。
こちらの記事を参考にしました。

https://qiita.com/quryu/items/532fe4c22bfc790a134c

また、所々の説明に、こちらの本を参考にさせていただいています。

https://www.amazon.co.jp/実践Terraform-AWSにおけるシステム設計とベストプラクティス-技術の泉シリーズ(NextPublishing)-野村-友規/dp/4844378139

ECRにイメージをpush

まずはECRにイメージをpushしておきます。

1、ディレクトリ作成

// ディレクトリ作成
$mkdir fargate-express
// ディレクトリに移動
$cd fargate-express

2、package.json ファイルを作成

{
  "name": "docker_web_app",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "author": "First Last <first.last@example.com>",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.1"
  }
}

3、パッケージをインストール

$npm install

4、server.js を作成
portは8080にしています。portを変更した場合は、セキュリティーグループ等に影響を与えます。

'use strict';

const express = require('express');

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';

// App
const app = express();
app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

5、動作確認
ローカルで動作確認をしておきましょう。
下記コマンド実行後、http://localhost:8080/ を確認し、Hello Worldが表示されていれば、OKです。

$node server.js

6、Dockerfile 作成
今回は、nodeのイメージをそのまま使っていますが、本番環境ではマルチステージビルド等を使ってイメージを小さくすることを推奨します。
ビルドレイヤーや、packageのインストールレイヤーではnodeのslimを使い、実行レイヤーではdistrolessなどを使うと良いのかなと思います。
(マルチステージビルドについては、どこかで記事にしたい)

FROM node:14.17.6

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 8080
CMD [ "node", "server.js" ]

7、.dockerignore ファイル作成
.dockerignoreファイルを作成して、下記を記載

node_modules
npm-debug.log

8、ビルド

ビルドしてイメージを作成しておきます。

$docker build . -t fargate-express

9、リポジトリの作成
AWSの管理画面から、リポジトリを作成します。

可視性設定: プライベート
リポジトリ名: fargate-express-repo
KMS 暗号化: 有効

10、プッシュコマンドの表示 & push
指示に従い、イメージをpushします。ここまでが、ECRにイメージをpushする一連の流れです。

VPCの作成

今回はVPCを自作しようと思います。

名前タグ: fargate-express
IPv4 CIDR ブロック: IPv4 CIDR の手動入力にチェック
IPv4 CIDR: 10.0.0.0/21
テナンシー: デフォルト

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

インターネットに繋げたいので、インターネットゲートウェイを作成して、先程作成したVPCにアタッチします。

1、インターネットゲートウェイの作成
名前タグ: fargate-express-ig

2、 作成したインターネットゲートウェイをVPC(fargate-express)にアタッチ

サブネット(1a, 1c)作成

ap-northeast-1a、ap-northeast-1cにサブネットを作成します

VPC ID: fargate-expressを選択
サブネット名: fargate-express-public-subnet-1a
アベイラビリティーゾーン: ap-northeast-1a
IPv4 CIDR ブロック: 10.0.0.0/24

サブネット名: fargate-express-public-subnet-1c
アベイラビリティーゾーン: ap-northeast-1c
IPv4 CIDR ブロック: 10.0.1.0/24

ルートテーブルの作成 & 編集

ルートテーブルを作成し、編集していきます。
個人的にルートテーブルは苦手なので、補足しておきます。
今回ルートテーブルを作成 & 編集することによって、0.0.0.0/0に関する送受信を、インターネットゲートウェイに流してくださいという設定ができます。

下記記事がわかりやすかったので、参考にしてください

[参考記事]
https://hikari-blog.com/vpc-subnet-routetable/

ルートテーブルは通信ルートの定義となります。
サブネットに関連付けます。
サブネットに関連付けられているルートテーブルにグローバルインターネットへのルートがあれば、そのサブネットはパブリックサブネットということになります。

名前: fargate-express-rt
VPC: fargate-express

  • ルートテーブルの編集(送信先は0.0.0.0/0。ターゲットは、internet gateway

  • サブネットの関連付け

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

セキュリティーグループを作成していきます。
セキュリティーグループはEC2インスタンスに適用できるファイヤーウォールのようなものという認識です。
今回インバウンドルールにポート80とポート8080を設定してます。
最初、80しか設定していなかったのですが、ヘルスチェックが通らなかったので、8080も設定しています。
ポート80でインターネットに接続できるようにして、8080で開けてるポートに接続できるようにしているのかなと思いつつ、世に出回る記事を見ていると、80しか開けていなかったりするので、このへんはまだまだ理解が不足しているなと感じます。

セキュリティグループ名: fargate-express-sg
説明: fargate-express-sg
VPC: fargate-express

インバウンドルール
タイプ: カスタムTCP
プロトコル: TCP
ポート範囲: 80
ソース: 0.0.0.0/0

タイプ: カスタムTCP
プロトコル: TCP
ポート範囲: 8080
ソース: 0.0.0.0/0

アウトバウンドルール
全許可

ターゲットグループ作成

ロードバランサーを作成する前に、ターゲットグループを作成しておきます。
ターゲットグループは、フォワード先として指定する、ターゲットを取りまとめたものです。
つまり、ロードバランシングする対象群のことです。
fargateの場合、ターゲットの種類はIPにしないとうまく動かないので注意しましょう。
ターゲットに接続するポートもここで設定できます。

ターゲットグループの名前: fargate-express-tg
ターゲットの種類: IP
プロトコル: HTTP
ポート: 80

ロードバランサー作成

ロードバランサーを作成します。
ロードバランサーは、通信を、コンテナサービス(ECS)などに、処理を振り分けることができます
今回はALBを作成します。
ALBとNLBの違いについては、雑すぎる説明をすると、HTTP(S)通信を振り分ける場合はALB、それ以外を振り分ける場合は、NLBという認識を持ってます。

セキュリティーグループは、作成したセキュリティーグループに変更してください。
リスナーとルーティングで、HTTPプロトコルの80番ポート。作成したターゲットグループを指定しましょう。

名前: fargate-express-lb
スキーム: インターネット向け
リスナー: HTTP:80
VPC: fargate-express
AZ: ap-northeast-1a, ap-northeast-1c のサブネット

セキュリティグループ名: fargate-express-sg
タイプ: カスタムTCP
プロトコル: TCP
ポート範囲: 80
ソース: カスタム 0.0.0.0/0, ::/0

ターゲットグループの名前: fargate-express-rg
ターゲットの種類: IP
プロトコル: HTTP
ポート: 80

ECS作成

いよいよECSを作成していきます。

1、クラスターの作成
クラスターは箱みたいなものです。まずは箱から作りましょう
クラスター名: fargate-express-cluster

2、タスク定義書作成
タスク定義書を作成します。
ECSではコンテナの実行単位をタスクと呼びます。
そして、タスクはタスク定義書から生成されます。
タスク定義では、コンテナ実行時の設定を記述します。
タスク定義はクラス、タスクはインスタンスのように例えられたりします。

タスク定義名: fargate-express-task
タスクロール: ecsTaskExecutionRole
タスクメモリ (GB): 0.5GB
タスク CPU (vCPU): 0.25vCPU

コンテナを追加します。
イメージURIは、ECSのリポジトリに飛ぶと確認できます。(検索窓で、ECRと検索して、リポジトリに飛んでも確認できます)
ポートマッピングは8080です

コンテナ名: fargate-express-container
イメージ: <イメージURI>
ポートマッピング: 8080

3、サービス作成
通常コンテナを起動しても、処理が完了したらすぐに終了します。
ECSサービスを使うことによって、タスクを維持することが可能になります。
ECSサービスは、起動するタスクの数を定義でき、指定した数のタスクを維持します。
何らかの理由でタスクが終了してしまった場合、自動的に新しいタスクを起動してくれます(オートスケーリング)

ECS > クラスター > 「サービス」タブ > 作成

起動タイプ: FARGATE
タスク定義: fargate-express-task
クラスター: fargate-express-cluster
サービス名: fargate-express-service
タスクの数: 2
最小ヘルス率: 50
最大率: 200

クラスター VPC: fargate-express
サブネット: ap-northeast-1a, ap-northeast-1c
ロードバランサーの種類: ALB
ロードバランサー名: fargate-express-alb

プロダクションリスナーポート: 80:HTTP
ターゲットグループ名: fargate-express-tg

起動確認

  • ECS > クラスター > 「タスク」タブから、runningになっていることを確認します

  • EC2 > ターゲットグループ > 該当のターゲットグループ選択 > Targets > statusがhealthy担っていることを確認します。

動作確認

  • EC2 > ロードバランサー > 該当のELB選択 > DNS名からDNS名をコピー

http://nuxt-fargate-load-balancer-*******.ap-northeast-1.elb.amazonaws.com/ にアクセスすると表示確認できると思います。

感想

ネットワーク周りの設定がめんどくさいですが、ECS(Fargate)自体の設定は、そんなに多くはないなというのが率直な感想です。
(と同時に、やっぱりネットワーク周りの設定が面倒なので、App runnerがプライベートサブネットでRDSを使えるようになれば良いなと思いました。)
備忘録も兼ねて、かなり詳細に記事を書いてみたので、是非fargate入門してみてください。

追記

App RunnerからVPCリソースへのアクセスが可能になりましたね。
どこかで試したい。

https://dev.classmethod.jp/articles/aws-app-runner-for-vpc/

Discussion