Docker Composeを使って、Node.jsアプリケーションの開発をコンテナ化する。

イントロダクション

アプリケーションの積極的な開発中であれば、Dockerの利用は作業フローを簡素化し、アプリケーションを本番環境に展開するプロセスを容易にします。開発時にコンテナを使用することにより、以下の利点があります。

  • Environments are consistent, meaning that you can choose the languages and dependencies you want for your project without worrying about system conflicts.
  • Environments are isolated, making it easier to troubleshoot issues and onboard new team members.
  • Environments are portable, allowing you to package and share your code with others.

このチュートリアルでは、Dockerを使用してNode.jsアプリケーションの開発環境をセットアップする方法を紹介します。Docker Composeを使用して、Nodeアプリケーション用の1つのコンテナとMongoDBデータベース用の別のコンテナを作成します。このアプリケーションはNodeとMongoDBと連携するため、セットアップでは以下のことを行います。

  • Synchronize the application code on the host with the code in the container to facilitate changes during development.
  • Ensure that changes to the application code work without a restart.
  • Create a user and password-protected database for the application’s data.
  • Persist this data.

このチュートリアルの終わりには、Dockerコンテナ上で動作する作動中のサメ情報アプリケーションを持っています。

Complete Shark Collection landing page

前提条件

このチュートリアルに従うためには、次のものが必要です:

  • A development server running Ubuntu 18.04, along with a non-root user with sudo privileges and an active firewall. For guidance on how to set these up, please see this Initial Server Setup guide.
  • Docker installed on your server, following Steps 1 and 2 of How To Install and Use Docker on Ubuntu 18.04.
  • Docker Compose installed on your server, following Step 1 of How To Install Docker Compose on Ubuntu 18.04.

ステップ1 – プロジェクトのクローンと依存関係の修正

このセットアップの構築の最初のステップは、プロジェクトコードをクローンして、そのpackage.jsonファイルを変更することです。このファイルには、プロジェクトの依存関係が含まれています。nodemonをプロジェクトのdevDependenciesに追加し、開発中に使用することを指定します。nodemonを使用してアプリケーションを実行すると、コードを変更するたびに自動的に再起動されることが保証されます。

最初に、Silicon Cloud CommunityのGitHubアカウントからnodejs-mongo-mongooseリポジトリをクローンします。
このリポジトリには、MongoDBをNodeアプリケーションに統合する方法を説明した「How To Integrate MongoDB with Your Node Application」というガイドで説明されているセットアップのコードが含まれています。このコードでは、Mongooseを使用して既存のNodeアプリケーションにMongoDBデータベースを統合する方法が説明されています。

ディレクトリ名をnode_projectとして、リポジトリをクローンしてください。

  1. git clone https://github.com/do-community/nodejs-mongo-mongoose.git node_project

 

「node_project」ディレクトリに移動してください。

  1. cd node_project

 

お気に入りのエディタを使用して、プロジェクトのpackage.jsonファイルをNanoで開く。

  1. nano package.json

 

プロジェクトの依存関係の下、閉じカッコの直上に、nodemonを含む新しいdevDependenciesオブジェクトを作成してください。

~/node_project/package.jsonを日本語で言い換えると、以下のようになります:「~/node_project/package.json」
...
"dependencies": {
    "ejs": "^2.6.1",
    "express": "^4.16.4",
    "mongoose": "^5.4.10"
  },
  "devDependencies": {
    "nodemon": "^1.18.10"
  }    
}

編集が完了したら、ファイルを保存して閉じてください。もしnanoを使用している場合は、CTRL+X、Y、エンターキーを順に押してください。

プロジェクトコードとその依存関係を修正したら、コンテナ化されたワークフロー向けにコードをリファクタリングすることができます。

ステップ2 – コンテナーと連携するためのアプリケーションの設定

アプリケーションをコンテナベースのワークフローに変更することは、コードをよりモジュラーにすることを意味します。コンテナは環境間での可搬性を提供しており、そのためにはコードはできるだけ基礎となるオペレーティングシステムから切り離す必要があります。これを実現するために、Nodeのprocess.envプロパティをより多く活用するためにコードをリファクタリングします。これにより、ランタイム時にユーザー環境に関する情報を含んだオブジェクトが返されます。このオブジェクトを使って、環境変数を使って実行時に動的に設定情報を割り当てることができます。

