Part 5:スタック

必要条件

  • Docker バージョン 1.13 以上のインストール
  • Part 4 を入手。
  • Part 1 の概要を読んでいること
  • Part 2 のコンテナの作成方法学んでいること
  • 自分で作成した friendlyhello イメージを レジストリに送信 して公開済みなのを確認します。ここでは、この共有イメージを使います。
  • イメージをコンテナとしてデプロイできるのを確認します。次のコマンドを実行しますが、 ユーザ名リポジトリ タグ は皆さんのものに置き換えます。コマンドは docker run -p 80:80 ユーザ名/リポジトリ:タグ です。そして http://localhost/ を表示します。
  • Part 3 で扱った docker-compose.yml のコピーを持っていること
  • Part 4 でセットアップしたマシンが実行中かつ準備できていること。確認には docker-machine ls を実行。マシンが停止している場合は、マネージャを docker-machine start myvm1 で起動し、ワーカを docker-machine start myvm2 で起動
  • Part 4 で作成した swarm (クラスタのこと)が実行中かつ準備できていること。確認には docker-machine ssh myvm1 "docker node ls" を実行。swarm が起動中であれば、いずれのノードも status (状態)は ready (準備完了)。そうでなければ、swarm を再度初期化し、ワーカを swram としてセットアップ します。

はじめに

Part 4 では、 swarm のセットアップ方法を学びました。swarm とは Docker を実行しているマシンのクラスタであり、アプリケーションを複数のマシン上へ一斉にデプロイします。

この Part 5 では、 スタック(stack) という分散アプリケーション階層の頂上に辿り着きました。スタックは相互関係を持つサービスのグループであり、依存関係を共有します。そして、同時にオーケストレート(訳者注;複数のサーバ上で一斉に挙動する)やスケール(訳者注;サービスの拡大および縮小)します。1つのスタックでアプリケーション全体の能力を定義し、機能全体をコード化します(複雑なアプリケーションであれば、複数のスタックを使うことになるでしょう)

良いお知らせがあります。スタックに関する技術的な内容は Part 3 で既に学んだとおり、 Compose ファイルを作成し、 docker stack deploy を実行するだけです。しかし、これまで行ったことは1つのホスト上で1つのサービス・スタックを動かしただけであり、プロダクションではあまり見ない環境です。ここでは従来の学びに加え、複数のマシン上で複数の関連サービスをお互いに作成し、実行しましょう。

ここまでおつかれさまでした。あと一息です!

新しいサービスの追加と再デプロイ

サービスは docker-compose.yml に追加するだけであり、とても簡単です。まず、swarm でコンテナのスケジューリングを調べるために、自由に使える可視化サービスを追加しましょう。

  1. エディタで docker-compose.yml を開き、内容を以下の通りに書き換えます。 username/repo:tag の部分は、皆さんのイメージにあわせてください。
version: "3"
services:
  web:
    # username/repo:tag は皆さんの名前とイメージにあわせて書き換えます
    image: username/repo:tag
    deploy:
      replicas: 5
      restart_policy:
        condition: on-failure
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
    ports:
      - "80:80"
    networks:
      - webnet
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
networks:
  webnet:

新しく追加したのは visualizer という名前の web と対となるサービスです。そして、ここでは新しい2つのものがあります。1つは volumes キーであり、ビジュアライザが Docker ホスト側のソケットファイルにアクセスするためです。それと、 placement キーはサービスが swarm マネージャのみでしか動作しないよう指定しています。ワーカーでは決して動きません。これは Docker によって作られたオープンソース・プロジェクト であり、 swarm 上で実行している Docker サービスを図で表示するものです。

placment 制限(constraint)とボリュームの詳細は後述します。

  1. 新しい docker-compose.yml を swarm マネージャ myvm1 にコピーします。
docker-machine scp docker-compose.yml myvm1:~
  1. マネージャ上で docker stack deploy コマンドを再度実行し、更新が必要なサービスはアップデートが始まります。
$ docker-machine ssh myvm1 "docker stack deploy -c docker-compose.yml getstartedlab"
Updating service getstartedlab_web (id: angi1bf5e4to03qu9f93trnxm)
Updating service getstartedlab_visualizer (id: l9mnwkeq2jiononb5ihz9u7a4)
  1. ビジュアライザを確認します。

Compose ファイルにあった visualizer はポート 8080 で動作します。 docker-machine ls を実行して、実行中のノードの IP アドレス1つを確認します。いずれかの IP アドレスの1つのポート 8080 を開くと、ビジュアライザの動作を確認できます。

