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無料インストールバージョンの設定チュートリアル

推薦する

Vue.js ソースコード解析のカスタム手順の詳細な説明

序文コア機能のデフォルトの組み込みディレクティブ (v-model および v-show) に加えて...

CSS ハート型読み込みアニメーションのソースコードの実装

さっそく、コードをお見せしましょう。コードは非常にシンプルなので、勉強すれば理解できるようになります...

CentOS8でのDockerの使い方の詳しい説明

1. CentOS8でのDockerのインストール カール https://download.doc...

MySQL データベース データのロード 複数の用途

目次MySQL Load Dataの多様な用途1. LOAD の基本的な背景2. 基本パラメータをロ...

Dockerfile を使用して Docker イメージをカスタマイズする方法

Dockerfile を使用したイメージのカスタマイズイメージのカスタマイズとは、実際には各レイヤー...

知っておくべき 25 の Vue のヒント

目次1. プロパティを型リストに制限する2. デフォルトのコンテンツと拡張ポイント3. ネストされた...

サイトマップをウェブページの下部に配置するメリットと例

以前は、ほとんどすべての Web サイトに、すべてのページをリストしたサイトマップ ページがありまし...

CSS 属性セレクタを使用して HTML DNA を接合する方法

CSS 属性セレクターは素晴らしいです。大量のクラス名を追加することを回避し、コード内の問題を指摘す...

CentOS SVN サーバーで複数のプロジェクトを管理する方法

一つの要求一般的に、企業には複数のプロジェクトがあります。SVN サーバーを設定した後は、プロジェク...

Vue2/vue3 ルーティング権限管理方法の例

1. Vueルーティングの権限制御には一般的に2つの方法がありますa. ルーティングメタ情報(メタ)...

ウェブデザイナーは3つの側面からウェブページを最適化する必要がある

<br />帯域幅の増加に伴い、Web ページ上のオブジェクトも増えているため、Web ...

Spark と Scala を使用して Apache アクセス ログを分析する方法

インストールまず、Java と Scala をインストールし、次に Spark をダウンロードしてイ...

Vueはダイアログのカプセル化を実装します

目次Vue2 ライティングVue3プラグインのバージョンの記述Vue3 動的コンポーネントの記述書き...

MySQL 4.1/5.0/5.1/5.5/5.6の主な違い

バージョン間でのコマンドの違い: innodb ステータスを表示\G mysql-5.1 エンジン ...

MySQL 5.7 のスロークエリログの時間がシステム時間より 8 時間遅れている理由の詳細な説明

遅いクエリをチェックすると、時間が正しくなく、システム時間とちょうど 8 時間異なっていることがわか...