MORITOMOMENT

登山好きエンジニアのテックブログ

プログラミング・アウトドア関連を中心に発信

Dockerチュートリアルを日本語で説明(第3章)

f:id:moritomo7315:20190117140005p:plain

第2章はコンテナについてのチュートリアルでしたが、

moritomo7315.hatenablog.com

今回はサービスについてのチュートリアルです。

なにをするかというと、

第2章で作成したコンテナをいくつか複製して、それらで負荷分散ネットワークを構築します。

見かけ上、アプリケーションの実行結果は変わりませんが、負荷分散ネットワークを構築することで、第2章だけのものよりも、高負荷のアクセスに耐えたりすることができるようになります。

先に結論をいうと、これを実現するためにはdocker-compose.ymlを書き特定のコマンドで実行することで簡単に構築することができます。

Dockerチュートリアルが英語しかないと思っていましたが、日本語版がありました。 なので公式のチュートリアルでも問題はないと思います。 本記事では、自分の勉強アウトプットのために投稿してますが、 公式のものにはない、 節の見通しを読者に与えたり、コマンドの実行結果や負荷分散の様子を載せているなど、 理解することに特化しているので、自分なりに公式より詳しく説明しているつもりです。

公式Docker Getstarted 日本語版

docs.docker.jp

  • Docker勉強し始めたい方
  • 公式の方でやってみたけどあまり理解できなくて困っている方

第3章の位置付け

第2章でも紹介した通りDockerでのアプリケーション開発では次の3層構造を意識します。 第3章では中間層の「Service」に着目します。

Service層は何のために位置付けられているかというと、

作ったアプリケーションの負荷を計測したり、負荷分散をおこなうなどアプリケーションの中でコンテナがどのように振る舞うかを決めるためにあります。

f:id:moritomo7315:20190120132832p:plain

Serviceについて

Serviceは1つのコンテナ(image)のみを実行することができます。

そしてimageをどのように実行するかを決めることができます。

例えば、

  • どのポートを使用するか
  • あるサービスが必要なキャパシティを満たすためには、いくつコンテナを複製すべきか

など考える際有効です。

サービスのスケーリングをしたい場合は実行するコンテナインスタンスの数を変更することで対応できます。

それでは本題に入っていきます。 上で述べたことはdocker-compose.ymlにより定義することで実現することができます。

docker-compose.yml

docker-compose.ymlはDockerコンテナがproductionでどのように振る舞うべきかを定義するYAMLファイルです。

まず次のdocker-compose.ymlをどこでもいいので作成してください。

docker-compose.yml↓

version: "3"
services:
  web: # サービス名をwebとする
    # 第2章で作成したimageのリポジトリに設定
    image: <username>/get-started:part2 #pullしたいリポジトリを指定
    deploy:
      replicas: 5 #webと名付けたimageのインスタンスを5つ用意
      resources:
        limits:
          cpus: "0.1" # 1つのインスタンスにつきCPUは10%まで使用可能
          memory: 50M # 1つのインスタンスにつきメモリは50MBまで使用可能
      restart_policy:
        condition: on-failure
    ports: # ポート指定 webの80ポートをホスト(自分のマシン)の4000ポートに割り当てる
      - "4000:80"
    networks:
      - webnet # webnetと呼ばれる負荷分散ネットワークに指定
networks:
  webnet:

docker-compose.ymlのimage: <username>/get-started:part2<username>を自分の環境に合わせて書き換えてください(第2章で設定しました)。

このYAMLはソースのコメントにも補足してありますが、次のことをDockerに伝えます。

  • image:で指定したリポジトリから第2章でアップロードしたimageをpullする。
  • replicasで指定される数分(今回は5つ)、imageのインスタンス(imageのコピーみたいなもの)を実行する。それぞれのインスタンスにつき、自分のPCのCPUの10%まで、メモリの50MBまで使用可能(limits:で指定)。
  • コンテナ終了時にステータスがon-failureだった場合、コンテナを再起動(restart_policyで設定)。
  • web(imageのサービス名)の80ポートをホスト(自分のマシン)の4000ポートに割り当てる
  • webnetと呼ばる負荷分散ネットワークを通じてwebのコンテナをポート80に共有する。
  • webnetをdefaultで定義する(webnet:の欄を空欄に)。defaultだと負荷分散オーバーレイネットワークとなります。

実際にこの負荷分散アプリケーションを動かしてみる

一連の流れは、

  1. docker swarm initswarmについては第4章で詳しく勉強します)
  2. docker stack deploy -c docker-compose.yml getstartedlabで実行。そのとき、この負荷分散アプリケーションにgetstartedlabと名前付けする。

この2つで負荷分散アプリケーションを実行することができます。

実際にやっていきます。

$ docker swarm init
実行結果↓
Swarm initialized: current node (bb7teuxa2thm4viwok5656dbz) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-0mub34dni79swd1yizk96yr0wxz3k1ba3dwd6254vbbokxo137-4pxnqgbp9189gujxcd8wpqr97 192.168.65.3:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
$ docker stack deploy -c docker-compose.yml getstartedlab
実行結果↓
Creating network getstartedlab_webnet
Creating service getstartedlab_web

