Kubernetes環境の規模が拡大し続けるにつれ、環境はより複雑化し、パフォーマンスと健全性のモニタリングがより困難になります。今回のアップデートでは、Kubernetesインテグレーション(v3)は、使用するCPUの数とメモリ容量が大幅に削減し、新たにRancherなどの外部コントロールプレーンに対応しているほか、問題の特定に役立つログメッセージが改善されています。たとえば大規模なクラスターでは、新しいインテグレーションを設定することにより、必要なメモリ容量を従来に比べて80%削減できます。これは大きな改善です。

このブログでは、新しいインテグレーションのメリットと、v3へのアップグレードに際して私たちが直面した課題の一部について説明します。

お客様がKubernetesインテグレーションをアップグレードすべきである理由

古いバージョンのKubernetesインテグレーションを使用している場合(またはNew RelicでKubernetesをモニターするのが初めての場合でも)、v3を使用することで多くのメリットが得られます。

  • メモリ使用量の削減:Kube状態メトリクス(KSM:kube-state-metrics)スクレイピングコンポーネントを改善したことにより、大きなクラスターを最大80%削減できます。
  • トラブルシューティングの改善:ログとプロセスサイクルを強化したことによりバグのトリアージと問題の修正が容易になりました。
  • 設定の自由度が向上:各データソースに対してより詳細な設定ができる設定ファイルなど、個別に構成可能な3つのコンポーネントを使用します。
  • 外部コントロールプレーンを抽出する:クラスター外部のコンポーネントからメトリクスを抽出します。
  • より柔軟なスクレイピング間隔:ニーズに合わせてデータ取り込み間隔を拡大または縮小します。

Kubernetesインテグレーションをアップグレードする方法

お客様がv2を使用しており、今すぐにアップグレードする準備ができている場合は、次のコマンドを実行するだけでアップグレードできます。

helm upgrade --install --my-installation newrelic/nri-bundle 

設定、ダッシュボード、アラートをアップデートする必要はありません。詳細については移行ガイドをご参照ください。

Kubernetesインテグレーションの改善の舞台裏

私たちはインテグレーションをアップデートするに当たり、留意すべき多くの要因に直面しました。私たちは、v2を使用しているお客様のために新しいインテグレーションを互換性のあるものにし、重要な機能強化を行い、アップグレードプロセスをできるだけ容易にしたいと考えました。また、インテグレーションのアーキテクチャーが変更される間、新しいインプリメンテーションを継続的にテストする必要もありました。

私たちはv3にアップグレードするに当たり、Kubernetesデプロイモデルと、まだ使用していなかった機能を十分に活用することを決めました。これが何を意味するのかをご理解いただくため、ここからやや技術的な説明をします。

Kubernetesの機能を完全に解き放つため、以下の点を改善しました。

  • Kubernetesインテグレーションが実行中ではなくスケジューリングおよびデプロイの最中によりスマートな決定を下せるようにするため、スクレイピングタスクを別々のコンポーネントに移動しました。
  • インテグレーションおよびエージェントプロセスを異なるコンテナに移動し、インテグレーションがKubernetesのベストプラクティスを踏襲したものにするため、サイドカーパターンに切り替えました。
  • RancherやマネージドapiServersなどのソリューションに対応するため、外部コントロールプレーンをスクレイピングする機能を追加しました。
  • Kubernetesインフォーマーを活用することで、キャッシュシステムの複雑さを緩和しました 。
  • リストやマップなどのインテグレーション設定で新たに複雑なデータ構造に対応できるようになりました。
  • コントロールプレーンのハードコーディングされたスクレイピング間隔を排除し、アプリケーションのニーズに合わせて間隔を手動で設定できるようにしました。

次のセクションでは、これらの各改善点の詳細を説明します。

分離されたコンポーネント設定

DaemonSetからKSMおよびコントロールプレーンコンポーネントをスクレイピングする際にデータが重複するのを回避するため、地域ベースのリーダー選定を実施しました。

バージョン2では、インフラDaemonSetが同じノードで実行されているポッドに応じて動作を変更するようになっています。

私たちは新しいアーキテクチャーを設計するに当たり、異なるインテグレーションタスクを異なるコンポーネントに分割し、異なるワークロードとしてスケジュールされるようにしました。各コンポーネントは、独自の個別の設定、リソース、注釈、ログなどを有しています。また、コンポーネントの挙動が同じノードで実行されているポッドによって、変化することがなくなりました。これにより、次のセクションで説明するように、Kubernetesインテグレーションが実行中ではなく、スケジュールおよびデプロイの最中でも、スマートな決定を下すことが可能になりました。

V3には、ノードで実行されているKubeletプロセスをスクレイピングするDaemonSetが含まれています。さらに、kube-state-metricsコンポーネントとコントロールプレーンコンポーネント /metricsを取得するための個別のデプロイメント機能も含まれています。設定によっては、コントロールプレーンコンポーネントとともにDaemonSetをデプロイできることもできます。

バージョン3では、アーキテクチャーがより複雑になったため、コードベースのサイズを縮小し、ユーザーエクスペリエンスを向上させています

最終的に、KubeStateMetricsインテグレーションのアーキテクチャーを最適化することでコードベースのサイズを縮小でき、New RelicのKubernetesインテグレーションエクスペリエンスが向上しました。