app.jsから始めて、メインアプリケーションのエントリーポイントを開きます。ファイルを開いてください。

  1. nano app.js

 

内部には、ポート定数の定義と、アプリケーションがリッスンするポートを指定するためにこの定数を使用するリッスン関数があります。

ネイティブの日本語で以下の文を言い換えてください。オプションは一つのみです:
~/home/node_project/app.jsホームディレクトリの中にあるnode_projectディレクトリの中のapp.js

...
const port = 8080;
...
app.listen(port, function () {
  console.log('Example app listening on port 8080!');
});

プロセスの環境変数(process.env オブジェクト)を使用して、実行時に動的に割り当てるために、ポート定数を再定義してください。定数の定義と listen 関数に以下の変更を加えてください。

以下の文を日本語で自然な表現に言い換えてください(1つのオプションで十分です):
~/home/node_project/app.js
...
const port = process.env.PORT || 8080;
...
app.listen(port, function () {
  console.log(`Example app listening on ${port}!`);
});

新しい定数の定義では、ランタイムで渡された値または8080を使用してポートを動的に割り当てます。同様に、リッスン関数をテンプレートリテラルを使用して書き直し、接続をリッスンする際にポートの値を補完します。ポートのマッピングを他の場所で行うため、これらの変更により、環境が変わるたびにこのファイルを継続的に修正する必要がなくなります。

編集が終わったら、ファイルを保存して閉じてください。

次に、設定の資格情報を削除するためにデータベースの接続情報を変更します。この情報が含まれているdb.jsファイルを開いてください。

  1. nano db.js

 

現在、ファイルは次のことを行っています。

  • Imports Mongoose, the Object Document Mapper (ODM) that you’re using to create schemas and models for your application data.
  • Sets the database credentials as constants, including the username and password.
  • Connects to the database using the mongoose.connect method.

ファイルに関する詳細は、「MongoDBをNodeアプリケーションに統合する方法」のステップ3をご覧ください。

ファイルを変更するために最初に行うのは、機密情報を含む定数の再定義です。現在、これらの定数は以下のようになっています。

~/node_project/db.js を日本語で言い換えると:
「~/node_project/db.js」
...
const MONGO_USERNAME = 'sammy';
const MONGO_PASSWORD = 'your_password';
const MONGO_HOSTNAME = '127.0.0.1';
const MONGO_PORT = '27017';
const MONGO_DB = 'sharkinfo';
...

この情報をハードコーディングする代わりに、process.envオブジェクトを使用してこれらの定数の実行時値をキャプチャすることができます。ブロックを次のように変更してください。

以下の内容を日本語で自然に言い換えてください。複数のオプションを必要としません:
~/node_project/db.js~/node_project/db.jsをパラフレーズすると :
~/node_project/db.js

...
const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB
} = process.env;
...

編集が終わったら、ファイルを保存し閉じてください。

この時点で、db.jsをアプリケーションの環境変数に対応させるために修正しましたが、それらの変数をアプリケーションに渡す方法がまだ必要です。実行時にアプリケーションに渡す値を持つ.envファイルを作成してください。

ファイルを開いてください。

  1. nano .env

 

このファイルには、db.jsから削除された情報が含まれます。アプリケーションのデータベースに関するユーザー名、パスワード、ポート設定、データベース名が含まれています。ここにリストされているユーザー名、パスワード、データベース名を自分自身の情報に更新することを忘れないでください。

~/node_project/.envを日本語で自然に言い換えてください。1つのオプションだけで構いません。
MONGO_USERNAME=sammy
MONGO_PASSWORD=your_password
MONGO_PORT=27017
MONGO_DB=sharkinfo

元々db.jsに表示されていたホスト設定が削除されたことに注意してください。今後はDocker Composeファイルのレベルでホストを定義し、サービスとコンテナに関する他の情報とともに設定します。

編集が終わったら、このファイルを保存して閉じてください。

.envファイルには機密情報が含まれているため、バージョン管理やコンテナにコピーされないようにするために、プロジェクトの.dockerignoreファイルと.gitignoreファイルに含まれるようにしてください。

