自分の Node イメージを構築¶
事前準備¶
Docker の概念を理解するため、導入ガイド Part 1 での説明を読み、準備をしてください。
BuildKit 有効化¶
イメージの構築を始める前に、マシン上で BuildKit を有効化します。 BuildKit があれば Docker イメージを効率的に構築できます。詳しい情報は、 BuildKit でイメージ構築 をご覧ください。
Docker Desktop 上のすべてのユーザは、デフォルトで BuildKit は有効化されています。Docker Desktop をインストール済みの場合、手動で BuildKit を有効化する必要はありません。 Linux 上で Docker を動かしている場合は、 BuildKit を有効化するため、環境変数を設定するか、 BuildKit がデフォルトになるよう設定を変更します。
docker build
コマンドの実行時、 BuildKit 環境編集を設定するには、次のように実行します。
$ DOCKER_BUILDKIT=1 docker build .
Docker で BuildKit をデフォルトで有効化するには、 /etc/docker/daemon.json
のデーモン設定で機能を true
にし、デーモンを再起動します。 daemon.json
ファイルが存在しなければ、 daemon.json
という名前でファイルを作成し、ファイル内に以下を追加します。
{
"features":{"buildkit" : true}
}
Docker デーモンを再起動します。
概要¶
これでコンテナと Docker プラットフォームの概要が分かりましたので、初めてのイメージを構築しましょう。イメージにはアプリケーションの実行に必要な全てを含みます。具体的には、コードやバイナリ、ランタイム、依存関係、必要なその他のファイルシステムです。
このチュートリアルを終えるには、以下が必要です。
Node.js バージョン 12.18 以上。 Node.js のダウンロード
Docker をローカルで実行: Docker のダウンロードとインストール の手順に従う
ファイルを編集するため、 IDE やテキストエディタ: Visual Studio Code の使用を推奨
サンプル アプリケーション¶
例として使える、簡単な Node.js アプリケーションを作りましょう。ローカルマシン内に node-docker
という名前のディレクトリを作成し、簡単な REST API を作成するため、以下の手順を進めます。
$ cd [path to your node-docker directory]
$ npm init -y
$ npm install ronin-server ronin-mocks
$ touch server.js
次は、 REST リクエストを扱うコードをいくつか追加します。Docker 化アプリケーションに集中できるようにするため、モックサーバを使います。
この作業ディレクトリを IDE で開き、以下のコードを server.js
に追加します。
const ronin = require('ronin-server')
const mocks = require('ronin-mocks')
const server = ronin.server()
server.use('/', mocks.server(server.Router(), false, true))
server.start()
モック用サーバは Ronin.js
と呼ばれ、デフォルトでポート 8000 をリッスンします。ルート(/)エンドポイントに対して POST リクエストすると、サーバに送信したあらゆる JSON 構造がメモリ内に保存されます。また、同じエンドポイントに GET リクエストを送信すると、先ほど POST 済みの JSON オブジェクトをアレイ形式で受け取ります。
アプリケーションのテスト¶
アプリケーションを起動し、正しく動作するか確認しましょう。ターミナルを開き、作成済みの作業ディレクトリに移動します。
$ node server.js
アプリケーションが正しく動作しているか確認するには、まず何らかの JSON を API に POST し、それから GET リクエストを作成し、保存されたデータを確認します。新しいターミナルを開き、以下の curl コマンドを実行します。
$ curl --request POST \
--url http://localhost:8000/test \
--header 'content-type: application/json' \
--data '{"msg": "testing" }'
{"code":"success","payload":[{"msg":"testing","id":"31f23305-f5d0-4b4f-a16f-6f4c8ec93cf1","createDate":"2020-08-28T21:53:07.157Z"}]}
$ curl http://localhost:8000/test
{"code":"success","meta":{"total":1,"count":1},"payload":[{"msg":"testing","id":"31f23305-f5d0-4b4f-a16f-6f4c8ec93cf1","createDate":"2020-08-28T21:53:07.157Z"}]}
サーバを実行しているターミナルに切り戻します。サーバログには以下のリクエストが表示されます。
2020-XX-31T16:35:08:4260 INFO: POST /test
2020-XX-31T16:35:21:3560 INFO: GET /test
すばらしい! アプリケーションの動作を確認しました。この段階では、サーバのスクリプトのテストをローカルで行いました。
サーバを実行中のターミナルセッション内で CTRL-c
を押すと、サーバが停止します。
2021-08-06T12:11:33:8930 INFO: POST /test
2021-08-06T12:11:41:5860 INFO: GET /test
^Cshutting down...
続いて、 Docker でアプリケーションの構築と実行をします。
Node.js 用の Dockerfile を作成¶
Dockerfile は Docker イメージを組み立てる命令を含むテキスト文章です。 docker build
コマンドを実行し、 Docker に対してイメージ構築を命令すると、 Docker はこれらの命令を読み込み、命令を実行し、その結果を Docker イメージとして作成します。
アプリケーションのために Dockerfile を作成する流れを見ていきましょう。プロジェクトのルートで、 Dockerfile
という名前のファイルを作成し、このファイルをテキストエディタで開きます。
注釈
Dockerfile の名前はどうしますか?
Dockerfile のデフォルトファイル名は Dockerfile
です(拡張子はありません)。デフォルトの名前を使えば、 docker build
コマンドの実行し、コマンドにフラグの追加が不要です。
プロジェクトによっては、特定の目的に対して Dockerfile を分ける必要があるでしょう。一般的な慣習として、名前を Dockerfile.<何か>
や <何か>.Dockerfile
にします。このような Dockerfile は docker build
コマンドで --file
( や省略形 -f`
)オプションを渡して利用できます。 --file
オプションについて学ぶには、 docker build
リファレンスの Dockerfile の指定(-f) を参照ください。
このガイドの大部分の例でも使われているように、プロジェクトで主となる Dockerfile には、デフォルト( Dockerfile
)の利用を推奨します。
Dockerfile の1行目に追加するのは、 # syntax パーサ ディレクティブ です。この命令は「オプション」ですが、Docker ビルダがどの Dockerfile を使って解釈するかを指定できます。さらに、古い BuildKit が入っている Docker のバージョンで構築する前に、アップグレードをできるようにします。 パーサ ディレクティブ は、 Dockerfile 内であらゆるコメント、空白、 Dockerfile より前に書く必要があるため、 Dockerfile では1行目に書くべきです。
# syntax=docker/dockerfile:1
私たちは docker/dockerfile:1
の指定を推奨します。これは、バージョン1構文の最新リリースを常に示します。 BuildKit は構築前、自動的に構文を確認するため、直近の現行バージョンを使えるようにします。
次は、Docker にアプリケーションが何のベースイメージを使うかを伝えるため、 Dockerfile に行を追加する必要があります。
# syntax=docker/dockerfile:1
FROM node:12.18.1
Docker イメージは他のイメージを
class MyImage extends NodeBaseImage {}
これは MyImage
と呼ぶクラスと作成し、基底クラス NodeBaseImage
の機能性を継承します。
同じような手法で、 FROM
コマンドのしようとは、私たちのイメージの全機能が node:12.18.1
イメージに入っていると Docker に伝えます。
注釈
自分でベースイメージを作成する方法についての情報は ベース イメージの作成 をご覧ください。
NODE_DEV
環境変数は、アプリケーションの動作環境を指定します(通常は、 development か production)。パフォーマンス改善にもっとも簡単な方法は、 NODE_ENV
を production
に指定します。
ENV NODE_ENV=production
以降のコマンドを実行しやすくるため、作業ディレクトリを作成しましょう。この命令は、以降すべてのコマンドを実行するデフォルトの場所として、指定したパスを使うよう Docker に対して伝えます。この方法によりフルパスを入力する必要がなくなりますが、その作業ディレクトリを基準とした相対パスで記述する必要があります。
WORKDIR /app
通常、 Node.js で書かれたプロジェクトをダウンロードして最初にするのは、 npm パッケージのインストールです。これにより、アプリケーションのすべての依存関係が node_modules
ディレクトリにインストールされ、 Node ランタイムがそれらを見つけられるようになります。
npm install
を実行する前に、 package.json
と package-lock.json
ファイルをイメージの中に入れる必要があります。そのためには COPY
命令が使えます。 COPY
命令は2つのパラメータ、 src
と dest
を使います。1つめのパラメータ src
は、 Docker に対して何のファイル(群)をイメージにコピーするかを伝えます。2つめのパラメータ dest
は、 Docker に対してファイル(群)をどこにコピーしたいか伝えます。以下は例です。
COPY ["<src>", "<dest>"]
複数の src
リソースをカンマで区切りで指定でいます。たとえば、 COPY ["<src1>", "<src2>",..., "<dest>"]
です。ここでは package.json
と package-lock.json
ファイルを、作業ディレクトリ /app
にコピーします。
COPY ["package.json", "package-lock.json*", "./"]
注意として、作業ディレクトリ全体をコピーするのではなく、 package.json ファイルのみコピーします。これにより、 Docker レイヤのキャッシュを活用できます。イメージ内にファイルが入ってしまえば、 RUN
命令を使って npm install コマンドを実行できるようになります。これは、自分のマシン上でローカルに npm install を実行するのと全く同じ挙動です。ですが、今回は各 Node モジュールはイメージ内の node_modules
ディレクトリ内へインストールされます。
RUN npm install --production
この時点で、私たちのイメージは node バージョン 12.18.1 をベースにし、必要となる依存関係をインストールしました。次に必要なのは、ソースコードをイメージの中に追加します。先ほど package.json
ファイルで行ったように、 COPY
コマンドを使います。
COPY . .
この COPY コマンドは、現在のディレクトリ内にある全てのファイルを取得し、すべてをイメージの中にコピーします。次は、イメージの実行時、コンテナ内で実行したいコマンドが何かを Docker に伝える必要があります。これを CMD
命令で行います。
CMD [ "node", "server.js" ]
これが完成した Dockerfile です。
# syntax=docker/dockerfile:1
FROM node:12.18.1
ENV NODE_ENV=production
WORKDIR /app
COPY ["package.json", "package-lock.json*", "./"]
RUN npm install --production
COPY . .
CMD [ "node", "server.js" ]
.dockerignore ファイルの作成¶
構築コンテクスト(訳者注:docker build で指定したディレクトリ内に含まれる、ファイルなどの中身のこと)内でファイルを使うために、 Dockerfile は COPY 命令のような命令で指定されたファイルを参照します。構築時のパフォーマンスを上げるには、、ファイルやディレクトリを除外するため、コンテクストがあるディクトリに .dockerignore ファイルを追加します。コンテクストの読み込み時間を減らすため、 .dockerignore
ファイルを追加し、その中に node_module
ディレクトリを追記します。
node_modules
イメージ構築¶
これで Dockerfile が作成できましたので、イメージを構築しましょう。そのためには docker build
コマンドを使います。 docker build
コマンドは Dockerfile と "コンテクスト" からイメージを構築します。構築コンテクストとは、指定したパスまたは URL 内に置かれているファイル群です。 Docker 構築プロセスは、コンテクスト内に置かれているあらゆるファイルにアクセス可能です。
build コマンドは、オプションで --tag
フラグを付けられます。 名前:タグ
の形式でイメージ名とオプションのタグを設定できます。今はオプションの「タグ」を省略し、シンプルにします。タグを渡さなければ、 Docker はデフォルトのタグ「latest」を使います。この様子は、構築時の最後の出力で確認できます。
はじめての Docker イメージを構築しましょう。
$ docker build --tag node-docker .
[+] Building 93.8s (11/11) FINISHED
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 617B 0.0s
=> [internal] load .dockerignore 0.0s
...
=> [2/5] WORKDIR /app 0.4s
=> [3/5] COPY [package.json, package-lock.json*, ./] 0.2s
=> [4/5] RUN npm install --production 9.8s
=> [5/5] COPY . .
ローカルイメージの表示¶
ローカルのマシン上にあるイメージを一覧表示するには、2つの方法があります。1つは CLI を使う方法と、もう1つは Docker Desktop を使う方法です。ここまでターミナル上で作業をしてきましたので、 CLI でイメージ一覧を見てみましょう。
イメージを一覧表示するには、シンプルに images
コマンドを実行します。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
node-docker latest 3809733582bc About a minute ago 945MB
実際の出力は様々ですが、イメージの一覧には先ほど構築した node-docker:latest
と、 latest
タグのあるイメージが確認できるでしょう。
イメージにタグ付け¶
イメージ名は、スラッシュ記号で区切られた名前の要素で構成されます。名前の要素には、小文字の文字列、数字、
イメージは
先ほど構築したイメージに新しいタグを作成するには、以下のコマンドを実行します。
$ docker tag node-docker:latest node-docker:v1.0.0
docker tag
コマンドはイメージに新しいタグを作成しますが、新しいイメージは作成しません。タグが示すのは同じイメージであり、そのイメージを別の方法で参照しているだけです。
次は docker images
コマンド実行し、ローカルにあるイメージの一覧を表示します。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
node-docker latest 3809733582bc 24 minutes ago 945MB
node-docker v1.0.0 3809733582bc 24 minutes ago 945MB
node-docker
から始まる2つのイメージが表示されています。 IMAGE ID 列を見ると、2つのイメージの値は同じに見えますので、どちらも同じイメージだと分かります。
先ほど作成したタグを消しましょう。そのためには、 rmi コマンドを使います。rmi コマンドは「
$ docker rmi node-docker:v1.0.0
Untagged: node-docker:v1.0.0
Docker の応答から分かるのは、イメージは削除しておらず、単に「
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
node-docker latest 3809733582bc 32 minutes ago 945MB
私たちのイメージは、タグ :v1.0.0
が削除されたものの、まだ node-docker:latest
タグはマシン上で利用可能です。
次のステップ¶
この章では、以降のチュートリアルで使うサンプル Node アプリケーションの設定方法を説明しました。また、Docker イメージ構築に使う Dockerfile を作成しました。それから、イメージにタグをつけ、イメージからタグを削除する方法を説明しました。次の章では、コンテナとしてイメージを実行する方法を説明します。
フィードバック¶
フィードバックを通し、このトピックの改善を支援ください。考えがあれば、 Docker Docs GitHub リポジトリに issue を作成して教えてください。あるいは、更新の提案のために RP を作成 してください。
参考
- Build your Python image