これで負荷分散アプリケーションを実行することができました。 実行したService(負荷分散アプリケーション)のIDや名前等は次のコマンドでみることができます。

$ docker service ls
実行結果↓
ID                  NAME                MODE                REPLICAS            IMAGE                          PORTS
y56sievmxu2a        getstartedlab_web   replicated          5/5                 <username>/get-started:part2   *:4000->80/tcp

サービスgetstartedlab_webで実行している1つのコンテナを「タスク(task)」と呼びます。タスクはユニークなIDを与えられており、タスクはgetstartedlab_web.数字で名前づけられます。タスクは次のコマンドで確認できます。

$ docker service ps getstartedlab_web
実行結果↓
ID                  NAME                  IMAGE                          NODE                    DESIRED STATE       CURRENT STATE           ERROR               PORTS
nl2g7hvtdi8i        getstartedlab_web.1   <username>/get-started:part2   linuxkit-025000000001   Running             Running 7 minutes ago                       
m49n4b57eeak        getstartedlab_web.2   <username>/get-started:part2   linuxkit-025000000001   Running             Running 7 minutes ago                       
9uzg797m8g9y        getstartedlab_web.3   <username>/get-started:part2   linuxkit-025000000001   Running             Running 7 minutes ago                       
hzts1lw84gmr        getstartedlab_web.4   <username>/get-started:part2   linuxkit-025000000001   Running             Running 7 minutes ago                       
uqz4dwzereid        getstartedlab_web.5   <username>/get-started:part2   linuxkit-025000000001   Running             Running 7 minutes ago  

アプリケーションで実行されているコンテナをリストアップするために次のコマンドを入力します。

$ docker container ls -q
実行結果↓
9aaca126702d
dc6c04cd7d0f
3916b7b57456
86eb305ca950
4577652260b6

任意のブラウザでhttp://localhost:4000/にアクセスしてください。

第2章と同じアプリケーションを動かしているため、同様な見た目が得られると思います。

f:id:moritomo7315:20190120130944p:plain

次にブラウザを更新してみてください。

するとHostnameの欄の値が変わると思います。

Hostnameの値の変わり方は5通りです。

f:id:moritomo7315:20190120131106p:plain

f:id:moritomo7315:20190120131050p:plain

f:id:moritomo7315:20190120131018p:plain

f:id:moritomo7315:20190120130959p:plain

この結果からわかるように、同じ結果を出力しているように見えて、それを出力しているhostが異なるのは負荷分散の恩恵です。 replicasで設定した数通りのhostによって負荷分散をできています。

また負荷分散アプリケーションのスケールを変更したい場合は、docker-compose.ymlreplicasの値を任意の値に書き換えて、

再び、docker stack deploy -c docker-compose.yml getstartedlabを実行すれば可能です。

試しにreplicasの値を5から8に変更しスケールアウトしてみましょう。

$ docker stack deploy -c docker-compose.yml getstartedlab
実行結果↓
Updating service getstartedlab_web (id: y56sievmxu2a1utk7h0zn8pn1)

実行結果の通り、Serviceの設定がアップデートされましたね。

また、

$ docker container ls -q
実行結果↓
2f7d8d74eef5
f60847282801
6c9af7c20321
96a2cce21a3b
bf2968c19aa4
3d19166e560d
b8c2baf1cf51
513adc5f9d54

上記コマンドの実行結果より、8つのインスタンスが動いていることがわかります。

このようにアプリケーションのスケールアウトも簡単にできます。

アプリケーションを停止させる

アプリケーションを停止させるためにはdocker stack rm <アプリケーション名>を実行します。

今回はアプリケーション名をgetstartedlabにしていたので、

$ docker stack rm getstartedlab
実行結果↓
Removing service getstartedlab_web
Removing network getstartedlab_webne

のように停止します。

普段からLinuxやMax、Unixを使用しているのであれば、rmというコマンドを使用するのでわかりやすいのではないでしょうか。

またSwarmというものも動作しているので

$ docker swarm leave --force
実行結果↓
Node left the swarm.

でswarmに対するコマンドも実行します。

まとめ

内容をもう一度まとめておきます。

今回はService層の役割を学ぶために、

負荷分散アプリケーションを作成しました。

第2章で作成したfriendlyhelloイメージのコンテナに 複製やネットワーク構成等の振る舞いの仕方をdocker-compose.ymlで命令することで負荷分散アプリケーションを実現しました。

  • 第3章の位置付け
  • docker-compose.ymlについて
  • 負荷分散アプリケーションの実行
  • 負荷分散アプリケーションのスケールアウト
  • 負荷分散アプリケーションの停止

Dockerの勉強頑張りましょう!!

コンテナについては第2章はこちらから。

docs.docker.jp

moritomo7315.hatenablog.com

第4章は出来次第更新