本記事では、Node.jsのフレームワークであるExpress.jsを使用してシンプルなWebアプリケーションを開発し、それをDockerでコンテナ化した後、AWSのElastic Beanstalkを使ってデプロイする一連のプロセスを解説する。

環境

"express": "^4.19.2"

Dockerバージョン: 4.26.1

手順

1. Express.jsアプリケーションのセットアップ
2. Dockerを使用したコンテナ化
3. AWS Elastic Beanstalkへのデプロイ

1. Express.jsアプリケーションのセットアップ

まず、Node.jsとExpress.jsを使って基本的なWebアプリケーションを作成する。

$ mkdir my-express-app
$ cd my-express-app
$ npm init -y
$ npm install express

アプリケーションのコード

index.jsファイルを作成し、以下のコードを記述。/にアクセスした際、「Hello World!」を返すAPI。

const express = require('express');
const app = express();
const port = process.env.PORT || 3000;

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

app.listen(port, () => {
  console.log(`App listening on port ${port}`);
});

2. Dockerを使用したコンテナ化

Dockerを使用して、アプリケーションをコンテナ化する。

Dockerのインストール

Dockerが未インストールの場合は、Docker公式サイトからインストールすること。

Dockerfileの作成

プロジェクトのルートディレクトリにDockerfileを作成し、以下の内容を記入する。

# Node.jsの公式イメージをベースとして使用
FROM node:18

# アプリケーションディレクトリを設定
WORKDIR /usr/src/app

# アプリケーションの依存ファイルをインストール
COPY package*.json ./

# npmの依存関係をインストール
RUN npm install

# アプリケーションのソースをコピー
COPY . .

# アプリケーションがリッスンするポートを指定
EXPOSE 3000

# アプリケーションの実行
CMD ["npm", "start"]

Dockerイメージのビルド

ターミナルで以下のコマンドを実行し、Dockerイメージをビルドする。

$ docker build -t my-express-app .

ちなみに、上記my-node-appはDockerイメージ名であり、Expressアプリケーションのディレクトリ名ではない。この名前はDockerイメージを識別するために使われ、Dockerイメージが何をするものか(この場合はNode.jsとExpressを使用したアプリケーション)を示している。

Dockerコンテナの実行

ビルドしたイメージからコンテナを起動する。

$ docker run -p 3000:3000 my-express-app

成功すると以下のような出力となる。

[+] Building 111.2s (10/10) FINISHED                       docker:desktop-linux
 => [internal] load .dockerignore                                          0.0s
 => => transferring context: 2B                                            0.0s
 => [internal] load build definition from Dockerfile                       0.0s
 => => transferring dockerfile: 535B                                       0.0s
 => [internal] load metadata for docker.io/library/node:18                 3.7s
 => [1/5] FROM docker.io/library/node:18@sha256:xxxxxxxxxxxxxx  105.5s
 => => resolve docker.io/library/node:18@sha256:xxxxxxxxxxxxxxcf  0.0s
 => => sha256:xxxxxxxxxxxxxxcfxxxxxxxxxxxxxxcf 2.00kB / 2.00kB  0.0s
 => => sha256:xxxxxxxxxxxxxxcf 49.60MB / 49.60MB  33.0s
 => => sha256:xxxxxxxxxxxxxxcf 23.58MB / 23.58MB  19.6s
 => => sha256:xxxxxxxxxxxxxxcfa32b1cb909d4720d9a 1.21kB / 1.21kB  0.0s
 => => sha256:xxxxxxxxxxxxxxcf 7.40kB / 7.40kB  0.0s
 => => sha256:xxxxxxxxxxxxxxcf 63.99MB / 63.99MB  50.0s
 => => sha256:xxxxxxxxxxxxxxcf 202.54MB / 202.54MB  99.0s
 => => extracting sha256:xxxxxxxxxxxxxxcf68d34b81  1.5s
 => => sha256:xxxxxxxxxxxxxxcf 3.37kB / 3.37kB  33.7s
 => => sha256:xxxxxxxxxxxxxxcf 45.69MB / 45.69MB  67.0s
 => => extracting sha256:xxxxxxxxxxxxxxcf  0.4s
 => => extracting sha256:xxxxxxxxxxxxxxcf95c7607b  1.7s
 => => sha256:xxxxxxxxxxxxxxcf 2.21MB / 2.21MB  53.5s
 => => sha256:xxxxxxxxxxxxxxcf 451B / 451B  53.8s
 => => extracting sha256:xxxxxxxxxxxxxxcf069b221c2f  4.5s
 => => extracting sha256:xxxxxxxxxxxxxxcfea716b  0.0s
 => => extracting sha256:xxxxxxxxxxxxxxcf6fcf995f  1.5s
 => => extracting sha256:xxxxxxxxxxxxxxcf  0.0s
 => => extracting sha256:xxxxxxxxxxxxxxcf  0.0s
 => [internal] load build context                                          0.1s
 => => transferring context: 2.21MB                                        0.1s
 => [2/5] WORKDIR /usr/src/app                                             0.6s
 => [3/5] COPY package*.json ./                                            0.0s
 => [4/5] RUN npm install                                                  1.2s
 => [5/5] COPY . .                                                         0.1s
 => exporting to image                                                     0.0s 
 => => exporting layers                                                    0.0s 
 => => writing image sha256:xxxxxxxxxxxxxxcf  0.0s
 => => naming to docker.io/library/my-node-app                             0.0s