「.dockerignore」ファイルを開いてください。

  1. nano .dockerignore

 

ファイルの最後に次の行を追加してください。

以下の文を日本語で同義に述べてください。1つのオプションで構いません:
~/node_project/.dockerignore~ /node_project/.dockerignoreファイル

...
.gitignore
.env

編集が終わったら、ファイルを保存して閉じてください。

このリポジトリの.gitignoreファイルには既に.envが含まれていますが、存在するか確認しても構いません。

  1. nano .gitignore

 

「~/node_project/.gitignore」
...
.env
...

この時点では、プロジェクトコードから機密情報を抽出し、その情報がどのようにどこにコピーされるかを制御するための対策を取りました。これでデータベース接続コードを追加して、コンテナ化されたワークフローに最適化することができます。

ステップ3-データベース接続設定の変更

あなたの次のステップは、アプリケーションがデータベースに接続できない場合に対応するコードを追加することで、データベース接続方法をより堅牢にすることです。Composeを使用したコンテナで作業する際には、このような強靭さをアプリケーションコードに導入することが推奨されています。

db.jsを編集するために開いてください。

  1. nano db.js

 

前に追加したコードと、Mongoの接続URIのURL定数とMongooseの接続メソッドに注目してください。

以下は日本語での表現例です:
~/node_project/db.js ファイル
...
const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB
} = process.env;

const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;

mongoose.connect(url, {useNewUrlParser: true});

現在、あなたのconnectメソッドは、MongooseがMongoの新しいURLパーサーを使用するかどうかを指定するオプションを受け入れています。再接続試行のパラメータを定義するために、このメソッドにオプションを追加することができます。新しいURLパーサーオプションに加えて、関連情報を含むoptions定数を作成してください。Mongoの定数の下に、options定数の以下の定義を追加してください。

「~/node_project/db.js」を日本語にネイティブに言い換えると、以下のようになります:
~/node_project/db.js
...
const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB
} = process.env;

const options = {
  useNewUrlParser: true,
  reconnectTries: Number.MAX_VALUE,
  reconnectInterval: 500, 
  connectTimeoutMS: 10000,
};
...

reconnectTriesオプションは、Mongooseに無期限での接続試行を続けるよう指示します。また、reconnectIntervalは接続試行間の期間をミリ秒単位で定義します。さらに、connectTimeoutMSはMongoドライバが接続試行を失敗と判断するまでの待機時間を10秒と定義します。

あなたは、Mongooseのconnectメソッドで新しいオプション定数を使用することができます。これにより、Mongoose接続設定をより細かく調整することができます。また、接続エラーに対応するために、プロミスを追加します。

現在、Mongooseのconnectメソッドは次のようになっています。

以下は~/node_project/db.jsの日本語での同義表現です。

~ / node_project / db.js の日本語での同義表現は次のとおりです。

...
mongoose.connect(url, {useNewUrlParser: true});

以下のコードには、オプション定数とプロミスを含む、既存の接続メソッドを削除して、置き換えてください。

以下の文を日本語で自然に言い換えてください。1つのオプションで結構です:
~/node_project/db.js~/node_project/db.js を日本語で言い換えてください。

...
mongoose.connect(url, options).then( function() {
  console.log('MongoDB is connected');
})
  .catch( function(err) {
  console.log(err);
});

成功した場合は、関数は適切なメッセージをログに記録します。それ以外の場合は、エラーを捕捉してログに記録し、トラブルシューティングを行うことができます。

完成したファイルは、以下のようになります。 (Kansei shita fairu wa, ika no yō ni narimasu.)

以下の内容を日本語で言い換えてください。一つのオプションのみで構いません:
~/node_project/db.js~/node_project/db.jsを言い換えてください。

const mongoose = require('mongoose');

const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB
} = process.env;

const options = {
  useNewUrlParser: true,
  reconnectTries: Number.MAX_VALUE,
  reconnectInterval: 500,
  connectTimeoutMS: 10000,
};

const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;

mongoose.connect(url, options).then( function() {
  console.log('MongoDB is connected');
})
  .catch( function(err) {
  console.log(err);
});

編集が終わったら、ファイルを保存して閉じてください。

