Node.jsサービスDockerコンテナアプリケーション実践のまとめ

Node.jsサービスDockerコンテナアプリケーション実践のまとめ

この記事では、Docker コマンドの使用とインストールについては説明しません。Docker を基礎から実践まで使い始める方法を説明した前回の記事ですでに詳しく説明されているからです。よくわからない場合は、リンクをクリックして戻ってもう一度読んでください。この記事の焦点は、Node.js プロジェクトで Docker コンテナ化を使用する方法と、いくつかの実用的な最適化、およびいくつかの一般的な問題を紹介することです。もちろん、使用に関して他に質問がある場合は、コメントエリアにメッセージを残してください。

著者について: Wu Yuejun、Nodejs 開発者、テクノロジーを愛し、共有することを好む 90 年代以降の若者、公開アカウント「Nodejs Technology Stack」、Github オープンソース プロジェクト www.nodejs.red

この記事から何を学べますか?

  • Docker で Node.js サービスをコンテナ化する方法を学ぶ
  • 環境変数を動的に設定して、1 つの Dockerfile で異なるバージョンをビルドする
  • イメージをビルドするときに Node.js プライベート NPM パッケージを認証する方法
  • Egg.jsフレームワークのDockerコンテナ化を使用する際に注意すべき問題
  • Docker イメージのサイズとビルド時間の最適化

Node.js アプリケーションを Docker 化する

この記事では、まず簡単な Node.js アプリケーションを作成し、次にそのアプリケーション用の Docker イメージを作成し、ビルドして実行します。

Node.js プロジェクトの作成

まず、HTTP サービスを開始するための app.js を作成し、次に Docker を使用してこのプログラムを実行する必要があります。

定数 http = require('http');
ポート = 30010;

定数サーバ = http.createServer((req, res) => {
 res.end('Hello Docker');
})

server.listen(PORT, () => {
 console.log('http://localhost: で実行中', PORT, 'NODE_ENV', process.env.NODE_ENV);
});

次に、アプリケーションと必要な依存関係を記述する package.json ファイルを作成します。Node.js を作成したことがある学生であれば、Node.js に非常に精通しているはずです。ここでは、ビルド時にパラメーターを渡して環境変数を動的に設定する方法を紹介したいため、スクリプトにnpm run devnpm run proの 2 つのコマンドを追加しました。

{ 
 "名前": "hello-docker", 
 "バージョン": "1.0.2",
 "説明": ""、 
 "著者": "5月",
 "メイン": "app.js", 
 「スクリプト」: {
 "dev": "NODE_ENV=dev ノード app.js",
 "pro": "NODE_ENV=pro ノード app.js"
 }
}

Dockerファイル

これは Dockerfile ファイルに含まれる情報です。これらのコマンドについては、「Getting Started with Docker」および「Practice」でも説明されています。

ノード:10.0-alpineから

apk --update add tzdata を実行してください \
 && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
 && echo "アジア/上海" > /etc/timezone \
 && tzdata の apk

mkdir -p /usr/src/nodejs/ を実行します。

ワークディレクトリ /usr/src/nodejs/

# npm パッケージを追加
package.json をコピー /usr/src/nodejs/package.json
cd /usr/src/nodejs/ を実行します。
npm i を実行する

# コードをコピー
./usr/src/nodejs/ をコピーします。

エクスポーズ30010

CMD npm run dev

ローカルデバッグファイル、node_modules、その他のファイルをDockerコンテナに配置しないように、Dockerfileと同じレベルに.dockerignoreファイルを作成します。

.git
ノードモジュール
npm-debug.log

この時点で、次のコマンドを使用して Docker イメージをビルドできます。

$ docker イメージビルド -t mayjun/hello-docker

その後、docker run -d -p 30010:30010 mayjun/hello-docker コマンドで Docker コンテナを実行できますが、質問があります。本番環境とテスト環境を区別しています。上記のCMD npm run devによると、パッケージ化できる環境は 1 つだけです。もちろん、それを実装するためのファイルを作成したり、他の方法を使用することもできます。

環境変数を動的に設定する

上記の疑問を解決するために、イメージをビルドするときにパラメータを渡して環境変数を動的に設定し、Dockerfile ファイルを変更するというアイデアがあります。次の実装を参照してください。

エクスポーズ30010