(スクリーンショット;todo)

期待した通り、マネージャ上では visualizer のコピーが動作し、 web の5つのインスタンスは swarm 全体に展開しています。図の内容が正しいかどうかを確認するには、 docker stack ps <stack> を実行します。

docker-machine ssh myvm1 "docker stack ps getstartedlab"

ビジュアライザはスタンドアローンのサービスのため、スタック上のあらゆるサービスと実行できます。また、その他のものと依存関係はありません。次は依存関係を 持つ サービスを作成しましょう。Redis サービスは来訪者カウンタ機能を提供します。

データの保持

同じワークフローを通して、今度はアプリのデータを保管する Redis データベースを追加しましょう。

  1. 末尾に Redis サービスを追加した、新しい docker-compose.yml ファイルを保存します。ただし、 username/repo:tag は皆さんのイメージに置き換えてください。
version: "3"
services:
  web:
    # username/repo:tag は皆さんの名前とイメージに置き換えてください
    image: username/repo:tag
    deploy:
      replicas: 5
      restart_policy:
        condition: on-failure
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
    ports:
      - "80:80"
    networks:
      - webnet
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
  redis:
    image: redis
    ports:
      - "6379:6379"
    volumes:
      - ./data:/data
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
networks:
  webnet:

Redis は Docker ライブラリ内に公式イメージがあるため、 image 名にあたる部分は redis のみに省略できます。そのため、ここでは ユーザ名/リポジトリ名 を明示する必要はありません。Redis では予め Redis 用にホスト側のポート 6379 をコンテナに対して公開するよう指定済みです。そのため、この Compose ファイルでは、クラスタ上のどこかのホスト上でポートを公開するのを指定するだけです。そのため、 Redis Desktop Manager で Redis インスタンスを管理するには、実際にはノード上のいずれかの IP アドレスを指定するだけで構いません。

最も重要なのは、このスタックに redis をデプロイするにあたり、データの保存を指定している箇所が2つあります。

  • redis は常にマネージャ上で動作し、常に同じファイルシステムを使用する
  • redis は Redis のデータ保管用に、ホスト側ファイルシステム上の外部ディレクトリを、コンテナ内から /data としてアクセスする

同時に、ここで Redis データを「実際に保存」するのは、ホスト側の物理ファイルシステム上です。この指定がなければ、Redis はコンテナのファイルシステム内にある /data へデータを保管しようとするため、データを取り出すことができず、コンテナの再デプロイを行えなくなってしまいます。

実際のデータ保管には2つのコンポーネントが関わります。

  • Redis サービスを置く場所は、同一ホスト上を用いる制約を設けます
  • 作成したボリュームには、コンテナは(ホスト上の) ./data を(Redis コンテナ内では) /data としてアクセスします。コンテナが稼働後は、ホスト上に指定した ./data にファイルが保管され続けます。

これで Redis を使う新しいスタックをデプロイする準備が整いました。

  1. マネージャ上で ./data ディレクトリを作成
$ docker-machine ssh myvm1 "mkdir ./data"
  1. docker-machine scp で新しい docker-compose.yml ファイルをコピー
$ docker-machine scp docker-compose.yml myvm1:~
  1. docker stack deploy をもう一度実行
$ docker-machine ssh myvm1 "docker stack deploy -c docker-compose.yml getstartedlab"
  1. ノードいずれかのウェブページを確認し(例: http://192.168.99.101 )、来訪者カウンタの動作を確認します。ここで表示されるデータは Redis で保管されたものです。

(Todo;図、ブラウザで Redis 対応 Hello World を確認)

また、他のノードの IP アドレスでポート 8080 を開き、ビジュアライザを確認します。そうしますと、 webvisualizer サービスと同様に、 redis サービスが動いているのが分かります。

(ToDo;VirualizerでRedisを確認するスクリーンショット)

まとめ(オプション)

このページで扱ったターミナルの録画 がこちらです。

以上、スタックとは内部で連携するサービスがすべて協調動作するものと学びました。皆さんは既にチュートリアルの Part 3 からスタックを使っていたのです。つまり「すごーい!」 スタック上へのサービス追加とは Compose ファイルへの追加と学んでいます。そして、どこで動かすのかという制約(constraint)と、作成したデータを保存し続ける場所としてのボリュームについて学びました。ですから、コンテナが停止して再デプロイしたとしても、アプリのデータは残り続けるのです。