前書き
Dockerプラットフォームを使用すると、開発者はアプリケーションをcontainersとしてパッケージ化して実行できます。 コンテナは、共有オペレーティングシステム上で実行される独立したプロセスであり、仮想マシンに代わる軽量な代替手段を提供します。 コンテナは新しいものではありませんが、プロセスの分離や環境の標準化などの利点があり、分散アプリケーションアーキテクチャを使用する開発者が増えるにつれて重要性が増しています。
Dockerを使用してアプリケーションを構築およびスケーリングする場合の出発点は、通常、アプリケーション用のイメージを作成することです。その後、イメージをコンテナーで実行できます。 イメージには、アプリケーションコード、ライブラリ、構成ファイル、環境変数、およびランタイムが含まれます。 イメージを使用すると、コンテナ内の環境が標準化され、アプリケーションのビルドと実行に必要なもののみが含まれることが保証されます。
このチュートリアルでは、ExpressフレームワークとBootstrapを使用する静的Webサイトのアプリケーションイメージを作成します。 次に、そのイメージを使用してコンテナーを作成し、将来使用するためにDocker Hubにプッシュします。 最後に、保存されたイメージをDocker Hubリポジトリからプルして別のコンテナーを構築し、アプリケーションを再作成およびスケーリングする方法を示します。
前提条件
このチュートリアルを実行するには、次のものが必要です。
-
このInitial Server Setup guideの後にセットアップされた1つのUbuntu18.04サーバー。
-
How To Install and Use Docker on Ubuntu 18.04のステップ1と2に従って、サーバーにDockerがインストールされました。
-
Node.js and npm installed, following these instructions on installing with the PPA managed by NodeSource.
-
Docker Hubアカウント。 これを設定する方法の概要については、Docker Hubの使用を開始する際のthis introductionを参照してください。
[[step-1 -—- installing-your-application-dependencies]] ==ステップ1—アプリケーションの依存関係をインストールする
イメージを作成するには、まずアプリケーションファイルを作成する必要があります。その後、アプリケーションファイルをコンテナにコピーできます。 これらのファイルには、アプリケーションの静的コンテンツ、コード、依存関係が含まれます。
まず、非ルートユーザーのホームディレクトリにプロジェクトのディレクトリを作成します。 node_project
と呼びますが、これを他のものに自由に置き換える必要があります。
mkdir node_project
このディレクトリに移動します。
cd node_project
これがプロジェクトのルートディレクトリになります。
次に、プロジェクトの依存関係やその他の識別情報を含むpackage.json
ファイルを作成します。 nano
またはお気に入りのエディターでファイルを開きます。
nano package.json
名前、作成者、ライセンス、エントリポイント、依存関係など、プロジェクトに関する次の情報を追加します。 必ず著者情報を自分の名前と連絡先の詳細に置き換えてください。
~/node_project/package.json
{
"name": "nodejs-image-demo",
"version": "1.0.0",
"description": "nodejs image demo",
"author": "Sammy the Shark ",
"license": "MIT",
"main": "app.js",
"keywords": [
"nodejs",
"bootstrap",
"express"
],
"dependencies": {
"express": "^4.16.4"
}
}
このファイルには、プロジェクトを共有するプロジェクト名、作成者、およびライセンスが含まれています。 Npmrecommendsは、プロジェクト名を短く説明的なものにし、npm registryでの重複を回避します。 ライセンスフィールドにMIT licenseをリストし、アプリケーションコードの無料使用と配布を許可します。
さらに、指定されたファイル:
-
"main"
:アプリケーションのエントリポイントapp.js
。 次にこのファイルを作成します。 -
"dependencies"
:プロジェクトの依存関係—この場合、Express4.16.4以降。
このファイルにはリポジトリがリストされていませんが、adding a repository to your package.json
fileに関するこれらのガイドラインに従ってリポジトリを追加できます。 これは、アプリケーションをバージョン管理している場合に便利な追加機能です。
変更が完了したら、ファイルを保存して閉じます。
プロジェクトの依存関係をインストールするには、次のコマンドを実行します。
npm install
これにより、プロジェクトディレクトリのpackage.json
ファイルにリストしたパッケージがインストールされます。
これで、アプリケーションファイルの作成に進むことができます。
[[step-2 -—- creating-the-application-files]] ==ステップ2—アプリケーションファイルの作成
サメに関する情報をユーザーに提供するウェブサイトを作成します。 このアプリケーションには、メインエントリポイント、app.js
、およびプロジェクトの静的アセットを含むviews
ディレクトリがあります。 ランディングページindex.html
は、ユーザーにいくつかの予備情報と、より詳細なサメ情報sharks.html
を含むページへのリンクを提供します。 views
ディレクトリに、ランディングページとsharks.html
の両方を作成します。
まず、メインプロジェクトディレクトリでapp.js
を開き、プロジェクトのルートを定義します。
nano app.js
ファイルの最初の部分では、Expressアプリケーションとルーターオブジェクトを作成し、ベースディレクトリとポートを定数として定義します。
~/node_project/app.js
const express = require('express');
const app = express();
const router = express.Router();
const path = __dirname + '/views/';
const port = 8080;
require
関数はexpress
モジュールをロードし、それを使用してapp
およびrouter
オブジェクトを作成します。 router
オブジェクトは、アプリケーションのルーティング機能を実行します。HTTPメソッドルートを定義するときに、それらをこのオブジェクトに追加して、アプリケーションがリクエストを処理する方法を定義します。
ファイルのこのセクションでは、path
とport
の2つの定数も設定します。
-
path
:ベースディレクトリを定義します。これは、現在のプロジェクトディレクトリ内のviews
サブディレクトリになります。 -
port
:アプリにリッスンしてポート8080
にバインドするように指示します。
次に、router
オブジェクトを使用してアプリケーションのルートを設定します。
~/node_project/app.js
...
router.use(function (req,res,next) {
console.log('/' + req.method);
next();
});
router.get('/', function(req,res){
res.sendFile(path + 'index.html');
});
router.get('/sharks', function(req,res){
res.sendFile(path + 'sharks.html');
});
router.use
関数は、ルーターの要求をログに記録してアプリケーションのルートに渡すmiddleware functionをロードします。 これらは後続の関数で定義されており、ベースプロジェクトURLへのGETリクエストはindex.html
ページを返し、/sharks
ルートへのGETリクエストはsharks.html
を返すように指定しています。
最後に、router
ミドルウェアとアプリケーションの静的アセットをマウントし、ポート8080
でリッスンするようにアプリに指示します。
~/node_project/app.js
...
app.use(express.static(path));
app.use('/', router);
app.listen(port, function () {
console.log('Example app listening on port 8080!')
})
完成したapp.js
ファイルは次のようになります。
~/node_project/app.js
const express = require('express');
const app = express();
const router = express.Router();
const path = __dirname + '/views/';
const port = 8080;
router.use(function (req,res,next) {
console.log('/' + req.method);
next();
});
router.get('/', function(req,res){
res.sendFile(path + 'index.html');
});
router.get('/sharks', function(req,res){
res.sendFile(path + 'sharks.html');
});
app.use(express.static(path));
app.use('/', router);
app.listen(port, function () {
console.log('Example app listening on port 8080!')
})
完了したら、ファイルを保存して閉じます。
次に、アプリケーションにいくつかの静的コンテンツを追加しましょう。 views
ディレクトリを作成することから始めます。
mkdir views
ランディングページファイルindex.html
を開きます。
nano views/index.html
次のコードをファイルに追加します。これにより、Boostrapがインポートされ、より詳細なsharks.html
情報ページへのリンクを含むjumbotronコンポーネントが作成されます。
~/node_project/views/index.html
About Sharks
Not all sharks are alike
Though some are dangerous, sharks generally do not attack humans. Out of the 500 species known to researchers, only 30 have been known to attack humans.
Sharks are ancient
There is evidence to suggest that sharks lived up to 400 million years ago.
ここでの最上位のnavbarを使用すると、ユーザーはHomeページとSharksページを切り替えることができます。 navbar-nav
サブコンポーネントでは、Bootstrapのactive
クラスを使用して、現在のページをユーザーに示しています。 静的ページへのルートも指定しました。これは、app.js
で定義したルートと一致します。
~/node_project/views/index.html
...
...
さらに、ジャンボトロンのボタンにサメ情報ページへのリンクを作成しました。
~/node_project/views/index.html
...
...
ヘッダーにはカスタムスタイルシートへのリンクもあります。
~/node_project/views/index.html
...
...
このスタイルシートは、この手順の最後に作成します。
完了したら、ファイルを保存して閉じます。
アプリケーションのランディングページを配置したら、サメ情報ページsharks.html
を作成できます。このページでは、関心のあるユーザーにサメに関する詳細情報を提供します。
ファイルを開きます。
nano views/sharks.html
Bootstrapとカスタムスタイルシートをインポートし、特定のサメに関する詳細情報をユーザーに提供する次のコードを追加します。
~/node_project/views/sharks.html
About Sharks
Shark Info
このファイルでは、active
クラスを使用して現在のページを示していることに注意してください。
完了したら、ファイルを保存して閉じます。
最後に、最初にviews
ディレクトリにcss
フォルダを作成して、index.html
とsharks.html
でリンクしたカスタムCSSスタイルシートを作成します。
mkdir views/css
スタイルシートを開きます。
nano views/css/styles.css
ページに必要な色とフォントを設定する次のコードを追加します。
~/node_project/views/css/styles.css
.navbar {
margin-bottom: 0;
}
body {
background: #020A1B;
color: #ffffff;
font-family: 'Merriweather', sans-serif;
}
h1,
h2 {
font-weight: bold;
}
p {
font-size: 16px;
color: #ffffff;
}
.jumbotron {
background: #0048CD;
color: white;
text-align: center;
}
.jumbotron p {
color: white;
font-size: 26px;
}
.btn-primary {
color: #fff;
text-color: #000000;
border-color: white;
margin-bottom: 5px;
}
img,
video,
audio {
margin-top: 20px;
max-width: 80%;
}
div.caption: {
float: left;
clear: both;
}
このファイルは、フォントと色の設定に加えて、max-width
を80%に指定することにより、画像のサイズを制限します。 これにより、ページで希望するよりも多くのスペースを使用できなくなります。
完了したら、ファイルを保存して閉じます。
アプリケーションファイルを配置し、プロジェクトの依存関係をインストールしたら、アプリケーションを起動する準備が整いました。
前提条件の初期サーバーセットアップチュートリアルに従った場合、SSHトラフィックのみを許可するアクティブなファイアウォールがあります。 ポート8080
へのトラフィックを許可するには、次のようにします。
sudo ufw allow 8080
アプリケーションを開始するには、プロジェクトのルートディレクトリにいることを確認してください。
cd ~/node_project
node app.js
でアプリケーションを起動します。
node app.js
ブラウザをhttp://your_server_ip:8080
に移動します。 次のランディングページが表示されます。
Get Shark Infoボタンをクリックします。 次の情報ページが表示されます。
これで、アプリケーションが稼働しました。 準備ができたら、CTRL+C
と入力してサーバーを終了します。 これで、Dockerfileの作成に進むことができます。これにより、必要に応じてこのアプリケーションを再作成およびスケーリングできます。
[[step-3 -—- writing-the-dockerfile]] ==ステップ3—Dockerfileの書き込み
Dockerfileは、実行時にアプリケーションコンテナに含まれるものを指定します。 Dockerfileを使用すると、コンテナー環境を定義し、依存関係またはランタイムバージョンとの矛盾を回避できます。
these guidelines on building optimized containersに続いて、画像レイヤーの数を最小限に抑え、画像の機能を単一の目的(アプリケーションファイルと静的コンテンツの再作成)に制限することで、画像を可能な限り効率的にします。
プロジェクトのルートディレクトリで、Dockerfileを作成します。
nano Dockerfile
Dockerイメージは、相互に構築される一連のレイヤー化されたイメージを使用して作成されます。 最初のステップは、アプリケーションビルドの開始点を形成するアプリケーションのbase imageを追加することです。
https://hub.docker.com//node/[node:10-alpine
image], since at the time of writing this is the recommended LTS version of Node.js. The alpine
image is derived from the Alpine Linux project, and will help us keep our image size down. For more information about whether or not the alpine
image is the right choice for your project, please see the full discussion under the Image Variants section of the https://hub.docker.com/ / node / [Dockerハブノードの画像ページ]を使用してみましょう。
次のFROM
命令を追加して、アプリケーションのベースイメージを設定します。
~/node_project/Dockerfile
FROM node:10-alpine
この画像にはNode.jsとnpmが含まれています。 各Dockerfileは、FROM
命令で始まる必要があります。
デフォルトでは、Dockerノードイメージにはルート以外のnodeユーザーが含まれており、アプリケーションコンテナをrootとして実行しないようにするために使用できます。 コンテナをrootとして実行することを避け、プロセスの実行に必要なコンテナのみをrestrict capabilities within the containerとして実行することをお勧めします。 したがって、nodeユーザーのホームディレクトリをアプリケーションの作業ディレクトリとして使用し、コンテナ内のユーザーとして設定します。 Dockerノードイメージを操作する際のベストプラクティスの詳細については、このbest practices guideを参照してください。
コンテナ内のアプリケーションコードの権限を微調整するために、app
ディレクトリとともに/home/node
にnode_modules
サブディレクトリを作成しましょう。 これらのディレクトリを作成すると、必要なアクセス許可が確実に付与されます。これは、npm install
を使用してコンテナにローカルノードモジュールを作成するときに重要になります。 これらのディレクトリを作成することに加えて、それらの所有権をnodeユーザーに設定します。
~/node_project/Dockerfile
...
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
RUN
命令を統合するユーティリティの詳細については、このdiscussion of how to manage container layersを参照してください。
次に、アプリケーションの作業ディレクトリを/home/node/app
に設定します。
~/node_project/Dockerfile
...
WORKDIR /home/node/app
WORKDIR
が設定されていない場合、Dockerはデフォルトで作成するため、明示的に設定することをお勧めします。
次に、package.json
ファイルとpackage-lock.json
(npm 5+の場合)ファイルをコピーします。
~/node_project/Dockerfile
...
COPY package*.json ./
npm install
を実行する前、またはアプリケーションコードをコピーする前に、このCOPY
命令を追加すると、Dockerのキャッシュメカニズムを利用できます。 ビルドの各段階で、Dockerはその特定の命令に対してキャッシュされたレイヤーがあるかどうかを確認します。 package.json
を変更すると、このレイヤーが再構築されますが、変更しない場合、この命令により、Dockerは既存のイメージレイヤーを使用して、ノードモジュールの再インストールをスキップできます。
node_modules
ディレクトリの内容を含め、すべてのアプリケーションファイルがルート以外のnodeユーザーによって所有されていることを確認するには、npm install
を実行する前にユーザーをnodeに切り替えます。 :
~/node_project/Dockerfile
...
USER node
プロジェクトの依存関係をコピーしてユーザーを切り替えた後、npm install
を実行できます。
~/node_project/Dockerfile
...
RUN npm install
次に、適切な権限を持つアプリケーションコードをコンテナのアプリケーションディレクトリにコピーします。
~/node_project/Dockerfile
...
COPY --chown=node:node . .
これにより、アプリケーションファイルがroot以外のnodeユーザーによって所有されるようになります。
最後に、コンテナのポート8080
を公開し、アプリケーションを起動します。
~/node_project/Dockerfile
...
EXPOSE 8080
CMD [ "node", "app.js" ]
EXPOSE
はポートを公開しませんが、代わりに、実行時にコンテナのどのポートが公開されるかを文書化する方法として機能します。 CMD
は、コマンドを実行してアプリケーションを起動します—この場合はnode app.js
です。 各DockerfileにはCMD
命令が1つだけ存在する必要があることに注意してください。 複数を含めると、最後のものだけが有効になります。
Dockerfileでできることはたくさんあります。 手順の完全なリストについては、DockerのDockerfile reference documentationを参照してください。
完全なDockerfileは次のようになります。
~/node_project/Dockerfile
FROM node:10-alpine
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
WORKDIR /home/node/app
COPY package*.json ./
USER node
RUN npm install
COPY --chown=node:node . .
EXPOSE 8080
CMD [ "node", "app.js" ]
編集が終了したら、ファイルを保存して閉じます。
アプリケーションイメージを作成する前に、.dockerignore
fileを追加しましょう。 .gitignore
fileと同様に機能する.dockerignore
は、プロジェクトディレクトリ内のどのファイルとディレクトリをコンテナにコピーしないかを指定します。
.dockerignore
ファイルを開きます。
nano .dockerignore
ファイル内に、ローカルノードモジュール、npmログ、Dockerfile、および.dockerignore
ファイルを追加します。
~/node_project/.dockerignore
node_modules
npm-debug.log
Dockerfile
.dockerignore
Gitを使用している場合は、.git
ディレクトリと.gitignore
ファイルも追加する必要があります。
完了したら、ファイルを保存して閉じます。
これで、docker build
コマンドを使用してアプリケーションイメージを構築する準備が整いました。 -t
フラグをdocker build
とともに使用すると、画像に覚えやすい名前を付けることができます。 画像をDocker Hubにプッシュするため、タグにDocker Hubユーザー名を含めます。 画像にnodejs-image-demo
のタグを付けますが、これを自由に選択した名前に置き換えてください。 your_dockerhub_username
を独自のDockerHubユーザー名に置き換えることも忘れないでください。
docker build -t your_dockerhub_username/nodejs-image-demo .
.
は、ビルドコンテキストが現在のディレクトリであることを指定します。
イメージの構築には1〜2分かかります。 完了したら、画像を確認します。
docker images
次の出力が表示されます。
OutputREPOSITORY TAG IMAGE ID CREATED SIZE
your_dockerhub_username/nodejs-image-demo latest 1c723fb2ef12 8 seconds ago 73MB
node 10-alpine f09e7c96b6de 3 weeks ago 70.7MB
docker run
を使用して、このイメージでコンテナーを作成できるようになりました。 このコマンドには3つのフラグが含まれます。
-
-p
:これにより、コンテナーのポートが公開され、ホストのポートにマップされます。 ホストではポート80
を使用しますが、そのポートで別のプロセスを実行している場合は、必要に応じてこれを自由に変更してください。 これがどのように機能するかについての詳細は、port bindingに関するDockerドキュメントのこの説明を参照してください。 -
-d
:これはコンテナをバックグラウンドで実行します。 -
--name
:これにより、コンテナに覚えやすい名前を付けることができます。
次のコマンドを実行して、コンテナを構築します。
docker run --name nodejs-image-demo -p 80:8080 -d your_dockerhub_username/nodejs-image-demo
コンテナが稼働すると、docker ps
を使用して実行中のコンテナのリストを調べることができます。
docker ps
次の出力が表示されます。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e50ad27074a7 your_dockerhub_username/nodejs-image-demo "node app.js" 8 seconds ago Up 7 seconds 0.0.0.0:80->8080/tcp nodejs-image-demo
コンテナが実行されている状態で、ブラウザをhttp://your_server_ip
に移動して、アプリケーションにアクセスできます。 アプリケーションのランディングページが再び表示されます。
アプリケーションのイメージを作成したので、将来使用するためにDocker Hubにプッシュできます。
[[step-4 -—- using-a-repository-to-work-with-images]] ==ステップ4—リポジトリを使用して画像を操作する
アプリケーションイメージをDocker Hubなどのレジストリにプッシュすることにより、コンテナを構築およびスケーリングするときに、アプリケーションイメージを後で使用できるようにします。 アプリケーションイメージをリポジトリにプッシュし、イメージを使用してコンテナを再作成することにより、これがどのように機能するかを示します。
イメージをプッシュする最初のステップは、前提条件で作成したDocker Hubアカウントにログインすることです。
docker login -u your_dockerhub_username
プロンプトが表示されたら、Docker Hubアカウントのパスワードを入力します。 この方法でログインすると、Docker Hubの認証情報を使用してユーザーのホームディレクトリに~/.docker/config.json
ファイルが作成されます。
以前に作成したタグyour_dockerhub_username/nodejs-image-demo
を使用して、アプリケーションイメージをDockerHubにプッシュできるようになりました。
docker push your_dockerhub_username/nodejs-image-demo
現在のアプリケーションコンテナとイメージを破棄し、リポジトリ内のイメージで再構築して、イメージレジストリのユーティリティをテストしましょう。
最初に、実行中のコンテナをリストします。
docker ps
次の出力が表示されます。
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e50ad27074a7 your_dockerhub_username/nodejs-image-demo "node app.js" 3 minutes ago Up 3 minutes 0.0.0.0:80->8080/tcp nodejs-image-demo
出力にリストされているCONTAINER ID
を使用して、実行中のアプリケーションコンテナーを停止します。 以下で強調表示されているIDを、必ず独自のCONTAINER ID
に置き換えてください。
docker stop e50ad27074a7
-a
フラグを使用してすべての画像を一覧表示します。
docker images -a
次の出力が、イメージの名前your_dockerhub_username/nodejs-image-demo
とともに、node
イメージおよびビルドからの他のイメージとともに表示されます。
OutputREPOSITORY TAG IMAGE ID CREATED SIZE
your_dockerhub_username/nodejs-image-demo latest 1c723fb2ef12 7 minutes ago 73MB
2e3267d9ac02 4 minutes ago 72.9MB
8352b41730b9 4 minutes ago 73MB
5d58b92823cb 4 minutes ago 73MB
3f1e35d7062a 4 minutes ago 73MB
02176311e4d0 4 minutes ago 73MB
8e84b33edcda 4 minutes ago 70.7MB
6a5ed70f86f2 4 minutes ago 70.7MB
776b2637d3c1 4 minutes ago 70.7MB
node 10-alpine f09e7c96b6de 3 weeks ago 70.7MB
次のコマンドを使用して、停止したコンテナと、未使用またはぶら下がり画像を含むすべての画像を削除します。
docker system prune -a
出力でプロンプトが表示されたら%(t0)sと入力して、停止したコンテナーとイメージを削除することを確認します。 これによりビルドキャッシュも削除されることに注意してください。
これで、アプリケーションイメージを実行しているコンテナとイメージ自体の両方が削除されました。 Dockerコンテナー、イメージ、およびボリュームの削除の詳細については、How To Remove Docker Images, Containers, and Volumesを参照してください。
すべてのイメージとコンテナーを削除したら、Docker Hubからアプリケーションイメージをプルできます。
docker pull your_dockerhub_username/nodejs-image-demo
画像をもう一度リストします。
docker images
アプリケーションイメージが表示されます。
OutputREPOSITORY TAG IMAGE ID CREATED SIZE
your_dockerhub_username/nodejs-image-demo latest 1c723fb2ef12 11 minutes ago 73MB
これで、ステップ3のコマンドを使用してコンテナを再構築できます。
docker run --name nodejs-image-demo -p 80:8080 -d your_dockerhub_username/nodejs-image-demo
実行中のコンテナーをリストします。
docker ps
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f6bc2f50dff6 your_dockerhub_username/nodejs-image-demo "node app.js" 4 seconds ago Up 3 seconds 0.0.0.0:80->8080/tcp nodejs-image-demo
もう一度http://your_server_ip
にアクセスして、実行中のアプリケーションを表示します。
結論
このチュートリアルでは、ExpressおよびBootstrapを使用して静的Webアプリケーションを作成し、このアプリケーションのDockerイメージを作成しました。 このイメージを使用してコンテナーを作成し、イメージをDocker Hubにプッシュしました。 そこから、イメージとコンテナを破棄し、Docker Hubリポジトリを使用してそれらを再作成できました。
Docker ComposeやDocker Machineなどのツールを使用して複数コンテナーのセットアップを作成する方法について詳しく知りたい場合は、次のガイドをご覧ください。
コンテナデータの操作に関する一般的なヒントについては、以下を参照してください。
他のDocker関連のトピックに興味がある場合は、Docker tutorialsの完全なライブラリを参照してください。