ウェビナーシリーズ:コンテナ化されたアプリケーションの構築
ウェビナーシリーズ
この記事は、クラウドでのコンテナー化されたワークロードのデプロイと管理に関するウェビナーシリーズを補足するものです。 このシリーズでは、コンテナーのライフサイクル管理、マルチコンテナーアプリケーションのデプロイ、ワークロードのスケーリング、Kubernetesの理解など、コンテナーの基本事項を取り上げ、ステートフルアプリケーションを実行するためのベストプラクティスを強調しています。
このチュートリアルには、シリーズの2番目のセッションであるコンテナ化されたアプリケーションの構築で説明されている概念とコマンドが含まれています。
序章
前回のチュートリアルDockerのインストールと構成方法では、DockerコンテナーをDockerイメージに変換する1つの方法について説明しました。 私たちが使用した方法は機能しましたが、それが常に画像を構築するための最適な方法であるとは限りません。
多くの場合、既存のコードをコンテナイメージに取り込み、コードベースの最新バージョンと同期するDockerイメージを作成するための反復可能で一貫性のあるメカニズムが必要になります。
Dockerfile は、Dockerイメージを構築するための宣言的で一貫した方法を提供することにより、これらの要件に対応します。
さらに、一緒にデプロイおよび管理される複数の異種コンテナーで構成されるアプリケーション全体をコンテナー化する必要がある場合があります。
Docker Compose は、Dockerfileと同様に、宣言型のアプローチを採用して、ネットワークとストレージの要件を含むテクノロジースタック全体を定義する方法を提供します。 これにより、コンテナ化されたアプリケーションの構築が容易になるだけでなく、それらの管理とスケーリングも容易になります。
このチュートリアルでは、Node.jsとMongoDBに基づくサンプルWebアプリケーションを使用してDockerfileからDockerイメージを構築し、Dockerコンテナーを許可するカスタムネットワークを作成します通信し、DockerComposeを使用してコンテナー化されたアプリケーションを起動およびスケーリングします。
前提条件
このチュートリアルに従うには、次のものが必要です。
- このUbuntu16.04初期サーバーセットアップチュートリアルに従ってセットアップされた1つのUbuntu16.04ドロップレット。これには、sudo非rootユーザーとファイアウォールが含まれます。
- このウェビナーシリーズの最初のチュートリアルに従ってインストールされたDockerCommunityEditionの最新バージョン。
ステップ1—Dockerfileを使用してイメージを構築する
まずホームディレクトリに移動し、 Git を使用して、GitHubの公式リポジトリからこのチュートリアルのサンプルWebアプリケーションのクローンを作成します。
- cd ~
- git clone https://github.com/janakiramm/todo-app.git
これにより、サンプルアプリケーションがtodo-app
という名前の新しいディレクトリにコピーされます。
todo-app
に切り替え、ls
を使用してディレクトリの内容を表示します。
- cd todo-app
- ls
新しいディレクトリには、2つのサブディレクトリと2つのファイルが含まれています。
app
-サンプルアプリケーションのソースコードが保存されているディレクトリcompose
-DockerCompose構成ファイルが保存されているディレクトリDockerfile
-Dockerイメージをビルドするための手順を含むファイルREADME.md
-サンプルアプリケーションの1文の要約を含むファイル
cat Dockerfile
を実行すると、次のように表示されます。
FROM node:slim
LABEL maintainer = "[email protected]"
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY ./app/ ./
RUN npm install
CMD ["node", "app.js"]
このファイルの内容をさらに詳しく見てみましょう。
FROM
は、カスタムイメージを構築するベースイメージを示します。 この例では、イメージはnode:slim
に基づいています。これは、node
の実行に必要な最小限のパッケージのみを含むpublicNode.jsイメージです。LABEL
は、説明情報を追加するために通常使用されるキーと値のペアです。 この場合、メンテナのメールアドレスが含まれています。RUN
はコンテナ内でコマンドを実行します。 これには、ディレクトリの作成や、基本的なLinuxコマンドの実行によるコンテナの初期化などのタスクが含まれます。 このファイルの最初のRUN
コマンドは、ソースコードを保持するディレクトリ/usr/src/app
を作成するために使用されます。WORKDIR
は、すべてのコマンドが実行されるディレクトリを定義します。 これは通常、コードがコピーされるディレクトリです。COPY
は、ファイルをホストマシンからコンテナイメージにコピーします。 この場合、app
ディレクトリ全体をイメージにコピーしています。- 2番目の
RUN
コマンドは、npm install
を実行して、package.json
で定義されているアプリケーションの依存関係をインストールします。 CMD
は、コンテナの実行を維持するプロセスを実行します。 この例では、パラメーターapp.js
を指定してnode
を実行します。
次に、Dockerfile
からイメージを作成します。 -t
スイッチを使用して、レジストリのユーザー名、イメージ名、およびオプションのタグでイメージにタグを付けます。
- docker build -t sammy/todo-web .
出力は、画像がSuccessfully built
であり、適切にタグ付けされていることを確認します。
Output from docker build -tSending build context to Docker daemon 8.238MB
Step 1/7 : FROM node:slim
---> 286b1e0e7d3f
Step 2/7 : LABEL maintainer = "[email protected]"
---> Using cache
---> ab0e049cf6f8
Step 3/7 : RUN mkdir -p /usr/src/app
---> Using cache
---> 897176832f4d
Step 4/7 : WORKDIR /usr/src/app
---> Using cache
---> 3670f0147bed
Step 5/7 : COPY ./app/ ./
---> Using cache
---> e28c7c1be1a0
Step 6/7 : RUN npm install
---> Using cache
---> 7ce5b1d0aa65
Step 7/7 : CMD node app.js
---> Using cache
---> 2cef2238de24
Successfully built 2cef2238de24
Successfully tagged sammy/todo-web:latest
docker images
コマンドを実行すると、イメージが作成されたことを確認できます。
- docker images
ここでは、画像のサイズと、画像が作成されてからの経過時間を確認できます。
Output from docker imagesREPOSITORY TAG IMAGE ID CREATED SIZE
sammy/todo-web latest 81f5f605d1ca 9 minutes ago 236MB
サンプルWebアプリケーションを実行するためのMongoDBコンテナーも必要なので、それをマシンに取得しましょう。
- docker pull mongo:latest
出力は、ダウンロードステータスとともにどのイメージがプルされたかを正確に報告します。
Output from docker pulllatest: Pulling from library/mongo
Digest: sha256:18b239b996e0d10f4ce2b0f64db6f410c17ad337e2cecb6210a3dcf2f732ed82
Status: Downloaded newer image for mongo:latest
これで、サンプルアプリケーションを実行するために必要なものがすべて揃ったので、コンテナが相互に通信できるようにするカスタムネットワークを作成しましょう。
ステップ2—コンテナをリンクするネットワークを作成する
docker run
コマンドを使用してWebアプリケーションとデータベースコンテナを個別に起動すると、それらはお互いを見つけることができなくなります。
理由を確認するには、Webアプリケーションのデータベース構成ファイルの内容を表示してください。
- cat app/db.js
Mongoose (Node.jsのMongoDBオブジェクトモデリングライブラリ)をインポートし、新しいデータベーススキーマを定義した後、Webアプリケーションはホスト名db
、まだ存在していません。
var mongoose = require( 'mongoose' );
var Schema = mongoose.Schema;
var Todo = new Schema({
user_id : String,
content : String,
updated_at : Date
});
mongoose.model( 'Todo', Todo );
mongoose.connect( 'mongodb://db/express-todo' );
同じアプリケーションに属するコンテナがお互いを確実に検出できるようにするには、同じネットワーク上でそれらを起動する必要があります。
Dockerは、インストール中に作成されたデフォルトネットワークに加えて、カスタムネットワークを作成する機能を提供します。
次のコマンドを使用して、現在利用可能なネットワークを確認できます。
- docker network ls
Dockerによって作成された各ネットワークは、ドライバーに基づいています。 次の出力では、bridge
という名前のネットワークがドライバーbridge
に基づいていることがわかります。 local
スコープは、ネットワークがこのホストでのみ使用可能であることを示します。
Output from docker network lsNETWORK ID NAME DRIVER SCOPE
5029df19d0cf bridge bridge local
367330960d5c host host local
f280c1593b89 none null local
次に、アプリケーション用にtodo_net
という名前のカスタムネットワークを作成し、そのネットワーク上でコンテナーを起動します。
- docker network create todo_net
出力は、作成されたネットワークのハッシュを示します。
Output from docker network createC09f199809ccb9928dd9a93408612bb99ae08bb5a65833fefd6db2181bfe17ac
ここで、使用可能なネットワークを再度リストします。
- docker network ls
ここで、todo_net
を使用する準備ができていることがわかります。
Output from docker network lsNETWORK ID NAME DRIVER SCOPE
c51377a045ff bridge bridge local
2e4106b07544 host host local
7a8b4801a712 none null local
bc992f0b2be6 todo_net bridge local
docker run
コマンドを使用すると、--network
スイッチでこのネットワークを参照できるようになります。 特定のホスト名でWebコンテナとデータベースコンテナの両方を起動してみましょう。 これにより、コンテナがこれらのホスト名を介して相互に接続できるようになります。
まず、MongoDBデータベースコンテナを起動します。
- docker run -d \
- --name=db \
- --hostname=db \
- --network=todo_net \
- mongo
そのコマンドを詳しく見ると、次のことがわかります。
-d
スイッチは、コンテナをデタッチモードで実行します。--name
および--hostname
スイッチは、ユーザー定義の名前をコンテナーに割り当てます。--hostname
スイッチは、Dockerによって管理されるDNSサービスにもエントリを追加します。 これは、ホスト名でコンテナを解決するのに役立ちます。--network
スイッチは、デフォルトのブリッジネットワークではなく、カスタムネットワークでコンテナーを起動するようにDockerEngineに指示します。
docker run
コマンドからの出力として長い文字列が表示された場合、コンテナーは正常に起動されたと見なすことができます。 ただし、これはコンテナが実際に実行されていることを保証するものではありません。
Output docker runaa56250f2421c5112cf8e383b68faefea91cd4b6da846cbc56cf3a0f04ff4295
db
コンテナが起動し、docker logs
コマンドで実行されていることを確認します。
- docker logs db
これにより、コンテナログがstdout
に出力されます。 ログの最後の行は、MongoDBの準備ができており、waiting for connections
であることを示しています。
Output from docker logs2017-12-10T02:55:08.284+0000 I CONTROL [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=db
. . . .
2017-12-10T02:55:08.366+0000 I NETWORK [initandlisten] waiting for connections on port 27017
それでは、Webコンテナを起動して確認しましょう。 今回は、ホストのポート3000
をコンテナーのポート3000
に公開する--publish=3000:3000
も含まれています。
- docker run -d \
- --name=web \
- --publish=3000:3000 \
- --hostname=web \
- --network=todo_net \
- sammy/todo-web
以前と同様に、出力として長い文字列を受け取ります。
また、このコンテナが稼働していることを確認しましょう。
- docker logs web
出力は、 Express (テストアプリケーションのベースとなっているNode.jsフレームワーク)がlistening on port 3000
であることを確認します。
Output from docker logsExpress server listening on port 3000
ping
コマンドを使用して、Webコンテナーがdbコンテナーと通信できることを確認します。 これを行うには、疑似TTY(-t
)に接続されたインタラクティブ(-i
)モードでdocker exec
コマンドを実行します。
- docker exec -it web ping db
このコマンドは、標準のping
出力を生成し、2つのコンテナーが相互に通信できることを通知します。
Output from docker exec -it web ping dbPING db (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.210 ms
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.095 ms
...
CTRL+C
を押して、ping
コマンドを停止します。
最後に、Webブラウザでhttp://your_server_ip:3000
を指定して、サンプルアプリケーションにアクセスします。 Containers Todo Example というラベルの付いたWebページと、Todoタスクを入力として受け入れるテキストボックスが表示されます。
名前の競合を回避するために、docker rm
およびdocker network remove
コマンドを使用して、コンテナーを停止し、リソースをクリーンアップできるようになりました。
- docker rm -f db
- docker rm -f web
- docker network remove todo_net
この時点で、2つの別々のコンテナーで構成されるコンテナー化されたWebアプリケーションができました。 次のステップでは、より堅牢なアプローチを検討します。
ステップ3—マルチコンテナアプリケーションのデプロイ
リンクされたコンテナーを起動することはできましたが、マルチコンテナーアプリケーションを処理するための最も洗練された方法ではありません。 関連するすべてのコンテナを宣言し、それらを1つの論理ユニットとして管理するためのより良い方法が必要です。
Docker Composeは、開発者がマルチコンテナーアプリケーションを処理するために利用できるフレームワークです。 Dockefileと同様に、スタック全体を定義するための宣言型メカニズムです。 次に、Node.jsおよびMongoDBアプリケーションをDockerComposeベースのアプリケーションに変換します。
DockerComposeをインストールすることから始めます。
- sudo apt-get install -y docker-compose
サンプルWebアプリケーションのcompose
ディレクトリにあるdocker-compose.yaml
ファイルを調べてみましょう。
- cat compose/docker-compose.yaml
docker-compose.yaml
ファイルはすべてをまとめます。 これは、MongoDBコンテナーをdb:
ブロックに、Node.js Webコンテナーをweb:
ブロックに、カスタムネットワークをnetworks:
ブロックに定義します。
build: ../.
ディレクティブでは、Composeがapp
ディレクトリのDockerfile
を指していることに注意してください。 これにより、Webコンテナを起動する前にイメージをビルドするようにComposeに指示します。
version: '2'
services:
db:
image: mongo:latest
container_name: db
networks:
- todonet
web:
build: ../.
networks:
- todonet
ports:
- "3000"
networks:
todonet:
driver: bridge
次に、compose
ディレクトリに移動し、docker-compose up
コマンドを使用してアプリケーションを起動します。 docker run
と同様に、-d
スイッチはコンテナをデタッチモードで起動します。
- cd compose
- docker-compose up -d
出力は、DockerComposeがcompose_todonet
というネットワークを作成し、その上で両方のコンテナーを起動したことを報告します。
Output from docker-compose up -dCreating network "compose_todonet" with driver "bridge"
Creating db
Creating compose_web_1
明示的なホストポートマッピングを提供していないことに注意してください。 これにより、Docker Composeはランダムなポートを割り当てて、ホスト上のWebアプリケーションを公開します。 次のコマンドを実行すると、そのポートを見つけることができます。
- docker ps
Webアプリケーションがホストポート32782
で公開されていることがわかります。
Output from docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6700761c0a1e compose_web "node app.js" 2 minutes ago Up 2 minutes 0.0.0.0:32782->3000/tcp compose_web_1
ad7656ef5db7 mongo:latest "docker-entrypoint..." 2 minutes ago Up 2 minutes 27017/tcp db
Webブラウザをhttp://your_server_ip:32782
に移動して、これを確認します。 これにより、ステップ2の最後に表示されたとおりにWebアプリケーションが表示されます。
マルチコンテナーアプリケーションがDockerComposeを介して稼働している状態で、アプリケーションの管理とスケーリングを見てみましょう。
ステップ4—アプリケーションの管理とスケーリング
Docker Composeを使用すると、ステートレスWebアプリケーションを簡単にスケーリングできます。 1つのコマンドでweb
コンテナの10個のインスタンスを起動できます。
- docker-compose scale web=10
出力により、インスタンスが作成および開始されているのをリアルタイムで監視できます。
Output from docker-compose scaleCreating and starting compose_web_2 ... done
Creating and starting compose_web_3 ... done
Creating and starting compose_web_4 ... done
Creating and starting compose_web_5 ... done
Creating and starting compose_web_6 ... done
Creating and starting compose_web_7 ... done
Creating and starting compose_web_8 ... done
Creating and starting compose_web_9 ... done
Creating and starting compose_web_10 ... done
docker ps
を実行して、Webアプリケーションが10インスタンスにスケーリングされていることを確認します。
- docker ps
Dockerが、ホスト上の各web
コンテナーを公開するためにランダムなポートを割り当てていることに注意してください。 これらのポートのいずれかを使用して、アプリケーションにアクセスできます。
Output from docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cec405db568d compose_web "node app.js" About a minute ago Up About a minute 0.0.0.0:32788->3000/tcp compose_web_9
56adb12640bb compose_web "node app.js" About a minute ago Up About a minute 0.0.0.0:32791->3000/tcp compose_web_10
4a1005d1356a compose_web "node app.js" About a minute ago Up About a minute 0.0.0.0:32790->3000/tcp compose_web_7
869077de9cb1 compose_web "node app.js" About a minute ago Up About a minute 0.0.0.0:32785->3000/tcp compose_web_8
eef86c56d16f compose_web "node app.js" About a minute ago Up About a minute 0.0.0.0:32783->3000/tcp compose_web_4
26dbce7f6dab compose_web "node app.js" About a minute ago Up About a minute 0.0.0.0:32786->3000/tcp compose_web_5
0b3abd8eee84 compose_web "node app.js" About a minute ago Up About a minute 0.0.0.0:32784->3000/tcp compose_web_3
8f867f60d11d compose_web "node app.js" About a minute ago Up About a minute 0.0.0.0:32789->3000/tcp compose_web_6
36b817c6110b compose_web "node app.js" About a minute ago Up About a minute 0.0.0.0:32787->3000/tcp compose_web_2
6700761c0a1e compose_web "node app.js" 7 minutes ago Up 7 minutes 0.0.0.0:32782->3000/tcp compose_web_1
ad7656ef5db7 mongo:latest "docker-entrypoint..." 7 minutes ago Up 7 minutes 27017/tcp db
同じコマンドでWebコンテナをスケールインすることもできます。
- docker-compose scale web=2
今回は、余分なインスタンスがリアルタイムで削除されているのがわかります。
Output from docker-composeStopping and removing compose_web_3 ... done
Stopping and removing compose_web_4 ... done
Stopping and removing compose_web_5 ... done
Stopping and removing compose_web_6 ... done
Stopping and removing compose_web_7 ... done
Stopping and removing compose_web_8 ... done
Stopping and removing compose_web_9 ... done
Stopping and removing compose_web_10 ... done
最後に、インスタンスを再確認します。
- docker ps
出力は、インスタンスが2つだけ残っていることを確認します。
Output from docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
36b817c6110b compose_web "node app.js" 3 minutes ago Up 3 minutes 0.0.0.0:32787->3000/tcp compose_web_2
6700761c0a1e compose_web "node app.js" 9 minutes ago Up 9 minutes 0.0.0.0:32782->3000/tcp compose_web_1
ad7656ef5db7 mongo:latest "docker-entrypoint..." 9 minutes ago Up 9 minutes 27017/tcp db
これで、アプリケーションを停止できます。また、以前と同様に、リソースをクリーンアップして、名前の競合を回避することもできます。
- docker-compose stop
- docker-compose rm -f
- docker network remove compose_todonet
結論
このチュートリアルでは、DockerfilesとDockerComposeを紹介しました。 イメージを構築するための宣言型メカニズムとしてDockerfileから始め、次にDockerネットワークの基本を探りました。 最後に、DockerComposeを使用してマルチコンテナーアプリケーションをスケーリングおよび管理しました。
新しいセットアップを拡張するには、別のコンテナー内で実行されている Nginxリバースプロキシを追加して、使用可能なWebアプリケーションコンテナーの1つにリクエストをルーティングします。 または、DigitalOceanのブロックストレージおよびロードバランサーを利用して、コンテナー化されたアプリケーションに耐久性とスケーラビリティをもたらすことができます。