ARG node_env # 新しく追加されたENV NODE_ENV=$node_env # 新しく追加されたCMD npm run ${NODE_ENV} # 変更

以下は上記のコードの説明です

  • ARGディレクティブは、docker buildコマンドの--build-arg=フラグを使用して、ビルド時にユーザーがビルダーARG node_envに渡すことができる変数を定義します。
  • Dockerfileでこの変数ENV NODE_ENV=$node_envを参照するにはENVを使用します。
  • このステップではCMD npm run ${NODE_ENV}を使用します。

残っているのは、イメージを構築するときにパラメータを動的に渡すことだけです。

$ docker image build --build-arg node_env=dev -t mayjun/hello-docker:1.0.2 . # テスト環境を構築します $ docker image build --build-arg node_env=pro -t mayjun/hello-docker:1.0.2 . # 本番環境を構築します

コンテナの実行

$ docker run -d -p 30010:30010 mayjun/hello-docker:1.0.2
$ docker ps
コンテナID イメージ コマンド 作成ステータス ポート名
2bc6e62cd0e8 mayjun/hello-docker:1.0.2 "/bin/sh -c 'npm run..." 3 分前 3 分前にアップ 0.0.0.0:30010->30010/tcp elastic_bouman

コンテナログを表示する

docker ログ -f 2bc6e62cd0e8

> [email protected] dev /usr/src/nodejs
> NODE_ENV=dev ノード app.js

http://localhost:30010 NODE_ENV dev で実行中

上記のコードをミラー mayjun/hello-docker:1.0.2 にパッケージ化しました。これはプルして表示できます。 docker pull mayjun/hello-docker:1.0.2

Docker および Node.js プライベート NPM パッケージ

プロジェクトでプライベート NPM パッケージを使用している場合、Docker のイメージ構築プロセス中に npm プライベート パッケージをインストールすると 404 エラーが発生します。コンテナー外であれば、npm login を使用して NPM プライベート パッケージの権限を持つアカウントにログインすることでこの問題を解決できますが、Docker ではこれができません。

認証トークンの作成

プライベート パッケージをインストールするには、継続的インテグレーション環境と Docker コンテナでプライベート NPM パッケージにアクセスできるように、「認証トークンを作成」する必要があります。作成方法については、https://docs.npmjs.com/creating-and-viewing-authentication-tokens を参照してください。

実装

Dockerfile ファイルを作成するときに、次の 2 つのコマンドを追加する必要があります。

# 528das62-e03e-4dc2-ba67-********** このトークンはあなたのために作成された認証トークンです
実行 echo "//registry.npmjs.org/:_authToken=528das62-e03e-4dc2-ba67-***********" > /root/.npmrc
cat /root/.npmrcを実行します。

EggフレームワークDockerコンテナ化

Egg では、 egg-scripts start --daemonの場合は、 --daemon を削除してegg-scripts start のみを使用します。そうしないと、Docker コンテナの起動に失敗します。

次のコード例を参照して、package.json を変更します。Dockerfile は、上記の最初のDockerized Node.js アプリケーションと同じです。

パッケージ.json

{
 「スクリプト」: {
 "start": "egg-scripts start" // --daemon を削除
 }
}

Egg の問題「Docker コンテナを実行できません。これに遭遇した人はいますか?」も参照してください。https://github.com/eggjs/egg/issues/1543

Docker イメージのサイズとビルド時間の最適化

画像が最適化されていない場合、そのサイズは通常非常に大きくなります。以下は実際に行われた最適化の一部です。

実行/コピーレイヤー

Dockerfile 内の各命令はイメージ レイヤーを作成します。各イメージ レイヤーは、Dockerfile 命令やコピーされたプロジェクト ファイルを変更せずに再利用およびキャッシュできます。

mayjun/hello-docker:latest イメージリポジトリには、次のコードがあります。次の例では、ソースコードが変更された後、package.json が変更されたかどうかに関係なく、NPM モジュールが再インストールされます。これは明らかに良くないので、以下を改善する必要があります。

# ...

ワークディレクトリ /usr/src/nodejs/hello-docker
コピー . /usr/src/nodejs/hello-docker

npmインストールを実行

# ...

改善したコードは以下のとおりです。package.json を進化させます。package.json を変更しないと NPM パッケージが再インストールされないため、デプロイ時間も短縮されます。