コード内に耐障害性を追加して、アプリケーションがデータベースに接続できない場合に対処できるようにしました。このコードが設定されているので、Composeを使用してサービスを定義することができます。

ステップ4 — Docker Composeでサービスを定義する

コードをリファクタリングしたら、サービスの定義を含んだdocker-compose.ymlファイルを作成する準備が整いました。Composeにおけるサービスは実行中のコンテナであり、サービスの定義は各コンテナのイメージが実行される方法に関する情報を含んでいます。Composeツールを使用することで、複数のサービスを定義し、マルチコンテナのアプリケーションを構築することができます。

あなたのサービスを定義する前に、wait-forというプロジェクトにツールを追加することで、アプリケーションがデータベースの起動完了後にのみ接続しようとすることを保証します。このラッパースクリプトは、特定のホストとポートがTCP接続を受け入れているかどうかをポーリングするためにnetcatを使用します。これによって、データベースが接続を受け入れる準備ができているかどうかをテストすることで、アプリケーションがデータベースに接続する試行を制御することができます。

Composeでは、depends_onオプションを使用してサービス間の依存関係を指定することができますが、この順序はコンテナが実行中かどうかに基づいており、準備ができているかどうかではありません。depends_onを使用すると、データベースの起動タスク(ユーザーとパスワードを管理者認証データベースに追加するなど)が完了した後に、アプリケーションが接続するようにしたいので、最適ではありません。起動順序を制御するためのwait-forや他のツールの使用方法についての詳細は、Composeドキュメントの関連推奨事項をご覧ください。

「wait-for.sh」というファイルを開く。

  1. nano wait-for.sh

 

以下のコードをファイルに入力して、ポーリング機能を作成してください。

以下の文を日本語に自然に言い換えてください。1つのオプションのみが必要です:
~/node_project/app/wait-for.sh「~/node_project/app/wait-for.sh」

#!/bin/sh

# original script: https://github.com/eficode/wait-for/blob/master/wait-for

TIMEOUT=15
QUIET=0

echoerr() {
  if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi
}

usage() {
  exitcode="$1"
  cat << USAGE >&2
Usage:
  $cmdname host:port [-t timeout] [-- command args]
  -q | --quiet                        Do not output any status messages
  -t TIMEOUT | --timeout=timeout      Timeout in seconds, zero for no timeout
  -- COMMAND ARGS                     Execute command with args after the test finishes
USAGE
  exit "$exitcode"
}

wait_for() {
  for i in `seq $TIMEOUT` ; do
    nc -z "$HOST" "$PORT" > /dev/null 2>&1
    
    result=$?
    if [ $result -eq 0 ] ; then
      if [ $# -gt 0 ] ; then
        exec "$@"
      fi
      exit 0
    fi
    sleep 1
  done
  echo "Operation timed out" >&2
  exit 1
}

while [ $# -gt 0 ]
do
  case "$1" in
    *:* )
    HOST=$(printf "%s\n" "$1"| cut -d : -f 1)
    PORT=$(printf "%s\n" "$1"| cut -d : -f 2)
    shift 1
    ;;
    -q | --quiet)
    QUIET=1
    shift 1
    ;;
    -t)
    TIMEOUT="$2"
    if [ "$TIMEOUT" = "" ]; then break; fi
    shift 2
    ;;
    --timeout=*)
    TIMEOUT="${1#*=}"
    shift 1
    ;;
    --)
    shift
    break
    ;;
    --help)
    usage 0
    ;;
    *)
    echoerr "Unknown argument: $1"
    usage 1
    ;;
  esac
done

if [ "$HOST" = "" -o "$PORT" = "" ]; then
  echoerr "Error: you need to provide a host and port to test."
  usage 2
fi

wait_for "$@"

コードの追加が終わったら、ファイルを保存して閉じてください。

スクリプトを実行可能にしてください。

  1. chmod +x wait-for.sh

 

次に、docker-compose.ymlファイルを開きます。

  1. nano docker-compose.yml

 

まず、ファイルに以下のコードを追加して、node.jsアプリケーションサービスを定義します。

以下の内容を日本語で言い換えてください。ただし、一つのオプションでお願いします:
~/node_project/docker-compose.yml~/node_project/docker-compose.ymlの日本語による言い換えを教えてください。ただし、一つのオプションでお願いします。

