DockerでNode.jsアプリケーションを構築する方法

前書き

Dockerプラットフォームを使用すると、開発者はアプリケーションをcontainersとしてパッケージ化して実行できます。 コンテナは、共有オペレーティングシステム上で実行される独立したプロセスであり、仮想マシンに代わる軽量な代替手段を提供します。 コンテナは新しいものではありませんが、プロセスの分離や環境の標準化などの利点があり、分散アプリケーションアーキテクチャを使用する開発者が増えるにつれて重要性が増しています。

Dockerを使用してアプリケーションを構築およびスケーリングする場合の出発点は、通常、アプリケーション用のイメージを作成することです。その後、イメージをコンテナーで実行できます。 イメージには、アプリケーションコード、ライブラリ、構成ファイル、環境変数、およびランタイムが含まれます。 イメージを使用すると、コンテナ内の環境が標準化され、アプリケーションのビルドと実行に必要なもののみが含まれることが保証されます。

このチュートリアルでは、ExpressフレームワークとBootstrapを使用する静的Webサイトのアプリケーションイメージを作成します。 次に、そのイメージを使用してコンテナーを作成し、将来使用するためにDocker Hubにプッシュします。 最後に、保存されたイメージをDocker Hubリポジトリからプルして別のコンテナーを構築し、アプリケーションを再作成およびスケーリングする方法を示します。

前提条件

このチュートリアルを実行するには、次のものが必要です。

[[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メソッドルートを定義するときに、それらをこのオブジェクトに追加して、アプリケーションがリクエストを処理する方法を定義します。

ファイルのこのセクションでは、pathportの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
    
    
    
    
    



    
    

Want to Learn About Sharks?

Are you ready to learn about sharks?


Get Shark Info

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

...

Want to Learn About Sharks?

Are you ready to learn about sharks?


Get Shark Info

...

ヘッダーにはカスタムスタイルシートへのリンクもあります。

~/node_project/views/index.html

...

...

このスタイルシートは、この手順の最後に作成します。

完了したら、ファイルを保存して閉じます。

アプリケーションのランディングページを配置したら、サメ情報ページsharks.htmlを作成できます。このページでは、関心のあるユーザーにサメに関する詳細情報を提供します。

ファイルを開きます。

nano views/sharks.html

Bootstrapとカスタムスタイルシートをインポートし、特定のサメに関する詳細情報をユーザーに提供する次のコードを追加します。

~/node_project/views/sharks.html





    About Sharks
    
    
    
    
    


Shark Info

Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
Sawshark

Other sharks are known to be friendly and welcoming!
Sammy the Shark

このファイルでは、activeクラスを使用して現在のページを示していることに注意してください。

完了したら、ファイルを保存して閉じます。

最後に、最初にviewsディレクトリにcssフォルダを作成して、index.htmlsharks.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に移動します。 次のランディングページが表示されます。

Application Landing Page

Get Shark Infoボタンをクリックします。 次の情報ページが表示されます。

Shark Info Page

これで、アプリケーションが稼働しました。 準備ができたら、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/nodenode_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に移動して、アプリケーションにアクセスできます。 アプリケーションのランディングページが再び表示されます。

Application Landing Page

アプリケーションのイメージを作成したので、将来使用するために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の完全なライブラリを参照してください。

Related