# ...

ワークディレクトリ /usr/src/nodejs/

# npm パッケージを追加
package.json をコピー /usr/src/app/package.json
cd /usr/src/app/ を実行します。
npm i を実行する

# コードをコピー
コピー . /usr/src/app/

# ...

Node.js Alpine イメージの最適化

mayjun/hello-docker:1.0.0 このイメージはDockerリポジトリでも検索できます。最適化前は約688MBです。

$ docker images リポジトリ タグ イメージ ID 作成サイズ mayjun/hello-docker 1.0.0 7217fb3e9daa 5 秒前 688MB

Alpineによる最適化

Alpine は非常に小さな Linux ディストリビューションです。イメージのサイズを大幅に削減したい場合は、Node.js の Alpine バージョンを選択するのが最も簡単です。また、alpine のデフォルトのタイムゾーンは国内のタイムゾーンではないため、Dockerfile でタイムゾーンを設定する必要があります。

ノード:10.0-alpineから

apk --update add tzdata を実行してください \
 && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
 && echo "アジア/上海" > /etc/timezone \
 && tzdata の apk

RUN echo "Asia/Shanghai" > /etc/timezone

mkdir -p /usr/src/nodejs/ を実行します。

ワークディレクトリ /usr/src/nodejs/

# npm パッケージを追加
package.json をコピー /usr/src/app/package.json
cd /usr/src/app/ を実行します。
npm i を実行する

# コードをコピー
コピー . /usr/src/app/

エクスポーズ30010
CMD npm スタート

mayjun/hello-docker:1.1.0 バージョンを再パッケージ化し、再度効果を確認しました。イメージ ファイルが 688 MB から 85.3 MB に削減されていることがわかります。このサイズの最適化は、まだ非常に大きいです。

$ docker イメージ
リポジトリ タグ イメージ ID 作成 サイズ
mayjun/hello-docker 1.1.0 169e05b8197d 3分前 85.3MB

運用環境ではdevDependenciesをパッケージ化しないでください

テスト環境で使用される一部のパッケージは、本番環境をミラーリングするときに含めないでください。つまり、package.jsonファイル内のdevDependenciesオブジェクトは、npm iの後に--productionパラメータを指定してフィルタリングできます。

改善点は次のとおりです。

ノード:10.0-alpineから

# 省略...

# npm パッケージを追加
package.json をコピー /usr/src/app/package.json
cd /usr/src/app/ を実行します。
RUN npm i --production # ここで変更 # 省略...

mayjun/hello-docker:1.2.0 のバージョンを再パッケージ化し、再度効果を確認しました。イメージファイルが 85.3MB から 72.3MB に削減されていることがわかります。

$ docker イメージ
リポジトリ タグ イメージ ID 作成 サイズ
mayjun/hello-docker 1.2.0 f018aa578711 3秒前 72.3MB

よくある質問

質問1

次のコマンドは、イメージを削除するときに次のエラーを報告します。

$ docker rmi 6b1c2775591e
デーモンからのエラー応答: 競合: 6b1c2775591e を削除できません (強制する必要があります) - イメージが複数のリポジトリで参照されています

注意深く見てみると、イメージ ID 6b1c2775591e が hello-docker リポジトリと mayjun/hello-docker リポジトリの両方を指していることがわかり、これが削除が失敗した理由です。

$ docker イメージ
リポジトリ タグ イメージ ID 作成 サイズ
mysql 5.7 383867b75fd2 6日前 373MB
hello-docker 最新 6b1c2775591e 7日前 675MB
mayjun/hello-docker 最新 6b1c2775591e 7日前 675MB

削除するリポジトリとタグを指定します。削除コマンドを実行した後、再度確認すると mayjun/hello-docker リポジトリが消えていることがわかります。

$ docker rmi mayjun/hello-docker
$ docker イメージ   
リポジトリ タグ イメージ ID 作成 サイズ
mysql 5.7 383867b75fd2 6日前 373MB
hello-docker 最新 6b1c2775591e 7日前 675MB

質問2

イメージ削除コマンドを実行すると、次のエラーが報告されます。

$ docker rmi 9be467fd1285
デーモンからのエラー応答: 競合: 9be467fd1285 を削除できません (強制できません) - イメージは実行中のコンテナ 1febfb05b850 によって使用されています

