コレクタ設定ファイルを一式仕上げる
目標
本番に載せられるコレクター設定ファイル一式を、最初から最後まで作成します。終わると、他人のコレクター設定を見て、プロセッサーの順序だけでどのような事故が起きるかを予測できるようになります。
なぜ重要なのか
コレクターの設定は、YAMLが1行ずれただけでもプロセスが起動できなくなりますが、問題は、その事実にほとんどの場合クラスターでCrashLoopBackOffを見てはじめて気づくという点です。さらに悪いのは、起動はするのに黙って間違っている設定です。memory_limiterを後ろに置くと、普段は何も問題がないのに負荷が来たときだけOOMで落ち、batchをtail_samplingの前に置くと、トレースがランダムに切れるのにメトリクスは何の異常も報告しません。コンポーネントを定義しただけでserviceに載せないと、設定ファイルにはあるのに動作しません。この3つがコレクター事故の大部分で、3つとも設定ファイルを読むだけで見つけられます。
ステップ
/root/otca-collector/config.yamlを作成し、receivers.otlp.protocolsの下にgrpc.endpoint: 0.0.0.0:4317とhttp.endpoint: 0.0.0.0:4318を書いてください。processors.memory_limiterにcheck_interval: 1s、limit_mib: 1638、spike_limit_mib: 328を書いてください(コンテナのメモリ上限2Giが基準です)。processors.k8sattributesにauth_type: serviceAccountを書き、extract.metadataにk8s.namespace.name、k8s.deployment.name、k8s.pod.name、k8s.node.nameの4つを入れてください。processorsにattributes/redactを作成し、actionsに3つ入れてください。http.request.header.authorizationはdelete、user.emailはdelete、db.query.textはhashにします。processors.batchにtimeout: 5s、send_batch_size: 8192、send_batch_max_size: 16384を書いてください。exportersに3つ定義してください。otlp/tempoはendpointに4317ポートを持つアドレス、otlp/gatewayも4317ポートを持つアドレスにします。prometheusremotewriteは、/api/v1/pushで終わるhttpのURLに、sending_queue(enabled: true、num_consumers: 10、queue_size: 5000)とretry_on_failure(enabled: true、initial_interval: 5s、max_elapsed_time: 300s)を付けてください。extensionsにhealth_check.endpoint: 0.0.0.0:13133とzpages.endpoint: 0.0.0.0:55679を定義し、service.extensionsに2つの名前をどちらも載せてください。service.pipelinesに3つのパイプラインを書いてください。tracesは、プロセッサーを[memory_limiter, k8sattributes, attributes/redact, batch]、エクスポーターを[otlp/tempo]にします。metricsは[memory_limiter, k8sattributes, batch]に[prometheusremotewrite]、logsは[memory_limiter, k8sattributes, attributes/redact, batch]に[otlp/gateway]にします。3つのパイプラインとも、レシーバーは[otlp]です。
参考
attributes/redactのようにスラッシュを付けた名前は、同じタイプの2つ目のインスタンスを意味します。YAMLのキーにスラッシュが入るため、参照するときは名前を正確に合わせてください。- よくある間違い1: コンポーネントを定義しただけで、
serviceに載せないことです。拡張も同様です。 - よくある間違い2:
send_batch_max_sizeを書き忘れることです。send_batch_sizeはトリガーにすぎません。 - よくある間違い3:
attributes/redactをk8sattributesの前に置くことです。新しく付く属性が、削除をすり抜けます。
OTLPレシーバーの2つのポート
/root/otca-collector/config.yamlを作成し、receivers.otlp.protocolsの下にgrpc.endpoint: 0.0.0.0:4317とhttp.endpoint: 0.0.0.0:4318を書いてください。
otlpレシーバーは、protocolsの下にgrpcとhttpを別々に持ちます。片方だけ開けておくと、もう片方へ送るSDKは接続そのものが失敗し、コレクターのメトリクスには何の痕跡も残りません。コンテナの中では、ループバックではなくすべてのインターフェースにバインドする必要があります。
memory_limiterの値を見積もる
processors.memory_limiterにcheck_interval: 1s、limit_mib: 1638、spike_limit_mib: 328を書いてください(コンテナのメモリ上限2Giが基準です)。
コンテナのメモリ上限が2Giだと仮定します。ハードリミットはその80%、スパイクの許容値はハードリミットの20%にするのが慣例です。コンテナの上限より高く設定すると、プロセッサーが介入する前にカーネルが先に強制終了します。
Kubernetesメタデータを付与する
processors.k8sattributesにauth_type: serviceAccountを書き、extract.metadataにk8s.namespace.name、k8s.deployment.name、k8s.pod.name、k8s.node.nameの4つを入れてください。
このプロセッサーは、Pod IPを手がかりにAPIサーバーからメタデータを探して、リソース属性として付けます。そのため認証方式を指定する必要があり、必要な項目だけをextractに並べて負荷を減らします。
機微属性の削除とハッシュ化
processorsにattributes/redactを作成し、actionsに3つ入れてください。http.request.header.authorizationはdelete、user.emailはdelete、db.query.textはhashにします。
プロセッサー名にスラッシュを付けると、同じタイプの2つ目のインスタンスを作れます。完全に消してしまうと、あとで同じ値同士をまとめて見ることができなくなるため、クエリ文のようにグルーピングが必要な値は、消す代わりにハッシュ化します。
batchのトリガーと上限
processors.batchにtimeout: 5s、send_batch_size: 8192、send_batch_max_size: 16384を書いてください。
send_batch_sizeは「これだけたまったらすぐ送れ」というトリガーであって、バッチサイズの上限ではありません。上限は別のキーで指定する必要があり、指定しないと、バッチが予想よりずっと大きくなることがあります。
3つのエクスポーターとキュー・リトライ
exportersに3つ定義してください。otlp/tempoはendpointに4317ポートを持つアドレス、otlp/gatewayも4317ポートを持つアドレスにします。prometheusremotewriteは、/api/v1/pushで終わるhttpのURLに、sending_queue(enabled: true、num_consumers: 10、queue_size: 5000)とretry_on_failure(enabled: true、initial_interval: 5s、max_elapsed_time: 300s)を付けてください。
sending_queueは、バックエンドが少し遅くなったときにデータを保持しておき、retry_on_failureは、失敗を指数バックオフで再試行します。どちらもオフだと、バックエンドが不安定になるたびにデータがそのまま失われます。
health_checkとzpages
extensionsにhealth_check.endpoint: 0.0.0.0:13133とzpages.endpoint: 0.0.0.0:55679を定義し、service.extensionsに2つの名前をどちらも載せてください。
拡張は、定義しただけでは動作しません。serviceの下にも名前を載せてはじめて有効になります。health_checkはlivenessプローブとreadinessプローブが叩くエンドポイントで、zpagesは最近のトレースとパイプラインの状態を表示します。
3つのパイプラインとプロセッサーの順序
service.pipelinesに3つのパイプラインを書いてください。tracesは、プロセッサーを[memory_limiter, k8sattributes, attributes/redact, batch]、エクスポーターを[otlp/tempo]にします。metricsは[memory_limiter, k8sattributes, batch]に[prometheusremotewrite]、logsは[memory_limiter, k8sattributes, attributes/redact, batch]に[otlp/gateway]にします。3つのパイプラインとも、レシーバーは[otlp]です。
並べた順序がそのまま処理順序です。メモリ保護は先頭で行うと上流へbackpressureが戻り、バッチは末尾に置くとほどいてまた束ねる無駄がありません。メタデータを付けるプロセッサーは新しい属性を作ることがあるため、削除はその後に来ます。