version: '3'

services:
  nodejs:
    build:
      context: .
      dockerfile: Dockerfile
    image: nodejs
    container_name: nodejs
    restart: unless-stopped
    env_file: .env
    environment:
      - MONGO_USERNAME=$MONGO_USERNAME
      - MONGO_PASSWORD=$MONGO_PASSWORD
      - MONGO_HOSTNAME=db
      - MONGO_PORT=$MONGO_PORT
      - MONGO_DB=$MONGO_DB 
    ports:
      - "80:8080"
    volumes:
      - .:/home/node/app
      - node_modules:/home/node/app/node_modules
    networks:
      - app-network
    command: ./wait-for.sh db:27017 -- /home/node/app/node_modules/.bin/nodemon app.js

nodejsサービスの定義には、以下のオプションが含まれています。

  • build: This defines the configuration options, including the context and dockerfile, that will be applied when Compose builds the application image. If you wanted to use an existing image from a registry like Docker Hub, you could use the image instruction instead, with information about your username, repository, and image tag.
  • context: This defines the build context for the image build — in this case, the current project directory.
  • dockerfile: This specifies the Dockerfile in your current project directory as the file Compose will use to build the application image. For more information about this file, please see How To Build a Node.js Application with Docker.
  • image, container_name: These apply names to the image and container.
  • restart: This defines the restart policy. The default is no, but you have set the container to restart unless it is stopped.
  • env_file: This tells Compose that you would like to add environment variables from a file called .env, located in your build context.
  • environment: Using this option allows you to add the Mongo connection settings you defined in the .env file. Note that you are not setting NODE_ENV to development, since this is Express’s default behavior if NODE_ENV is not set. When moving to production, you can set this to production to enable view caching and less verbose error messages.
    Also note that you have specified the db database container as the host, as discussed in Step 2.
  • ports: This maps port 80 on the host to port 8080 on the container.
  • volumes: You are including two types of mounts here:The first is a bind mount that mounts your application code on the host to the /home/node/app directory on the container. This will facilitate rapid development, since any changes you make to your host code will be populated immediately in the container.
    The second is a named volume, node_modules. When Docker runs the npm install instruction listed in the application Dockerfile, npm will create a new node_modules directory on the container that includes the packages required to run the application. The bind mount you just created will hide this newly created node_modules directory, however. Since node_modules on the host is empty, the bind will map an empty directory to the container, overriding the new node_modules directory and preventing your application from starting. The named node_modules volume solves this problem by persisting the contents of the /home/node/app/node_modules directory and mounting it to the container, hiding the bind.

Note

このアプローチを使用する際には、次のポイントに注意してください。

– バインドすることにより、コンテナのnode_modulesディレクトリの内容がホストにマウントされます。このディレクトリはDockerによって作成された名前付きボリュームによって所有されます。
– ホストに事前に存在するnode_modulesディレクトリがある場合、コンテナ上で作成されたnode_modulesディレクトリが上書きされます。このチュートリアルで構築しているセットアップでは、事前に存在するnode_modulesディレクトリはなく、ホストでnpmを使用しないことを前提としています。これは、アプリケーション開発のためのtwelve-factorアプローチに準拠しており、実行環境間の依存関係を最小限に抑えます。

  • networks: This specifies that your application service will join the app-network network, which you will define at the bottom of the file.
  • command: This option lets you set the command that should be executed when Compose runs the image. Note that this will override the CMD instruction that you set in our application Dockerfile. Here, you are running the application using the wait-for script, which will poll the db service on port 27017 to test whether the database service is ready. Once the readiness test succeeds, the script will execute the command you have set, /home/node/app/node_modules/.bin/nodemon app.js, to start the application with nodemon. This will ensure that any future changes you make to your code are reloaded without your having to restart the application.

次に、アプリケーションサービスの定義の下に、次のコードを追加してデータベースサービスを作成してください。

以下は、日本語での同等の表現です:
~/node_project/docker-compose.ymlというファイル
...
  db:
    image: mongo:4.1.8-xenial
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME
      - MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD
    volumes:  
      - dbdata:/data/db   
    networks:
      - app-network  

