過去5年間、Node.jsはプロの開発者の間で トッププラットフォームとしての地位を維持してきました 。 これは、スループットを最大化するように設計されたオープンソースのクロスプラットフォームのJavaScriptランタイム環境です。 Node.jsは、イベント駆動型のノンブロッキングI/Oモデルを使用しているため、軽量で効率的であり、データ集約型のリアルタイム分散アプリケーションに最適です。
90,500以上の星と24,400のフォークを備えた Nodeの 開発者コミュニティは非常に活発です。 これまで以上に多くの開発者がNode.jsアプリを作成する中、ビルドとデプロイ、クロスプラットフォームの効率的な方法を見つけることが重要です。 ガイドの核心に飛び込む前に、コンテナ化がどのように役立つかについて説明しましょう。
Nodeアプリケーションをコンテナ化することが重要なのはなぜですか?
Node アプリケーションをコンテナー化することには多くの利点があります。 まず、Dockerの使いやすいCLIベースのワークフローにより、開発者はコンテナ化されたNodeアプリケーションを構築、共有、実行できます。 次に、開発者は単一のパッケージからアプリをインストールし、数分で起動して実行できます。 第 3 に、Node 開発者は、開発から本番環境までの一貫性を確保しながら、ローカルでコーディングとテストを行うことができます。
Node.jsアプリをコンテナにすばやくパッケージ化する方法を説明します。 また、イメージの脆弱性、イメージの肥大化、イメージタグの欠落、ビルドパフォーマンスの低下など、忘れがちな重要な懸念事項にも取り組みます。 簡単な ToDo リスト アプリを調べて、9 つのヒントがどのように適用されるかについて説明しましょう。
単純な ToDo リスト・アプリケーションの分析
まず、単純な ToDo リスト アプリケーションを考えてみましょう。 これは、ノード.jsバックエンド、およびMongoDBデータベースを備えた基本的なReactアプリケーションです。 完全なプロジェクトのソース コードは、 GitHub サンプル リポジトリ内で入手できます。
アプリケーションのビルド
さいわい、サンプル アプリケーションはわずか数ステップで構築できます。 まず、適切な素晴らしい作成サンプルを複製して、プロジェクトで使用する必要があります。
git clone https://github.com/dockersamples/awesome-compose/
cd awesome-compose/react-express-mongodb
docker compose -f docker-compose.yaml up -d
次に、コマンドを入力して docker compose ps
、ターミナルにサービスを一覧表示します。 これにより、すべてが考慮され、適切に機能していることが確認されます。
docker compose ps
NAME COMMAND SERVICE STATUS PORTS
backend "docker-entrypoint.s…" backend running 3000/tcp
frontend "docker-entrypoint.s…" frontend running 0.0.0.0:3000->3000/tcp
mongo "docker-entrypoint.s…" mongo running 27017/tcp
3 番目に、ブラウザーを開き、[ https://localhost:3000 ] に移動して、アプリケーションの動作を確認します。 ToDo リストの UI が表示され、アプリケーションと直接対話できるようになります。
これは、機能的なアプリケーションを短時間で起動するための優れた方法です。 ただし、これらのサンプルは、構築できる基盤であることに注意してください。 それらはあなたのニーズによりよく合うようにカスタマイズ可能です。 そして、これはパフォーマンスの観点から重要な場合があります—上記の例は完全に最適化されていないためです。 次に、可能な限り最高のアプリを構築するのに役立つ一般的な最適化のヒントなどを紹介します。
Nodeアプリケーションをコンテナ化および最適化するための9つのヒント
1)「バージョン:最新」の代わりに特定のベースイメージタグを使用する
Docker イメージをビルドするときは、バージョン情報、目的の宛先 (本番環境やテストなど)、安定性、または環境間でアプリケーションをデプロイするためのその他の有用な情報をコード化する便利なタグを指定することを常にお勧めします。
ローカル開発以外では、Docker が自動的にプルするタグに依存し latest
ないでください。 使用する latest
と予測できず、予期しない動作が発生する可能性があります。 イメージ バージョンをプル latest
するたびに、アプリケーションを破損する可能性のある新しいビルドまたはテストされていないコードが含まれている可能性があります。
ではなく、特定の node:lts-buster
Docker イメージをベースイメージ node:latest
として使用する次の点 Dockerfile
を考慮してください。このアプローチは、安定したイメージであるため lts-buster
、好ましい場合があります。
# Create image based on the official Node image from dockerhub
FROM node:lts-buster
# Create app directory
WORKDIR /usr/src/app
# Copy dependency definitions
COPY package.json ./package.json
COPY package-lock.json ./package-lock.json
# Install dependencies
#RUN npm set progress=false \
# && npm config set depth 0 \
# && npm i install
RUN npm ci
# Get all the code needed to run the app
COPY . .
# Expose the port the app runs in
EXPOSE 3000
# Serve the app
CMD ["npm", "start"]
全体として、多くの場合 FROM node:latest
Dockerfile
、.
2)マルチステージビルドを使用する
マルチステージ ビルドでは、Docker ビルドでコンパイル、パッケージ化、単体テストに 1 つの基本イメージを使用できます。 別のイメージは、アプリケーションのランタイムを保持します。 これにより、最終的なイメージのセキュリティが強化され、フットプリントが縮小されます (開発ツールやデバッグ ツールが含まれていないため)。 多段 Docker ビルドは、ビルドが 100% 再現可能で無駄のないものであることを保証するのに役立ちます。 内に Dockerfile
複数のステージを作成して、そのイメージの構築方法を制御できます。
Node アプリケーションは、多層アプローチを使用してコンテナ化できます。 各レイヤーには、ソース コード、リソース、スナップショットの依存関係など、さまざまなアプリ コンポーネントが含まれている場合があります。 前述のように、アプリケーションを独自のイメージにパッケージ化する場合はどうなりますか? それがどのように行われるかを確認するには、以下 Dockerfile
を確認してください。
FROM node:lts-buster-slim AS development
WORKDIR /usr/src/app
COPY package.json ./package.json
COPY package-lock.json ./package-lock.json
RUN npm ci
COPY . .
EXPOSE 3000
CMD [ "npm", "run", "dev" ]
FROM development as dev-envs
RUN <<EOF
apt-get update
apt-get install -y --no-install-recommends git
EOF
# install Docker tools (cli, buildx, compose)
COPY --from=gloursdocker/docker / /
CMD [ "npm", "run", "dev" ]
まず、 AS development
node:lts-buster-slim
ステートメントにラベルを追加します。これにより、このビルドステージを他のビルドステージで参照できます。 次に、というラベル dev-envs
の付いた新しい開発ステージを追加します。 このステージを使用して開発を実行します。
それでは、イメージを再構築して開発を実行しましょう。 上記と同じ docker build
コマンドを使用しますが、 --target
開発ビルドステージを具体的に実行するための開発フラグを追加します。
docker build -t node-docker --target dev-envs .
3)ノードイメージのセキュリティ脆弱性を修正する
今日の開発者は、サービスを構築する際にサードパーティのコードとアプリに依存しています。 外部ソフトウェアは、注意しないとコードに不要な脆弱性をもたらす可能性があります。 信頼できるイメージを活用し、コンテナーを継続的に監視することで、保護に役立ちます。
Docker イメージをビルド node:lts-buster-slim
するたびに、Docker Desktop は、既知の脆弱性を検出するためにイメージのセキュリティ スキャンを実行するように求めます。
Docker Desktop 用の Snyk 拡張機能 を使用して、Node.js アプリケーションを検査してみましょう。まず、 Docker Desktop 4.8.0+ を Mac、 Windows、または Linux マシンにインストールします。 次に、[設定]>[拡張機能]内のチェックボックスをオンにして、 Docker拡張機能を有効にします。
次に、左側のサイドバーにある[拡張機能の追加]ボタンをクリックしてから、Snykを検索することで、拡張機能マーケットプレイスを閲覧できます。
Snykの拡張機能を使用すると、ローカルとリモートの両方のDockerイメージをすばやくスキャンして脆弱性を検出できます。
Snykをインストールし、[ node:lts-buster-slim
イメージ名の選択]フィールドにノードドッカーの公式イメージを入力します。 スキャンを開始するには、Docker Hubにログインする必要があります。 アカウントをお持ちでなくても心配しないでください—無料で作成に数分しかかかりません。
スキャンを実行すると、Docker デスクトップ内に次の結果が表示されます。
Snykは、このスキャン中にさまざまな重大度の70の脆弱性を発見しました。 これらに気づいたら、イメージを強化するための修復を開始できます。
それだけじゃないです。 脆弱性チェックを実行するには、次のコマンド Dockerfile
を直接使用できます docker scan
。
docker scan -f Dockerfile node:lts-buster-slim
4)ヘルスチェックの活用
この命令は HEALTHCHECK
、コンテナーをテストし、それがまだ機能していることを確認する方法を Docker に指示します。 たとえば、サーバープロセスがまだ実行されている場合でも、Webサーバーが無限ループに陥り、新しい接続を処理できない場合を検出できます。
アプリケーションが運用環境に到達すると、ほとんどの場合、Kubernetes やサービス ファブリックなどのオーケストレーターがアプリケーションを管理します。 HEALTHCHECK
を使用すると、コンテナーの状態をオーケストレーターと共有して、構成ベースの管理タスクを実行できます。次に例を示します。
# syntax=docker/dockerfile:1.4
FROM node:lts-buster-slim AS development
# Create app directory
WORKDIR /usr/src/app
COPY package.json ./package.json
COPY package-lock.json ./package-lock.json
RUN npm ci
COPY . .
EXPOSE 3000
CMD [ "npm", "run", "dev" ]
FROM development as dev-envs
RUN <<EOF
apt-get update
apt-get install -y --no-install-recommends git
EOF
RUN <<EOF
useradd -s /bin/bash -m vscode
groupadd docker
usermod -aG docker vscode
EOF
HEALTHCHECK CMD curl --fail http://localhost:3000 || exit 1
# install Docker tools (cli, buildx, compose)
COPY --from=gloursdocker/docker / /
CMD [ "npm", "run", "dev" ]
```
HEALTHCHECK
が存在する場合 Dockerfile
は、コマンドを実行した後 docker ps
、 STATUS
列にコンテナーの正常性が表示されます。このチェックに合格したコンテナーは正常です。 CLI は、異常なコンテナーに異常のラベルを付けます。
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1d0c5e3e7d6a react-express-mongodb-frontend "docker-entrypoint.s…" 23 seconds ago Up 21 seconds (health: starting) 0.0.0.0:3000->3000/tcp frontend
a89721d3c42d react-express-mongodb-backend "docker-entrypoint.s…" 23 seconds ago Up 21 seconds (health: starting) 3000/tcp backend
194c953f5653 mongo:4.2.0 "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 27017/tcp mongo
Docker Compose内で(大文字と小文字の違いに注意してください)を定義する healthcheck
こともできます。 これは、を使用していない Dockerfile
ときに非常に便利です。 プレーンテキストの命令を記述する代わりに、この構成を YAML 形式で記述します。
ファイル内で docker-compose.yml
定義 healthcheck
できる設定例を次に示します。
backend:
container_name: backend
restart: always
build: backend
volumes:
- ./backend:/usr/src/app
- /usr/src/app/node_modules
depends_on:
- mongo
networks:
- express-mongo
- react-express
expose:
- 3000
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 1m30s
timeout: 10s
retries: 3
start_period: 40s
5).ドッカー無視を使用する
ビルドのパフォーマンスを向上させるには .dockerignore
、 Dockerfile
ファイルを .このチュートリアルでは、 .dockerignore
ファイルには1行だけを含める必要があります。
node_modules
この行は、 node_modules
Maven からの出力を含むディレクトリを Docker ビルドコンテキストから除外します。 慎重に構成 .dockerignore
する多くの正当な理由があります ファイルですが、今のところこの単純なファイルで十分です。
それでは build context
、説明しましょう そしてなぜそれが不可欠であるか 。 このコマンドは、 docker build
と "コンテキスト" から Dockerfile
Docker イメージをビルドします。 このコンテキストは、指定した PATH
または URL
にあるファイルのセットです。 ビルド プロセスでは、これらのファイルを参照できます。
一方、コンパイルコンテキストは開発者が作業する場所です。 これは、Mac、Windows、またはLinuxディレクトリ上のフォルダである可能性があります。 このディレクトリには、ソースコード、構成ファイル、ライブラリ、プラグインなど、必要なすべてのアプリケーションコンポーネントが含まれています。 と .dockerignore
ファイルを使用すると、新しいイメージの構築中に除外するソースコード、構成ファイル、ライブラリ、プラグインなどの次の要素のどれを決定できます。
方法 .dockerignore
は次のとおりです ビルドから除外することを選択した場合、 node_modules directory
ファイルが表示される場合があります。
バックエンド:
フロントエンド:
6)セキュリティ目的で非rootユーザーとして実行する
ユーザー特権でアプリケーションを実行すると、リスクの軽減に役立つため、より安全です。 同じことがDockerコンテナにも当てはまります。 既定では、Docker コンテナーと実行中のアプリにはルート権限があります。 したがって、Dockerコンテナは非ルートユーザーとして実行することをお勧めします。
これを行うには、内に指示 Dockerfile
を追加します USER
。この命令は USER
、イメージの実行中に優先ユーザー名 (または UID) とオプションでユーザーグループ (または GID) を設定し、後続の RUN
, CMD
または ENTRYPOINT
命令に対して設定します。
# syntax=docker/dockerfile:1.4
FROM node:lts-buster AS development
WORKDIR /usr/src/app
COPY package.json ./package.json
COPY package-lock.json ./package-lock.json
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
FROM development as dev-envs
RUN <<EOF
apt-get update
apt-get install -y --no-install-recommends git
EOF
RUN <<EOF
useradd -s /bin/bash -m vscode
groupadd docker
usermod -aG docker vscode
EOF
USER vscode
# install Docker tools (cli, buildx, compose)
COPY --from=gloursdocker/docker / /
CMD [ "npm", "start" ]
7)マルチアーキテクチャのDockerイメージを優先する
CPUは、ネイティブアーキテクチャのバイナリのみを実行できます。 たとえば、x86 システム用に構築された Docker イメージは、Arm ベースのシステムでは実行できません。 AppleがカスタムArmベースのシリコンに完全に移行しているため、x86(IntelまたはAMD)コンテナイメージがAppleのMシリーズチップで動作しない可能性があります。
そのため、 マルチアーキテクチャコンテナイメージの構築を常に推奨しました。 以下は、 mplatform/mquery
任意のパブリックレジストリ内のパブリックイメージのマルチプラットフォームステータスを照会できるDockerイメージです。
docker run --rm mplatform/mquery node:lts-buster
Unable to find image 'mplatform/mquery:latest' locally
d0989420b6f0: Download complete
af74e063fc6e: Download complete
3441ed415baf: Download complete
a0c6ee298a93: Download complete
894bcacb16df: Downloading [=============================================> ] 3.146MB/3.452MB
Image: node:lts-buster (digest: sha256:a5d9200d3b8c17f0f3d7717034a9c215015b7aae70cb2a9d5e5dae7ff8aa6ca8)
* Manifest List: Yes (Image type: application/vnd.docker.distribution.manifest.list.v2+json)
* Supported platforms:
- linux/amd64
- linux/arm/v7
- linux/arm64/v8
マルチアーキテクチャ イメージの構築に役立つコマンドを導入し docker buildx
ました。 Buildx は、使い慣れた Docker ユーザー エクスペリエンスで多くの強力なビルド機能を有効にする Docker コンポーネントです。
すべての Buildx ビルドは、 Moby BuildKit エンジンを使用して実行されます。
BuildKitは、マルチプラットフォームビルド、またはユーザーのローカルプラットフォームをターゲットにしないビルドに優れているように設計されています。 ビルドを呼び出すときに、フラグを設定して --platform
、ビルド出力のターゲットプラットフォーム(linux/amd64
、、linux/arm/v7
linux/arm64/v8
など)を指定できます。
docker buildx build --platform linux/amd64,linux/arm/v7 -t node-docker .
8)ノードのグレースフルシャットダウンオプションを調べる
Docker コンテナーは本質的に一時的なものです。 それらは停止して破壊し、最小限の労力で再構築または交換することができます。 プロセスに通知シグナルを送信する SIGTERM
ことで、コンテナを終了できます。 この短い猶予期間では、アプリが進行中の要求を処理し、リソースをタイムリーにクリーンアップしていることを確認する必要があります。
一方、Node.jsは、アプリを適切にシャットダウンするための鍵となるOSなどの SIGINT
SIGTERM
信号を受け入れて転送します。Node.js を使用すると、これらのシグナルの処理方法をアプリで決定できます。 コードを記述したり、モジュールを使用して処理したりしない場合、アプリは正常にシャットダウンされません。 タイムアウト期間後に Docker または Kubernetes が強制終了するまで、これらのシグナルは無視されます。
アプリ内 Dockerfile
で やtini などの docker run --init
特定の init オプションを使用することは、アプリコードを変更できない場合に実行可能です。
ただし、グレースフル シャットダウンのために適切なシグナル処理を処理するコードを記述することをお勧めします。
Docker の Captain Bret Fisher (12:57) によるこのビデオでは、利用可能な 3 つのノード シャットダウン オプションすべてについて詳しく説明しています。
9) OpenTelemetry API を使用して NodeJS のパフォーマンスを測定する
Node開発者はどのようにしてアプリをより速く、よりパフォーマンスの高いものにしますか? 一般に、開発者はサードパーティの可観測性ツールを使用してアプリケーションのパフォーマンスを測定します。 このパフォーマンス監視は、一流のユーザーエクスペリエンスを備えた多機能ノードアプリケーションを作成するために不可欠です。
可観測性は、アプリケーションのパフォーマンスだけにとどまりません。 メトリック、トレース、ログが前面と中央に配置されました。 メトリックは開発者がシステムの問題点を理解するのに役立ち、トレースはシステムがどのように間違っているかを発見するのに役立ちます。 ログは、それが間違っている理由を教えてくれます。 開発者は、特定のメトリックとトレースを掘り下げて、システムの動作を全体的に理解できます。
Node アプリケーションを監視するということは、Node のメトリック、リクエスト率、リクエストエラー率、およびリクエスト期間を追跡することを意味します。 OpenTelemetryは、ノード.jsアプリケーションのインストゥルメント化に役立つツールとAPIの一般的なコレクションの1つです。
SigNoz などのオープンソースツールを使用して、アプリのパフォーマンスを分析することもできます。SigNozはフルスタックの可観測性ツールを提供しているため、複数のツールに依存する必要はありません。
結論
このガイドでは、慎重に作成する Dockerfile
ことからSnykスキャンによるイメージの保護まで、Dockerイメージを最適化するための多くの方法について説明しました。 より優れたNode.jsアプリの構築は複雑である必要はありません。 いくつかのコアファンダメンタルズを釘付けにすることで、あなたは素晴らしい体調になります。
さらに詳しく知りたい場合は、安全な運用グレードの Docker イメージを構築するための追加の推奨事項とベスト プラクティスを確認してください。