第2のドワンゴ Advent Calendar 2016の9日目の記事です。
こっちのアドベントカレンダーで数少ない現役社員のビビるです。普段は主にニコニコ生放送周りでWebpackやTypeScriptとかを触るフロントエンドエンジニアをやっています。
最近気になっていたDockerとswarmを使って、クラスタリングと監視をやってみたいと思います。
そもそもSwarmとは
Dockerのバージョン1.12で追加された、Docker Engine内蔵のクラスタ管理機能です。
以前からあった Docker Swarmとは別物で、swarm mode
と呼ばれたりします。詳細は公式ページを見て下さい。
今回やりたいこと
- DockerのサービスとしてWebサーバー、APIサーバーを建てる
- それらのログを収集して、よしなに表示してくれる環境を作る
サーバーを準備する
Dockerのv1.12では、64-bitのLinuxのカーネルバージョン3.10以上が要求されます。その為、今回のサーバーOSはCentos 7系を選択しました。
丁度良いところにConoha VPSに 64bit Centos 7.2のテンプレートが準備されているようなので、それを利用します。
今回は管理用のマネージャーインスタンスを1台、ワーカーとなるインスタンスを2台準備します。準備フェーズのAnsible Playbook
今回使いませんでしたが、Conoha VPSにはプライベートネットワーク機能があり、とても便利です。実際に何かを作って本運用する際には、是非利用していきたいですね。
クラスタリングを準備する
Docker HubにイメージをPush
DockerHubに予め自分の動かしたいイメージをアップロードしておきます。プライベートなものはGoogle Container Registryなどを利用するのも良いかと思います。今回はテスト用なので、単純にAPIサーバーとWebサーバーの2種類のイメージをDocker Hubにアップロードしました。
Dockerのswarmをセットアップする
マネージャーのセットアップ
swarmのマネージャー(管理インスタンス)となるサーバーを1台決めておき、そのインスタンスで以下のコマンドを打ちます。
docker swarm init --advertise-addr XXX.XXX.XXX.XXX
ここで表示されるトークンは後々使うので、コピーしておきます。
また、合わせてWebインスタンスとApiインスタンス間の通信をやるためのネットワークを作ります。今回はサービス用のネットワークと、状態監視用のネットワークの2つを作ります。サブネットは他のシステムに影響がないように注意して設定して下さい。
docker network create --driver overlay --subnet 10.0.2.0/24 service
docker network create --driver overlay --subnet 10.0.3.0/24 monitoring
ワーカーのセットアップ
同様にワーカーも設定します。先程マネージャーのセットアップで表示されたトークンを利用します
docker swarm join --token YYYYYYY XX.XX.XX.XX:2377
マネージャーに戻って、以下のコマンドで正常にクラスタに組み込まれているのを確認できます
docker node ls
Api, Webのサービスを立ち上げる
docker service create --replicas 1 --env NODE_ENV=production --env PORT=80 --name api --network service --constraint 'node.role == worker' viviljp/test-api
docker service create --replicas 1 --env NODE_ENV=production --env PORT=3000 --publish 3000:3000 --name web --network service --constraint 'node.role == worker' viviljp/test-web
暫くすると、サービスが立ち上がっているのがわかります
docker service ls
スケーリング
折角クラスタを組んだので、スケーリングも試してみます。
マネージャーで以下のコマンドを打つことで、スケーリングを指示できます。
docker service scale web=3
どのマシンに何台インスタンスが割当たっているかは以下のコマンドで調べられます。
docker service ps web
既に死んだインスタンスもShutdown状態で表示されています。ここでは(意図的にweb2サーバーを2回止めたので)Web.1のインスタンスが2回再起動しているのが見て取れます。
dockerのswarmにはIngressネットワークという内部オーバーレイネットワークがあり、一つのサーバーにアクセスしても自動的に内部ルーティングをしてくれる便利な機能が備わっています。(今回の構成のうちweb, apiインスタンスが接続している service
もオーバーレイネットワークです。)
その為、複数のインスタンスを建てておいても勝手に負荷分散をやってくれます。便利な時代になったなあと思います。
監視をする
サービスを建てただけじゃ、ちゃんと動いているか不安になりますよね。ここでは各コンテナに対する監視もやっていきたいと思います。
各ノードにリソース確認用のツールを設定します
リソース監視ツールには、cAdvisorを利用しました。
docker service create --network=monitoring --mode global --name cadvisor \
--mount type=bind,source=/,target=/rootfs,readonly=true \
--mount type=bind,source=/var/run,target=/var/run,readonly=false \
--mount type=bind,source=/sys,target=/sys,readonly=true \
--mount type=bind,source=/var/lib/docker/,target=/var/lib/docker,readonly=true \
google/cadvisor
この場合、各ノードに1台ずつ立っていて欲しいので、グローバルモードで建てています。スケールをしなくなる代わりに、必ず1台1インスタンスずつ配置されるモードです。
これだけでも監視は可能なのですが、各サーバーに入ってチェックするのは面倒なので、一箇所でまとめて監視しておきたいですよね。
マネージャーノードに監視用ツールを設定する
リソース監視ツールを監視するためのツールをマネージャーに建てます。
今回は Prometheusを使ってみます。
docker service create --publish 9090:9090 --network=monitoring --name prometheus \
--mount type=bind,source=/tmp/prometheus.yml,target=/etc/prometheus/prometheus.yml,readonly=false \
--constraint 'node.role == manager' prom/prometheus
global:
external_labels:
monitor: 'service'
scrape_configs:
- job_name: 'docker'
scrape_interval: 5s
dns_sd_configs:
- names: ['tasks.cadvisor']
type: 'A'
port: 8080
このような感じでCPU使用率・メモリ使用率・ネットワーク状況など、様々な情報が取得できます。
より見やすく可視化する
prometheusで取得した情報は1項目ずつ確認する形になるのですが、まとめて確認するために、Grafanaなどのツールを使って可視化するのも良さそうです。
docker service create --constraint 'node.role == manager' --publish 3001:3000 grafana/grafana
デフォルトでは3000番ポートを使うのですが、webインスタンスとポートが衝突してしまったので、ずらしました…。ちゃんと計画的にポートを振ればよかったと後悔。
Grafanaは適切な設定をすれば、デフォルトでPrometheusをソースとして利用できます。
localhostと書いているところは、マネージャーインスタンスのIPになります
あとは、ダッシュボードの見た目を自分で好きなように調整すれば、下の画像のような自分が一番見やすい監視ツールを作ることができます。
dockerはサービス名指定しないと適当な名前をつけてくれます
GrafanaやPrometheusにはアラートを発する機能があるようなので、エラーログがいっぱい出たらSlackに通知!とかエンジニアなら誰でも欲しがるシステムを容易に構築できます。便利ですね。
他にも、elasticsearchとかfluentdを使ってログ収集などやってみるのも面白いかもしれません。
おわりに
DockerはストレージサービスのInfinitをちょうど買収したとの発表もあり、今後ますます目に掛かる機会は増えると思います。フロントエンジニアだから触らない!ということなく、どんどん新しい分野に挑戦していきたいです。
明日はD3vel0pperさんです。