Nodejsサービスに定義されている設定の一部は同じままですが、イメージ、環境、およびボリュームの定義には以下の変更が加えられました。

  • image: To create this service, Compose will pull the 4.1.8-xenial Mongo image from Docker Hub. You are pinning a particular version to avoid possible future conflicts as the Mongo image changes. For more information about version pinning, please see the Docker documentation on Dockerfile best practices.
  • MONGO_INITDB_ROOT_USERNAME, MONGO_INITDB_ROOT_PASSWORD: The mongo image makes these environment variables available so that you can modify the initialization of your database instance. MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD together create a root user in the admin authentication database and ensure that authentication is enabled when the container starts. You have set MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD using the values from your .env file, which you pass to the db service using the env_file option. Doing this means that your sammy application user will be a root user on the database instance, with access to all the administrative and operational privileges of that role. When working in production, you will want to create a dedicated application user with appropriately scoped privileges.

Note

注意:既存のデータディレクトリの場所にコンテナを開始すると、これらの変数は効果を持ちません。
  • dbdata:/data/db: The named volume dbdata will persist the data stored in Mongo’s default data directory, /data/db. This will ensure that you don’t lose data in cases where you stop or remove containers.

ネットワークオプションを使用して、アプリネットワークネットワークにもDBサービスが追加されました。

最後のステップとして、ファイルの最後にボリュームとネットワークの定義を追加してください。

以下は、日本語で1つのオプションで言い換えたものです:
〜/node_project/docker-compose.yml を使ってください。
...
networks:
  app-network:
    driver: bridge

volumes:
  dbdata:
  node_modules:  

ユーザーが定義したブリッジネットワーク、app-networkは、同じDockerデーモンホスト上にあるため、コンテナ間での通信を可能にします。これにより、アプリケーション内のトラフィックと通信が効率化されます。同じブリッジネットワーク上のコンテナ間では、すべてのポートが開放されますが、外部へのポートは公開されません。このため、dbコンテナとnodejsコンテナは互いに通信でき、アプリケーションへのフロントエンドアクセスのためにポート80を公開するだけで十分です。

トップレベルのボリュームキーには、ボリュームのdbdataとnode_modulesが定義されています。Dockerがボリュームを作成する際、ボリュームの内容はDockerが管理するホストファイルシステムの一部(/var/lib/docker/volumes/)に格納されます。各ボリュームの内容は、/var/lib/docker/volumes/のディレクトリの下に格納され、ボリュームを使用するコンテナにマウントされます。このように、ユーザーが作成する鮫情報データは、dbコンテナを削除して再作成してもdbdataボリュームに保持されます。

完成したdocker-compose.ymlファイルは、以下のようになります。

~/node_project/docker-compose.ymlを日本語で原文の意味を保ったまま言い換えると次のようになります:
「~/node_project/docker-compose.ymlファイル」
version: '3'

services:
  nodejs:
    build:
      context: .
      dockerfile: Dockerfile
    image: nodejs
    container_name: nodejs
    restart: unless-stopped
    env_file: .env
    environment:
      - MONGO_USERNAME=$MONGO_USERNAME
      - MONGO_PASSWORD=$MONGO_PASSWORD
      - MONGO_HOSTNAME=db
      - MONGO_PORT=$MONGO_PORT
      - MONGO_DB=$MONGO_DB
    ports:
      - "80:8080"
    volumes:
      - .:/home/node/app
      - node_modules:/home/node/app/node_modules
    networks:
      - app-network
    command: ./wait-for.sh db:27017 -- /home/node/app/node_modules/.bin/nodemon app.js 

  db:
    image: mongo:4.1.8-xenial
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME
      - MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD
    volumes:     
      - dbdata:/data/db
    networks:
      - app-network  

networks:
  app-network:
    driver: bridge

volumes:
  dbdata:
  node_modules:  

編集が終わったら、ファイルを保存して閉じてください。

サービスの定義が完了しましたら、アプリケーションの開始に備えられます。

ステップ5- アプリケーションのテスト

docker-compose.ymlファイルがあれば、docker-compose upコマンドでサービスを作成することができます。また、docker-compose downコマンドでコンテナを停止して削除することでデータが永続化されるかをテストすることもできます。

