1
1

Docker 環境で Node.js Express Webサービスを起動する

Last updated at Posted at 2023-08-07

Docker 環境で Node.js Express Webサービスを起動する

こんにちは、@studio_meowtoon です。今回は、WSL Ubuntu の Docker 環境で、Node.js Express Web アプリケーションをコンテナとして起動する方法を紹介します。
express_on_docker.png

目的

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

ファイルの内容

backend/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

ファイルの内容

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

ファイルの内容

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

ファイルの内容

backend/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

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1