Docker 環境で Node.js Express Webサービスを起動する
こんにちは、@studio_meowtoon です。今回は、WSL Ubuntu の Docker 環境で、Node.js Express Web アプリケーションをコンテナとして起動する方法を紹介します。
目的
Windows 11 の Linux でクラウド開発します。
こちらから記事の一覧がご覧いただけます。
実現すること
ローカル環境の WSL Ubuntu の Docker 環境で、Dockerfile からビルドした Node.js Express Web サービスのカスタムコンテナイメージを起動します。
JS ファイルのアプリをコンテナとして起動
実行環境
要素 | 概要 |
---|---|
terminal | ターミナル |
Ubuntu | OS |
Docker | コンテナ実行環境 |
Web サービス コンテナ
要素 | 概要 |
---|---|
app-hello-express | カスタムコンテナ |
node.js | Node.js 実行環境 |
server.js | JS スクリプト |
express | Web サーバー |
技術トピック
Express とは?
こちらを展開してご覧いただけます。
Express
Express は、軽量で柔軟な Web アプリケーションフレームワークです。Node.js 上で動作し、簡単なルーティングやミドルウェアを提供します。
キーワード | 内容 |
---|---|
ミニマルなフレームワーク | Express は Node.js 用のミニマルなウェブフレームワークであり、不要な複雑さを排除しつつ、ウェブアプリケーションの構築に必要な基本的な機能を提供します。 |
簡単なルーティング | シンプルで柔軟なルーティングシステムを提供し、HTTP リクエストのハンドリングと異なるエンドポイントのルートを定義するのが簡単です。 |
ミドルウェアのサポート | Express はミドルウェアの利用を可能にし、リクエストとレスポンスオブジェクトを変更する関数を追加できます。これにより、認証、ログ出力などの機能を簡単に追加できます。 |
テンプレートエンジンの統合 | Express は EJS、Pug、Handlebars などのさまざまなテンプレートエンジンとの統合をサポートし、動的なビューを簡単にレンダリングできます。 |
強力な HTTP ユーティリティ | Express は GET、POST、PUT、DELETE などの HTTP 動詞を扱うための HTTP ユーティリティメソッドを提供します。 |
モジュール性 | Express はモジュール性を奨励し、再利用可能なミドルウェアとルートハンドラーを作成することができます。 |
大規模なコミュニティ | 大きく活発なコミュニティが存在し、多数のライブラリやモジュールが提供されており、他のツールやサービスとの簡単な統合が可能です。 |
スケーラビリティ | ベースとなる Node.js の特性により、Express は多数の同時接続を処理することができるため、スケーラビリティに優れています。 |
ミドルウェアエコシステム | Express は豊富なサードパーティのミドルウェアエコシステムを利用できるため、アプリケーションの機能を簡単に拡張できます。 |
オープンソース | Express はオープンソースであり、積極的にメンテナンスが行われているため、安定性とセキュリティを確保しています。 |
Dockerfile とは?
こちらを展開してご覧いただけます。
Dockerfile
Dockerfile は、Docker コンテナを構築するためのテキストファイルです。Docker コンテナはアプリケーションやサービスを実行するための環境を含む軽量でポータブルな仮想化ユニットです。
キーワード | 内容 |
---|---|
スクリプト形式 | Dockerfile はシンプルなスクリプト形式で記述されるため、コンテナのビルドプロセスを自動化することが容易です。 |
レイヤー構造 | Docker イメージは Dockerfile の各命令が実行される際にレイヤーとして生成され、再利用やキャッシュが可能な構造となっています。 |
バージョン管理 | Dockerfile はテキストベースであるため、コードと同様にバージョン管理システムで管理しやすいです。 |
ポータビリティ | Dockerfile により、アプリケーションとその依存関係が1つのコンテナイメージにパッケージ化されるため、異なる環境間での移植性が高まります。 |
自動化と効率化 | Dockerfile を使用することで、アプリケーションのビルドや環境構築を自動化できます。これにより、手動での作業時間やヒューマンエラーが減り、開発・デプロイプロセスが効率的になります。 |
再現性 | Dockerfile はビルド手順を完全に定義するため、異なる環境で同じアプリケーションを再現できます。これにより、開発、テスト、本番環境間での一貫性が確保されます。 |
環境の分離 | Docker コンテナはホストシステムから分離されるため、アプリケーションの依存関係やライブラリの衝突を回避し、より安全な環境で実行できます。 |
拡張性 | Dockerfile を使用することで、カスタムイメージを作成することができます。このため、特定のニーズに合わせてカスタマイズされたコンテナイメージを容易に作成できます。 |
開発環境
- Windows 11 Home 22H2 を使用しています。
WSL の Ubuntu を操作していきますので macOS の方も参考にして頂けます。
WSL (Microsoft Store アプリ版) ※ こちらの関連記事からインストール方法をご確認いただけます
> wsl --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
Ubuntu ※ こちらの関連記事からインストール方法をご確認いただけます
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
npm ※ こちらの関連記事からインストール方法をご確認いただけます
$ node -v
v19.8.1
$ npm -v
9.5.1
Docker ※ こちらの関連記事からインストール方法をご確認いただけます
$ docker --version
Docker version 23.0.1, build a5ee5b1
この記事では基本的に Ubuntu のターミナルで操作を行います。Vim を使用してコピペする方法を初めて学ぶ人のために、以下の記事で手順を紹介しています。ぜひ挑戦してみてください。
作成する Web アプリケーションの仕様
No | エンドポイント | HTTPメソッド | MIME タイプ |
---|---|---|---|
1 | /api/data | GET | application/json |
/api/data というエンドポイントに対して HTTP GET リクエストを送信すると、JSON データがレスポンスされるシンプルな Web サービスを実装します。
{"message":"Hello World!"}
Hello World を表示する手順
プロジェクトの作成
プロジェクトフォルダを作成します。
※ ~/tmp/hello-express をプロジェクトフォルダとします。
$ mkdir -p ~/tmp/hello-express
$ cd ~/tmp/hello-express
JS ファイルの作成
server.js JS ファイルを作成します。
$ mkdir -p backend/src
$ vim backend/src/server.js
ファイルの内容
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
app.get('/api/data', (req, res) => {
const response = {
message: "Hello World!"
};
res.json(response);
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
webpack 設定の作成
webpack.config.js ファイルを作成します。
$ vim backend/webpack.config.js
ファイルの内容
const path = require('path');
module.exports = {
mode: 'development',
target: 'node',
entry: './src/server.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'server.bundle.js',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
};
プロジェクトの初期化
プロジェクトの初期化を行います。
$ cd backend
$ npm init -y
package.json を修正します。
$ vim package.json
ファイルの内容
{
"name": "hello-express",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"start": "node build/server.bundle.js",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC"
}
ライブラリをインストールします。
$ npm install express --save
$ npm install babel-loader @babel/core @babel/preset-env \
webpack webpack-cli --save-dev
ローカルでビルド・実行します。
停止するときは ctrl + C を押します。
$ npm run build
$ npm start
別ターミナルから curl コマンドで確認します。
$ curl -v http://localhost:5000/api/data -w '\n'
出力
* Trying 127.0.0.1:5000...
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET /api/data HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: application/json; charset=utf-8
< Content-Length: 26
< ETag: W/"1a-iEQ9RXvkycqsT4vWvcdHrxZT8OE"
< Date: Fri, 04 Aug 2023 05:10:15 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
* Connection #0 to host localhost left intact
{"message":"Hello World!"}
ここまでの手順で、ターミナルに {"message":"Hello World!"} と表示され、JSON データを取得することが出来ました。
コンテナイメージをビルド
Dockerfile を作成します。
$ vim Dockerfile
ファイルの内容
# build the app.
FROM node:lts-bookworm-slim as build-env
# set the working dir.
WORKDIR /app
# copy json files to the working dir.
COPY package.json package-lock.json /app/
COPY webpack.config.js /app/
# copy the source files to the working dir.
COPY src /app/src
# install dependencies listed in package.json.
RUN npm install
# run the build command to build the app.
RUN npm run build
# set up the production container.
FROM node:lts-bookworm-slim
# set the working dir.
WORKDIR /app
# install dumb-init for process management.
RUN apt-get update && \
apt-get install -y dumb-init
# copy the build output from the build-env.
COPY --from=build-env /app/build /app/build
# install express.
RUN npm install express
# expose port.
EXPOSE 5000
# command to run the app.
CMD ["dumb-init","node","build/server.bundle.js"]
Docker デーモンを起動します。
$ sudo service docker start
* Starting Docker: docker [ OK ]
Docker 環境をお持ちでない場合は、以下の関連記事から Docker Engine のインストール手順をご確認いただけます。
コンテナイメージをビルドします。
$ docker build \
--no-cache \
--tag app-hello-express:latest .
コンテナイメージを確認します。
$ docker images | grep app-hello-express
app-hello-express latest 6c3f5b84bbf4 31 seconds ago 269MB
ここまでの手順で、ローカル環境の Docker にアプリのカスタムコンテナイメージをビルドすることができました。
コンテナを起動
ローカルでコンテナを起動します。
※ コンテナを停止するときは ctrl + C を押します。
$ docker run --rm \
--publish 5000:5000 \
--name app-local \
app-hello-express:latest
ここまでの手順で、ローカル環境の Docker でアプリのカスタムコンテナを起動することができました。
コンテナの動作確認
別ターミナルから curl コマンドで確認します。
$ curl -v http://localhost:5000/api/data -w '\n'
出力
* Trying 127.0.0.1:5000...
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET /api/data HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: application/json; charset=utf-8
< Content-Length: 26
< ETag: W/"1a-iEQ9RXvkycqsT4vWvcdHrxZT8OE"
< Date: Thu, 03 Aug 2023 07:12:50 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
<
* Connection #0 to host localhost left intact
{"message":"Hello World!"}
ここまでの手順で、ターミナルに {"message":"Hello World!"} と表示され、JSON データを取得することが出来ました。
コンテナの状態を確認してみます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f505344b0132 app-hello-express:latest "docker-entrypoint.s…" 5 minutes ago Up 5 minutes 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp app-local
コンテナに接続
別ターミナルからコンテナに接続します。
$ docker exec -it app-local /bin/sh
コンテナに接続後にディレクトリを確認します。
※ コンテナから出るときは ctrl + D を押します。
# pwd
/app
# ls -lah
total 44K
drwxr-xr-x 1 root root 4.0K Aug 10 01:53 .
drwxr-xr-x 1 root root 4.0K Aug 10 02:20 ..
drwxr-xr-x 2 root root 4.0K Aug 10 01:53 build
drwxr-xr-x 60 root root 4.0K Aug 10 01:53 node_modules
-rw-r--r-- 1 root root 22K Aug 10 01:53 package-lock.json
-rw-r--r-- 1 root root 53 Aug 10 01:53 package.json
top コマンドで状況を確認します。
# apt update
# apt install procps
# top
top - 02:28:08 up 2:37, 0 user, load average: 0.13, 0.03, 0.01
Tasks: 4 total, 1 running, 3 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.1 sy, 0.0 ni, 99.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 7897.1 total, 2492.5 free, 1786.6 used, 3913.8 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 6110.5 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 2328 888 796 S 0.0 0.0 0:00.01 dumb-init
8 root 20 0 604752 51572 35612 S 0.0 0.6 0:00.11 node
15 root 20 0 2576 868 776 S 0.0 0.0 0:00.01 sh
203 root 20 0 8560 4464 2596 R 0.0 0.1 0:00.00 top
コンテナの情報を表示してみます。
$ cat /etc/*-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
このコンテナは Debian GNU/Linux をベースに作成されています。つまり、Debian GNU/Linux と同じように扱うことができます。
ディレクトリ・ファイル構成
プロジェクトのファイル構成を表示してみます。
$ tree -I 'node_modules'
.
└── backend
├── Dockerfile
├── build
│ └── server.bundle.js
├── package-lock.json
├── package.json
├── src
│ └── server.js
└── webpack.config.js
まとめ
WSL Ubuntu の Docker 環境で、Dockerfile からビルドした Node.js Express Web サービスのカスタムコンテナを起動することができました。
クラウド開発においては、Dockerfile の理解は重要です。自動ビルドツールもありますが、手動で書く必要があるケースもあります。Ubuntu を使うと Linux の知識も身に付きます。最初は難しく感じるかもしれませんが、徐々に進めていけば自信を持って書けるようになります。
どうでしたか? WSL Ubuntu で、Node.js Express Web アプリケーションを手軽に実行することができます。ぜひお試しください。今後も Node.js の開発環境などを紹介していきますので、ぜひお楽しみにしてください。
推奨コンテンツ
関連記事
Java Spring Boot