Cloud Foundry を 2年間運用してみて、マイクロサービスの運用について考えたこと
最近ではすっかり kubernetes (k8s) が注目されていますが、k8s が流行り始める前から僕は業務で Cloud Foundry (CF) を運用しています。→ 20000 container journey
この記事での CF は CFAR (Cloud Foundry Application Runtime) を指します。CFCR (Cloud Foundry Container Runtime) は bosh 上で走る k8s であり、こちらは運用経験はありません。
CF は 2011 年に誕生し、2018年現在、基幹となる Diego のアーキテクチャなどの変更はあまりされていないものの、ログ取得の仕組みである LogCache や Container2Container (C2C) 通信やより柔軟なネットワーキングを実現するための Envoy を導入するなど様々な変更が行われています。
CF は k8s と明確に異なるプラットフォームを目指しており、2つは競合するものではありません。
具体的には、CF は opinionated (主張のある; 制約があるがそれに乗れば簡単) な PF であり、k8s は un-opinionated (主張しない; 極力利用者の好きなように使える) PF となっています。 実際、僕の職場では CFAR と k8s の両方を運用しており、その利用のされ方も異なります。
CF も k8s もコンテナ上で App を動作させるという点では同じであり、また PF としてローリングアップデートができるよう、マイクロサービスな作りになっています。
マイクロサービスを運用するためには、ログ・メトリクス収集基盤が必要
マイクロサービスは、全体として提供するビジネスロジックを小分けにし、各ビジネスロジックを VM やコンテナなどで独立して稼働させるアーキテクチャです。
これなら分かる! マイクロサービス(入門編)~モノリスと比較した特徴、利点と課題 (1/3):CodeZine(コードジン)
上記、記事にもあるとおり、マイクロサービスとモノリスはそれぞれでメリデメがあるのですが、CF を運用しているとマイクロサービスならでは大変さを感じました。
O(M*N) で増えるログとメトリクス
例えば、CF では gorouter と呼ばれる CF への http リクエストを App へルーティングするコンポーネントがあるのですが、これはリクエストの量に応じてスケールアウトできます。これはマイクロサービスの良いところで、コンポーネントが独立しているため、機能単位でのスケーリングが可能となっています。
しかし、コンポーネントが気軽に増やせる分だけ、出力されるメトリクスやログの量も自ずと O(N) だけ増加します(N はスケールアウトした数)。さらに新しいコンポーネントが追加された場合は、O(M*N) だけ増加します(M はコンポーネント数)。つまり、コンポーネントとその数が増減しても、それに対応できるログやメトリクス収集基盤が運用上必要 になってきます。
僕のチームではメトリクス収集システムとして Prometheus、ログ収集システムとして Splunk を利用していますが、CF の利用増加やリクエスト増加に伴う負荷も増えていき、安定的な提供を行うことが困難になっていきました。ElasticSearch などその他のシステムも同様でしょう。 (これらのログ・メトリクス収集基盤はマイクロサービス運用上必須のため、自ずと高い SLO が求められます)
マイクロサービスはコンポーネントが分離されている分、障害発生時には様々なログやメトリクスを突き合わせる必要があります。 モノリスであれば、ローカルにログファイルを出して、それを scp するなりして分析ができますが、それを 10 種類の異なるコンポーネントで行えと言われたら、その大変さは想像に難くないでしょう。さらにそれらのコンポーネントがスケールアウトされている状態だと、grep だけでは原因を突き止めるだけでかなり時間がかかってしまいます。
有意義なログと様々なメトリクスを残す
マイクロサービスのオペレーターとして考えることは有意義なログを残し、様々なメトリクスを取得しておくことです。
基本的に数値であるメトリクスのほうが、テキストのログよりもデータ量あたりの情報量が高いです。そこで、CF を運用する際は
- bosh-prometheus/firehose_exporter: Cloud Foundry Firehose Prometheus exporter
- bosh-prometheus/cf_exporter: Cloud Foundry Prometheus Exporter
- bosh-prometheus/bosh_exporter: BOSH Prometheus Exporter
- prometheus/mysqld_exporter: Exporter for MySQL server metrics
- prometheus/node_exporter: Exporter for machine metrics
などの Prometheus Exporter を駆使して、様々なメトリクスを記録しておきます。ストレージにどれほど余裕があるかによりますが、2週間は保存して置けると障害の対応後にメトリクスを振り返ることができます。
ログについては、CF すべてのコンポーネントのログを保存できればベストですが、障害の原因となりやすい、gorouter や MySQL、diegocell など利用者の App の挙動に直結するようなログのみを保存するように取捨選択しました。
ちなみに、CF を動作させる基盤である bosh は 12 ファクターな VM をデプロイする設計になっているため、VM recreate 時にローカルに保存していたログが消えたり、自動でログローテートするようになっています。つまり、その上で稼働する CF は VM のログを基本的にどこかへ送る必要があります。
さいごに
大規模なマイクロサービスを運用する場合は、それが CF であれ、k8s であれ、分散されているログ・メトリクスを集約する基盤が必要になります。 そして、その基盤は高い SLO でなければ、プラットフォームの障害原因の調査すらままならなくなります。
幸い自分のチームでは Splunk を保守するチームがいるため、倍々で増えていくログ量に対して対応できています。 オペレーター用のダッシュボードを作り、障害が発生したときはまずそのダッシュボードを見て、事態を把握するようチームメンバーと対応フローを共有することが可能です(たとえば、稼働している App の Status Code や router のレイテンシ)
良いツールが揃っていれば、障害対応も早く解決でき、その分システム改善に SREのリソースを割くことができます。システム改善により、障害が起こりにくくなれば、さらに時間に余分ができ、さらなる改善に時間を割り当てられます。その正のループを保ち続けることが SRE として非常に重要になってきます。
しかし、まずはログ収集基盤が揃わないうちはマイクロサービスを運用するのは困難という話でした。
Cloud Foundry Advent Calendar 2018 - Qiita の記事です。Happy Christmas!