What's Next?
  View a summary of image vulnerabilities and recommendations → docker scout quickview

これで、イメージ my-node-app が正しく作成され、使用する準備が整ったので、AWS Elastic Beanstalkへのデプロイを行う。

3. AWS Elastic Beanstalkへのデプロイ

AWS CLIとElastic Beanstalk CLIのインストール

AWS CLIおよびElastic Beanstalk CLI (ebcli) が必要なので未インストールの場合は以下のコマンドでインストールする。

$ pip install awsebcli

ちなみに、インストール済みであるかどうかは以下のコマンドで確認できる。

$ eb --version

EB CLI 3.20.10 (Python 3.11.3 (v3.11.3:f3909b8bc8, Apr  4 2023, 20:12:10) [Clang 13.0.0 (clang-1300.0.29.30)])

Elastic Beanstalkアプリケーションの初期化

プロジェクトディレクトリで以下のコマンドを実行する。

eb init -p docker my-express-app -r ap-northeast-1

Application my-express-app has been created.

成功したら、`Application my-express-app has been created.`と表示される。

環境の作成とアプリケーションのデプロイ

以下のコマンドを実行し、Elastic Beanstalk環境を作成し、アプリケーションをデプロイする。

eb create my-express-env

成功すれば、AWSコンソール > Elastic Beanstalk > 環境 > my-express-app > ドメインをブラウザで開くことで「Hello World!」が表示される。

TypeScript対応

1. TypeScript の設定

必要なパッケージをインストールする。プロジェクトディレクトリがすでにあると仮定して、次のコマンドを実行

$ npm install typescript @types/node @types/express --save-dev

TypeScript の設定ファイル(tsconfig.json)をプロジェクトのルートに生成する。

$ npx tsc --init

生成された tsconfig.json ファイルを開き、必要に応じて以下のように編集する。

{
  "compilerOptions": {
    "target": "es6",                                // コンパイルされるJavaScriptのバージョン
    "module": "commonjs",                           // モジュールシステム
    "outDir": "./dist",                             // トランスパイルされたファイルの出力ディレクトリ
    "strict": true,                                 // 厳格な型チェックオプション
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],                          // トランスパイルするファイルのディレクトリ
  "exclude": ["node_modules"]                       // 除外するディレクトリ
}

Express アプリケーションをTypeScriptで記述する。

import express, { Application, Request, Response } from 'express';

const app: Application = express();
const port = process.env.PORT || 3000;

app.get('/', (req: Request, res: Response) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

ビルドスクリプトの設定

"scripts": {
  "build": "tsc",
  "start": "node dist/index.js",
  "dev": "ts-node src/index.ts"
}
カテゴリー: awsNode.js