プロンプトによると、実行中のコンテナがあります。まずコンテナを停止し、コンテナを削除してから、イメージを削除する必要があります。

$ docker container kill 1febfb05b850 # コンテナを停止します $ docker rm 1febfb05b850 # コンテナを削除します $ docker rmi 9be467fd1285 # イメージを削除します

質問3

作業ディレクトリ(WORKDIR)の設定は、次のとおりにする必要があります。

...
ワークディレクトリ /usr/src/nodejs/

# npm パッケージを追加
COPY package.json /usr/src/node/package.json # ディレクトリの不整合 RUN cd /usr/src/node/ # ディレクトリの不整合 RUN npm i
...

たとえば、上記の構成が作業ディレクトリと実際の COPY ディレクトリと一致していない場合、次のエラーが報告されます。

次に、次のように変更します。

...
ワークディレクトリ /usr/src/nodejs/

# npm パッケージを追加
COPY package.json /usr/src/nodejs/package.json # 同じRUNに変更 cd /usr/src/nodejs/ # 同じRUNに変更 npm i
...

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • TypeScriptを使用してNode.jsアプリケーションを開発する方法を教えます
  • LuvitはNode.jsのようなLuaアプリケーションを作成します
  • Node.js の子プロセスとアプリケーション シナリオに関する簡単な説明
  • Node.js のパフォーマンスを向上させるアプリケーションのヒントを共有する
  • Node.js の基本的なアプリケーションについてどれくらい知っていますか?

<<:  MYSQL8.0.13 無料インストール版 設定チュートリアル例 詳細説明

>>:  Windows環境でのMySQL 8.0.13無料インストールバージョンの設定チュートリアル

推薦する

LinuxでIPを表示する方法の例

ネットワークの問題のトラブルシューティング、新しい接続のセットアップ、ファイアウォールの構成を行うと...

MySQLインデックスが失敗するいくつかの状況の分析

1. 最左プレフィックス原則 - 複数の列にインデックスが付けられている場合は、最左プレフィックス原...

SMS送信のカウントダウンを実装するJavaScript

この記事では、SMS送信のカウントダウンを実装するためのJavaScriptの具体的なコードを参考ま...

ホームページのデザインはウェブデザイナーのレベルを最もよく反映する

私がこれまで携わってきた多くのプロジェクトでは、基本的に避けられない悪循環がありました。それは、ホー...

npm 淘宝ミラー変更説明

1. トップレベルの使用法1. cnpmをインストールする npm i -g cnpm --regi...

ウェブページヘッダーの最適化の提案

ロゴの最適化: 1.ロゴ画像はできるだけ小さくしてください。 2. 一般的には背景として配置されます...

CSS 動的読み込みバー効果のサンプルコード

CSS変数の知識を使って、追加したコードとコメントを直接投稿します <!DOCTYPE htm...

MySQL Index Pushdown (ICP) とは何かを理解するための記事

目次1. はじめに2. 原則III. 実践3.1 インデックスプッシュダウンを使用しない3.2 イン...

Linux システムで Code Cloud にプロジェクトをアップロードする方法

Code Cloudで新しいプロジェクトtest1を作成します。 公開鍵を取得するには次のコマンドを...

HTMLで境界線を設定する3つの方法の詳細な説明

HTML で境界線を設定する 3 つの方法 境界線の幅: 1px 2px 2px; 境界線のスタイル...

mysql-connector-java8.0.27 へのアップグレードに関する注意事項

最近、オンライン セキュリティ スキャンにより、MySQL コネクタに脆弱性が見つかりました。確認し...

データベースの冗長フィールドを合理的に使用する方法

privot は、多対多の関係の中間テーブルです。 PT5 フレームワークは自動的に privot ...

モバイルの赤い封筒の雨機能ページを実装するための JavaScript HTML

この記事の例では、モバイル紅包雨機能ページを実現するためのHTMLの具体的なコードを共有しています。...

純粋な CSS ヘッダーの実装コードを修正

純粋な CSS で固定ヘッダーを実装するのが難しい主な理由は 2 つあります。まず、最大のシェアを持...

古い Vue プロジェクトに Vite サポートを追加する方法

1. はじめに会社のプロジェクトを引き継いで2年になります。今では毎回プロジェクトを起動するのに1分...