なぜ、OpenTelemetryなのでしょうか?なぜ、またオブザーバビリティの新たな領域に、わざわざ足を踏み入れなければならないのでしょうか?そもそも、OpenTelemetryとは一体何なのでしょうか?
コミュニティによる定義を見てみましょう。OpenTelemetryとは、トレース、メトリクス、ログなどのテレメトリーデータを生成、管理するオブザーバビリティフレームワークでありツールキットです。重要な点は、OpenTelemetryはベンダーやツールに依存しないということです。つまり、商業製品と併せてJaegerやPrometheusなどのオープンソースツールも含む、多種多様なオブザーバビリティバックエンドとともに使用することができます。OpenTelemetryは、Cloud Native Computing Foundation(CNCF)のプロジェクトです。
これは使いやすそうです。コミュニティのミッション、ビジョン、バリューを読むと、さらにいい感じです。とはいえ、同じような目標を掲げるCNCFサンドボックスプロジェクトは、おそらく山ほどあるでしょう。OpenTelemetry(OTelとも表記)がこれほど特別である理由は、何なのでしょうか?
このプロジェクトが発展してきた経過と、これに積極的に貢献している企業を確認してみると、これがどうやって進化を遂げてきたか、そして今後何が可能になっていくかが見えてきます。
実際に問うべきは、今これに参加しない理由があるか?ということです。
Kubernetesを理解する
このブログ記事の目的は、私たちの多くがすでにKubernetesについて知っていることではなく、役に立つかもしれない背景情報をご紹介することです。
Kubernetesが目指すのは、極めて可用性の高いプラットフォームです。その実現のため、多くの役割を複数の拡張可能なコンポーネントに移動できるよう設計されています。公式ドキュメントの概要をざっと見ていきましょう。
かなり多くの変動要素があり、ワークロードをスムーズに実行するには、それらが正常に運用される必要があります。幸運なことに、これらのコンポーネントはパフォーマンスのインサイトを詳細に示してくれるので、クラスタ内で何が起こっているかについてのさらに幅広い視点を得ることができます。さらに好都合なことに、すべてが同じ言語、Prometheusを使用しています。
クラスタレベルのメトリクスの収集
KubernetesはPrometheusで対話を行うため、ここでは同じ言語を使用するのが得策でしょう。ただし、これは、一見そう聞こえるほど単純なことではありません。
まず始めに、Prometheusはプル型のリソースモニタリングソフトウェアです。すなわち、Prometheusがメトリクスを取得したいエンドポイントはどれかを定義する必要があります。Kubernetesはその性質的に、コンテナのすばやい作成と削除においてきわめて動的であることを考えると、これはかなり大変です。
ありがたいことに、Prometheusはさまざまなデータ連携用ジョブを設定できるKubernetes用のサービス検出を提供しているため、Prometheusのインスタンスがどこからデータ取得するかを事前に決めることができます。
拡張性についてはどうでしょうか?
クラスタの規模が拡大するにつれ、Prometheusの1つのインスタンスに膨大なリソースとそれを実行する大規模マシンが必要になる場合があります。それより、規模の小さなマシンで複数の小規模インスタンスを実行するほうがいいと思うかもしれません。しかし、メトリクスをプルするときに複数のインスタンスを持つことは、同じエンドポイントを複数回スクレイピングすることにしかなりません。
これらを考慮の上、いよいよOpenTelemetryコレクターの説明に移ります。端的に言うと、OTelコレクターは、レシーバー、プロセッサ、およびエクスポーターの3つのコンポーネントから構成されています。この3つのコンポーネントのさまざまなオプションを使用することで、テレメトリーデータを処理する多様なパイプラインを構築し、必要に応じて異なるバックエンドに送信することができます。
OtelコレクターをKubernetesとの対話にどのように活用できるでしょうか?
Prometheusレシーバーは、Prometheusサーバーの設定と同様に設定できるため、シンプルに同一のスクレイピングジョブの定義を使用することができます。これのいいところは、取得したメトリクスをローカルに保管する必要が(メモリ以外に)ないことです。これはエージェントモードのPrometheusと考えることができます。
ここまではいい調子です。ただ、共有の問題がまだ残っています。OTelコレクターを水平方向に拡張することは、まだできません。ここで登場するのがTarget Allocatorです。Target Allocatorは、ステートフルなOtelコレクターにおいて、スクレイピングされるターゲットによってインスタンス全体に分散させることでPrometheusの設定を処理します。すべてのエンドポイントが、1つのOTelコレクターインスタンスで一度にスクレイピングされます。スクレイパーの拡張がどう機能するかについては、公式ドキュメンテーションをご参照ください。
Prometheusの機能、OTelコレクターの活用方法、その拡張方法についていろいろとご紹介してきましたが、実際に何を収集すべきかについてはまだ話していませんでした。ここで、Kubernetesが何を提供できるのかを見ていきましょう。
まず、すべてのコントロールプレーンのコンポーネントが専用ポートで示され、/metrics
エンドポイントのもとでメトリクスを提供します。例えば、kube-api-serverのスクレイピングジョブ設定を見てみましょう。
scrape_configs:
- job_name: 'kubernetes-apiservers'
scrape_interval: 60s
kubernetes_sd_configs:
- role: endpoints
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
relabel_configs:
- source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
action: keep
regex: default;kubernetes;https
次に、マシン(ノード)の可視性が必要です。ノードメトリクスの収集と抽出ができる成熟した普及製品はNode Exporterです。これをすべての(Linux)ノードでDaemonSetとして実行し、基盤のマシンで収集されるものを以下のようにスクレイピングします。
scrape_configs:
- job_name: 'kubernetes-node-exporter'
scrape_interval: 60s
honor_labels: true
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape_slow]
action: drop
regex: true
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+?)(?::\d+)?;(\d+)
replacement: $$1:$$2
- source_labels: [__meta_kubernetes_service_name]
action: keep
regex: <NODE_EXPORTER_SERVICE_NAME>
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: namespace
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: service
- source_labels: [__meta_kubernetes_pod_node_name]
action: replace
target_label: node
これでマシンレベルのメトリクスが得られるようになるため、次のレベルのコンテナ監視に移ります。コンテナメトリクスは、cAdvisorツール(Container Advisor)により収集され、これはすべてのノードで実行されます。以下のようにスクレイピングできます。
scrape_configs:
- job_name: 'kubernetes-nodes-cadvisor'
scrape_interval: 60s
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- target_label: __address__
replacement: kubernetes.default.svc:443
- source_labels: [__meta_kubernetes_node_name]
regex: (.+)
target_label: __metrics_path__
replacement: /api/v1/nodes/$$1/proxy/metrics/cadvisor
最後に重要なこととして、クラスタのコンポーネントの状態を知る必要があります。kube-state-metricsツールは、さまざまなエンドポイントにその情報を問い合わせてメトリクスを生成します。これもOTelコレクターのPrometheusレシーバーでスクレイピングができます。
scrape_configs:
- job_name: 'kubernetes-kube-state-metrics'
scrape_interval: 60s
honor_labels: true
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape_slow]
action: drop
regex: true
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+?)(?::\d+)?;(\d+)
replacement: $$1:$$2
- source_labels: [__meta_kubernetes_service_name]
action: keep
regex: <KUBE_STATE_METRICS_SERVICE_NAME>
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: namespace
- source_labels: [__meta_kubernetes_service_name]
action: replace
target_label: service
- source_labels: [__meta_kubernetes_pod_node_name]
action: replace
target_label: node
この時点で、監視したいすべての各コンポーネントに特化したスクレイピングジョブをシンプルに作成できることは、言うまでもありません。
クラスタから得られるその他の要素
Prometheusレシーバーから正常に収集されるメトリクスに加えて、クラスタからはイベントとログも収集できます(注:トレースはこのブログでは扱いません)。
イベントから見ていきましょう。Kubernetesは、クラスタで作成、削除、ミューテーションが行われるたびにイベントをターゲットにします。これらのイベントは、kube-api-serverのクエリにより取得できます。ありがたいことに、OTelコレクターにはそのためのレシーバーがあります。それが k8seventsレシーバーです(注:現在、このレシーバーの廃止と今後のk8sobjectレシーバーの使用について議論中)。
単一のコレクターのインスタンスを実行して、Kubernetesのイベントを取得し、それをログとしてNew Relicに転送できます。注意すべき点は、k8seventレシーバーの複数のインスタンスが同じイベントを取得し、New Relicに送信することです。
では、ログはどうでしょうか。OTelコレクターにはファイルログレシーバーが含まれており、これをDaemonSetとして実行し、そこにノードのログディレクトリをマウントできます。さまざまな正規表現(regex)を使用して、クラスタ内のあらゆるコンポーネントからのログを収集、解析、フィルタリング、強化できます。
New RelicでのOTelコレクターのデプロイと監視
必要なテレメトリーデータの場所を見つけ、収集する方法がわかりました。次に必要なのは以下のことです。
- 必要な設定を行い、OTelコレクターのインスタンスをデプロイする戦略を作成する
- 拡張的なNew Relicクエリ言語(NRQL)を使用して適切なダッシュボードとアラートを構築し、クラスタを監視する
幸運なことに、これまで話してきたすべてが含まれるリポジトリがあります。
- OTelコレクターの展開に使用できるパブリックのHelmチャート
- ビルト済みの監視を自身のNew Relicアカウントにブートストラップする際に使用できるTerraformのデプロイメント
詳細については、以下のリソースをご覧ください。
- こちらのドキュメンテーションを読んで、多様なタイプ(DaemonSet、デプロイメント、StatefulSet、シングルトン)のコレクターが必要な理由を理解する
- こちらのドキュメンテーションを参照し、クラスタに監視ソリューションをデプロイする
- こちらのドキュメンテーションで、収集したPrometheusデータを適切にクエリし、活用する方法を学ぶ
New Relicアカウントでダッシュボードとアラートを作成する方法については、こちらのドキュメンテーションをご覧ください。
次のステップ
このリポジトリは、パブリックな共同作業により構築されるものです。お客様にとってどんな有用な情報があるかをご覧ください。問題を作成したり、新機能について質問したり、さらに重要なこととして、ぜひ皆様の貢献をお待ちしています。
本ブログに掲載されている見解は著者に所属するものであり、必ずしも New Relic 株式会社の公式見解であるわけではありません。また、本ブログには、外部サイトにアクセスするリンクが含まれる場合があります。それらリンク先の内容について、New Relic がいかなる保証も提供することはありません。