データなしでDocker Swarmを運用する恐怖
初めてプロジェクトにDocker Swarmを導入した際、些細なミスのせいで徹夜したことがあります。当時は、Swarmがオーケストレーションをうまくやってくれるので、サービスが停止しても自動で復活するから心配ないと思っていました。しかし、現実はもっと過酷でした。設定ミスでサービスがCrashLoopBackOffに陥り、Swarmが再起動とクラッシュを繰り返したのです。サーバーのCPU使用率は95%に跳ね上がり、ログがディスクを埋め尽くしていることに、顧客から苦情の電話が来るまで気づきませんでした。
モニタリングなしで10〜15ノードのクラスターを管理するのは、霧の中を運転するようなものです。以前は各マネージャーノードにSSHで入り、docker service lsを何度も打ち込んで状態を確認していました。この手動の方法は非常に時間がかかり、ミスも起きやすいです。今ではダッシュボードを見るだけで、どのサービスのレプリカが不足しているか、どのノードが過負荷かがすぐに分かります。
3つのツール:Prometheus、cAdvisor、Docker Swarm
効果的な監視を行うには、個別にインストールするのではなく、自動的にデータを収集する仕組みが必要です。私は、Swarm自体の機能を活用して監視スタックを構築する方法を選びました。
- cAdvisor (Container Advisor): 各ノードに常駐する「エージェント」のような存在です。各コンテナのCPU、RAM、ネットワークなどの統計情報を抽出します。Swarmでは、全ノードを漏れなくカバーするために
mode: globalで実行します。 - Prometheus: 中央の「脳」の役割を果たします。定期的にcAdvisorにアクセスしてデータを取得(プル・メカニズム)し、時系列データベースに保存します。
- Docker Engine Metrics: バージョン17.05以降、DockerはPrometheus形式のメトリクスを出力できるようになりました。この機能を有効にすることで、クラスター全体の真の状態を把握できます。
データ出力のためのDocker Engine設定
デフォルトでは、Dockerのメトリクスポートは閉じられています。Prometheusがレプリカ数のデータを読み取れるようにするには、すべてのノードで/etc/docker/daemon.jsonファイルを編集する必要があります。
{
"metrics-addr" : "0.0.0.0:9323",
"experimental" : true
}
修正後、次のコマンドでDockerを再起動します:
sudo systemctl restart docker
重要な注意点:0.0.0.0:9323ポートを開放すると、サーバーがパブリックIPを持っている場合にセキュリティリスクが生じる可能性があります。ファイアウォール(UFW/Iptables)を使用して、クラスター内の内部IPのみがこのポートにアクセスできるように制限すべきです。
監視スタックのデプロイ
個別のコマンドを実行する代わりに、すべてをmonitoring-stack.ymlファイルにまとめます。この方法の利点は、一貫性が高いことです。以下は、イメージしやすいように簡略化した設定です:
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- "9090:9090"
networks:
- monitor-net
deploy:
placement:
constraints: [node.role == manager]
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
networks:
- monitor-net
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
deploy:
mode: global
resources:
limits:
memory: 128M
networks:
monitor-net:
driver: overlay
Prometheusにおけるサービスディスカバリの威力
Swarm環境では、コンテナは頻繁にノード間を移動します。IPアドレスが絶えず変わるため、設定ファイルに静的なIPを記述することはできません。Prometheusは、dockerswarm_sd_configs機能によってこの問題を解決します。
下図は、Prometheusが自動的にノードを検出するための設定例です:
scrape_configs:
- job_name: 'docker-swarm'
dockerswarm_sd_configs:
- host: unix:///var/run/docker.sock
role: nodes
relabel_configs:
- target_label: __address__
replacement: 127.0.0.1:9323
docker.sockファイルをPrometheusコンテナにマウントするのを忘れないでください。このステップを怠ると、Prometheusはアクセスを拒否され、Docker Swarmに稼働中のノードリストを問い合わせることができなくなります。
実践的なRolling Updateとレプリカの監視
データが収集されたら、通常は以下の3つの実践的なシナリオに注目します:
1. レプリカ不足のアラート
5つのレプリカを要求しているのに3つしか動いていない場合、システムは危険な状態にあります。以下のクエリを使うと、不足しているサービスを特定できます:
engine_daemon_swarm_service_tasks_total{state="running"}
2. Rolling Updateの制御
docker service updateを実行した際、新しいバージョンにバグがあるとアップデートプロセスがハングすることがあります。私はengine_daemon_container_states_containersメトリクスを監視しています。アップデート後にrestarting状態が急増した場合は、サービスの中断を防ぐために即座にロールバックを行います。
3. ノードのヘルスチェック
dockerswarm_node_statusメトリクスは非常に便利です。かつて、あるノードのネットワーク接続が切れましたが、Swarmがそのノードにトラフィックを振り分け続け、502エラーが多発したことがありました。Prometheusからのアラートのおかげで、2分以内に発見して対処することができました。
最後に
監視を設定するのは、単にきれいなグラフを描くためではありません。それは、夜ぐっすり眠るためのツールです。不安に怯える代わりに、Prometheusにシステムを見守らせましょう。もし、あなたのクラスターが本番環境で稼働しているのにcAdvisorやPrometheusを導入していないなら、今日30分かけてインストールしてください。それが将来、何時間ものデバッグの苦労からあなたを救ってくれるはずです。