最初に、コンテナイメージをビルドし、docker-compose upコマンドを-dフラグと共に実行して、バックグラウンドでnodejsとdbのコンテナを実行します。

  1. docker-compose up -d

 

出力は、ご利用のサービスが作成されたことを確認します。

Output

… Creating db … done Creating nodejs … done

サービスからのログ出力を表示することで、起動プロセスに関するより詳細な情報を取得することもできます。

  1. docker-compose logs

 

もしすべてが正しく開始されていれば、次に示すものが出力されます。

Output

… nodejs | [nodemon] starting `node app.js` nodejs | Example app listening on 8080! nodejs | MongoDB is connected … db | 2019-02-22T17:26:27.329+0000 I ACCESS [conn2] Successfully authenticated as principal sammy on admin

docker-compose psコマンドを使って、コンテナの状態も確認することができます。

  1. docker-compose ps

 

出力は、コンテナが実行されていることを示しています。

Output

Name Command State Ports ———————————————————————- db docker-entrypoint.sh mongod Up 27017/tcp nodejs ./wait-for.sh db:27017 — … Up 0.0.0.0:80->8080/tcp

あなたのサービスが稼働している状態で、ブラウザでhttp://your_server_ipにアクセスすることができます。

Everything Sharks Application Landing Page

「サメの情報を入手する」ボタンをクリックして、エントリーフォームがあるページに移動し、そこでサメの名前とそのサメの一般的な特徴の説明を送信できます。

Shark Info Form where you can enter a shark name and the characteristics of that shark

フォームに、あなたが選んだサメを追加してください。このデモンストレーションのために、「サメの名前」フィールドにメガロドン・シャークを追加し、「サメの特徴」フィールドに「古代」と追加してください。

Filled Shark Form

「送信ボタンをクリックすると、このサメの情報が表示されたページがあなたに戻ってきます。」

Shark Output from the form you submitted

最後のステップとして、データベースコンテナを削除しても、先ほど入力したデータが維持されるかテストしてください。

ターミナルに戻り、次のコマンドを入力してコンテナとネットワークを停止して削除してください。

  1. docker-compose down

 

–volumesオプションを含めないように注意してください。そのため、dbdataボリュームは削除されません。

次の出力は、コンテナとネットワークが削除されたことを確認しています。

Output

Stopping nodejs … done Stopping db … done Removing nodejs … done Removing db … done Removing network node_project_app-network

容器を再作成する

  1. docker-compose up -d

 

では、今度はサメの情報フォームに戻ってください。

Shark Info Form

好みの新しいサメを選んでください。この例では、ジンベエザメと大型を使います。

Enter New Shark

「送信」ボタンをクリックすると、入力したデータが失われることなく、新しいサメがデータベースのサメコレクションに追加されていることに気づきます。

Complete Shark Collection

現在、データの永続性とコードの同期が可能なDockerコンテナ上であなたのアプリケーションが稼働しています。

結論

このチュートリアルに従うことで、Dockerコンテナを使ったNodeアプリケーションの開発環境を作成しました。機密情報を取り出し、アプリケーションの状態をアプリケーションコードから切り離すことにより、プロジェクトをよりモジュラーかつ移植可能にしました。また、開発のニーズや要件が変わるにつれて、修正できるボイラープレートのdocker-compose.ymlファイルも設定しました。

あなたが成長するにつれて、コンテナ化されたアプリケーションとクラウドネイティブなワークフローの設計についてさらに知りたいと思うかもしれません。これらのトピックに関する詳細情報は、Kubernetes向けのアプリケーションアーキテクチャとKubernetes向けのアプリケーションの近代化を参照してください。

このチュートリアルで使用されているコードについて詳しく学ぶには、「Dockerを使用したNode.jsアプリケーションの構築方法」と「NodeアプリケーションにMongoDBを統合する方法」を参照してください。コンテナを使用してNginxリバースプロキシを使用したNodeアプリケーションの展開についての情報は、「Nginx、Let’s Encrypt、およびDocker Composeを使用したコンテナ化されたNode.jsアプリケーションのセキュリティ」を参照してください。

コメントを残す 0

Your email address will not be published. Required fields are marked *