サイドカーパターンを使用して不要なプロセスを削除する

v2では、コンテナごとに複数のプロセスが存在しました。New Relicインフラストラクチャエージェントは、nri-kubernetesインテグレーションの実行を別のプロセスとして起動させていました。このアプローチは、コンテナ表面のメインプロセスで障害が発生したときにのみポッドが再起動されることを意味しました。

v2では、KubeStateMetricsインテグレーションはコンテナのメインプロセスではなかったため、設定エラーや実行エラーが発生した場合、障害を検知するのが難しい場合がありました。ポッドは自動的に再起動されなかったため、問題を検出するのが困難でした。

v3における新たなインプリメンテーションは、別のサイドカーで実行されているエージェントの隣のnri-kubernetesスクレーパーコンテナのサイドカーパターンに従います。コンテナごとに単一のプロセスを持つKubernetesはインテグレーションプロセスのライフサイクルを制御できるため、エラーによってインテグレーションが失敗したときに通知を送信し、ポッドを再起動します。

外部コントロールプレーンをスクレイピングする機能を追加

v2では、スクレイピングするURLを指定しても、外部コントロールプレーンをスクレイピングできませんでした。

アップデートされたKubernetesインテグレーションv3では、静的なエンドポイントを指定することができ、データの重複を避ける必要がある場合は、DaemonSetとしてではなく、デプロイメントとしてコントロールプレーンのコンポーネントをデプロイすることができます。

バージョン3におけるAWS APIサーバーコントロールプレーンのスクレイピング

また、bearer tokens や相互トランスポート層セキュリティ(MTLS)など、コンポーネントごとに異なる認証方法を指定することもできます。

また、デフォルトで追加されたautodiscovery 等の設定により、デフォルト設定はKubeadm、kind、minikube など、いくつかのKubernetesフレーバーに対応しています。設定でカバーされていないフレーバーについては、インテグレーションをセレクター、URL、または認証メソッドを使用するように構成することができます。

環境変数に基づく設定

v2では、お客様がインテグレーションを設定したい場合に、環境変数のみを使用することができました。このアプローチでは、お客様が設定できるのはキーの値だけであったため、複雑なシナリオへの対応を面倒な作業にしていました。たとえば、設定オプションがフラットリストだったため、どのグループ変数が属しているのかを示すプレフィックスを追加する必要がありました。これが原因で、ネストされた構成グループに新しいパラメーターを追加する必要があるたびに混乱が生じたため、異なるプレフィックスを持つ環境変数(DiscoveryCacheTTL、APIServerCacheTTL、APIServerCacheK8SVersionTTL、APIServerCacheK8SVersionTTLJitter)が必要でした。

新しいインテグレーションでは、リストやマップなどのより複雑なデータ構造に対応するためにYAML設定を活用しています。それによりお客様はインテグレーションの大半のパラメーターを設定することが可能になりました。一見すると、Helmチャートの新しいYAML設定は以前の設定よりも複雑に思えます。ところが新しいvalues.yamlは、Helmチャートでよく使用される追加構文を提供します。

最終的に設定が変更されると、インストール方法としてHelmが使用されていれば、インスタンスは自動的に再始動され、設定ファイルがリロードされます。

ハードコードされたスクレイピング間隔の設定を削除

v2では、スクレイピング間隔設定オプションは15秒にハードコーディングされています。お客様はこの間隔が設定可能であればよいと思っていたかもしれません。

それがv3で可能となりました。私たちはこのパラメーターを公開しました。これによりお客様は、間隔を手動で10~40秒の範囲で設定できるようになりました。デフォルトでは、間隔は15秒に設定されています。lowDataModeを選択すると、間隔が自動的に30秒に変更され、フェッチされるデータ量が減少します。

新しいアーキテクチャーはどのようにテストされたか

v3に追加された一連のインテグレーションテストは、当社の改善されたディスカバリー・アンド・モジュラー・アプローチを用いて事前に生成された静的データを各コンポーネントに入力します。

私たちは、インプリメンテーションプロセスから分離された新しいアプローチによってエンドツーエンドのテストを改善しました。テストに当たり、Kubernetes環境にグラフをインストールして、すべてのエンティティが作成されているかどうか、さらにKubernetes仕様のファイルに含まれるすべてのメトリクスがレポートされるかどうかを確認しました。これらのテストは特定のアーキテクチャーに依存せず、パイプライン全体をテストするため、Kubernetesインテグレーションの任意のバージョンまたはインプリメンテーションで実行できます。こうしたテストはv2からv3へのアップデートの最中に実行できたため、既存のバグを発見(および修正)することが可能になりました。

E2Eのテストは、特定のアーキテクチャーに依存しません。パイプライン全体をブラックボックスとしてテストします。

互換性に影響する変更をいかに削減したか

私たちは、お客様によるv3へのアップグレードを容易にするため、Helmチャートの互換性レイヤーを使用して古い値を新しい値にマッピングしました。このようにして、nri-kubernetesの最新バージョンのすべての恩恵を、互換性に影響する変更や設定変更で頭を悩ませることなく受けることができます。

バージョン2の値をサポートするため、互換性レイヤーが設けられています。