OpenTelemetry Collector を使用して Kubernetes ログ データを収集する

OpenTelemetry Collector を使用して Kubernetes ログ データを収集する

先ほど、OpenTelemetry Collector を使用して Kubernetes クラスターのメトリック データを収集する方法を紹介しました。次に、クラスター ログ データを収集する方法を学びます。

Lokiのインストール

まず、ログデータを収集するために Loki をデプロイする必要があります。ここでも、迅速なデプロイメントのために Helm Chart を使用します。ただし、OpenTelemetry Collector を使用してログ データを収集し、それを Loki に送信するため、ログ コレクターを展開する必要はないことに注意してください。

 $ helm repo add grafana https://grafana.github.io/helm-chart $ helm repo update

ここで、Loki Helm Chart を構成するために loki-values.yaml ファイルを作成します。

 # loki-values.yaml loki: commonConfig: replication_factor: 1 auth_enabled: false storage: type: "filesystem" singleBinary: replicas: 1 persistence: enabled: true size: 10Gi storageClass: cfsauto monitoring: lokiCanary: enabled: false selfMonitoring: grafanaAgent: installOperator: false test: enabled: false gateway: ingress: enabled: true ingressClassName: nginx tls: [] hosts: - host: loki.k8s.local paths: - path: / pathType: Prefix

次に、次のコマンドを使用して、ワンクリックで Loki をデプロイします。

 $ helm upgrade --install loki grafana/loki -f loki-values.yaml --namespace kube-otel $ kubectl get pods -n kube-otel -l app.kubernetes.io/instance=loki NAME READY STATUS RESTARTS AGE loki-0 1/1 Running 0 3m52s loki-gateway-5ffc9fbbf5-m5q75 1/1 Running 0 8m42s $ kubectl get ingress -n kube-otel NAME CLASS HOSTS ADDRESS PORTS AGE loki-gateway nginx loki.k8s.local 10.98.12.94 80 11m

ファイルログレシーバーを有効にする

次に、ログ データを Loki に送信するように OpenTelemetry Collector を構成する必要があります。まず、otel-collector-ds-values.yaml ファイルを更新します。 Loki エクスポーターを追加し、filelogreceiver レシーバーを有効にする必要があります。

 # otel-collector-ds-values.yaml mode: daemonset presets: hostMetrics: enabled: true kubernetesAttributes: enabled: true kubeletMetrics: enabled: true # 启用filelogreceiver 收集器logsCollection: enabled: true config: exporters: loki: endpoint: http://loki-gateway/loki/api/v1/push timeout: 10s # 超时时间read_buffer_size: 200 write_buffer_size: 100 retry_on_failure: # 配置重试enabled: true initial_interval: 10s # 初始间隔max_interval: 60s # 最大间隔max_elapsed_time: 10m # 最大时间default_labels_enabled: exporter: false processors: resource: attributes: - action: insert key: loki.resource.labels value: k8s.namespace.name,k8s.pod.name,k8s.container.name service: pipelines: logs: exporters: - loki processors: - memory_limiter - k8sattributes - resource - batch

次に、OpenTelemetry Collector DaemonSet を再更新します。

 $ helm upgrade --install opentelemetry-collector ./opentelemetry-collector -f otel-ds-values.yaml --namespace kube-otel --create-namespace

更新後、コマンド kubectl get cm -n opentelemetry-collector-agent -oyaml を使用して完全な構成情報を表示します。

 exporters: logging: loglevel: debug loki: endpoint: http://loki-gateway/loki/api/v1/push timeout: 10s # 超时时间read_buffer_size: 200 write_buffer_size: 100 retry_on_failure: # 配置重试enabled: true initial_interval: 10s # 初始间隔max_interval: 60s # 最大间隔max_elapsed_time: 10m # 最大时间default_labels_enabled: exporter: false extensions: health_check: {} memory_ballast: size_in_percentage: 40 processors: batch: {} k8sattributes: extract: metadata: - k8s.namespace.name - k8s.deployment.name - k8s.statefulset.name - k8s.daemonset.name - k8s.cronjob.name - k8s.job.name - k8s.node.name - k8s.pod.name - k8s.pod.uid - k8s.pod.start_time filter: node_from_env_var: K8S_NODE_NAME passthrough: false pod_association: - sources: - from: resource_attribute name: k8s.pod.ip - sources: - from: resource_attribute name: k8s.pod.uid - sources: - from: connection memory_limiter: check_interval: 5s limit_percentage: 80 spike_limit_percentage: 25 resource: attributes: - action: insert key: loki.resource.labels value: k8s.namespace.name,k8s.pod.name,k8s.container.name receivers: filelog: exclude: - /var/log/pods/kube-otel_opentelemetry-collector*_*/opentelemetry-collector/*.log include: - /var/log/pods/*/*/*.log include_file_name: false include_file_path: true operators: - id: get-format routes: - expr: body matches "^\\{" output: parser-docker - expr: body matches "^[^ Z]+ " output: parser-crio - expr: body matches "^[^ Z]+Z" output: parser-containerd type: router - id: parser-crio regex: ^(?P<time>[^ Z]+) (?P<stream>stdout|stderr) (?P<logtag>[^ ]*) ?(?P<log>.*)$ timestamp: layout: 2006-01-02T15:04:05.999999999Z07:00 layout_type: gotime parse_from: attributes.time type: regex_parser - combine_field: attributes.log combine_with: "" id: crio-recombine is_last_entry: attributes.logtag == 'F' max_log_size: 102400 output: extract_metadata_from_filepath source_identifier: attributes["log.file.path"] type: recombine - id: parser-containerd regex: ^(?P<time>[^ ^Z]+Z) (?P<stream>stdout|stderr) (?P<logtag>[^ ]*) ?(?P<log>.*)$ timestamp: layout: "%Y-%m-%dT%H:%M:%S.%LZ" parse_from: attributes.time type: regex_parser - combine_field: attributes.log combine_with: "" id: containerd-recombine is_last_entry: attributes.logtag == 'F' max_log_size: 102400 output: extract_metadata_from_filepath source_identifier: attributes["log.file.path"] type: recombine - id: parser-docker output: extract_metadata_from_filepath timestamp: layout: "%Y-%m-%dT%H:%M:%S.%LZ" parse_from: attributes.time type: json_parser - id: extract_metadata_from_filepath parse_from: attributes["log.file.path"] regex: ^.*\/(?P<namespace>[^_]+)_(?P<pod_name>[^_]+)_(?P<uid>[a-f0-9\-]+)\/(?P<container_name>[^\._]+)\/(?P<restart_count>\d+)\.log$ type: regex_parser - from: attributes.stream to: attributes["log.iostream"] type: move - from: attributes.container_name to: resource["k8s.container.name"] type: move - from: attributes.namespace to: resource["k8s.namespace.name"] type: move - from: attributes.pod_name to: resource["k8s.pod.name"] type: move - from: attributes.restart_count to: resource["k8s.container.restart_count"] type: move - from: attributes.uid to: resource["k8s.pod.uid"] type: move - from: attributes.log to: body type: move start_at: beginning otlp: protocols: grpc: endpoint: ${env:MY_POD_IP}:4317 http: endpoint: ${env:MY_POD_IP}:4318 service: extensions: - health_check - memory_ballast pipelines: logs: exporters: - loki processors: - memory_limiter - k8sattributes - resource - batch receivers: - otlp - filelog # 同样只保留了和logs 相关的配置,其他省略......

新しい loki エクスポーターと filelog シンクを追加しました。

ロキエクスポーター

このエクスポータは、HTTP 経由でデータを Loki にエクスポートします。エクスポーターは次のように構成できます。

  • エンドポイント: Loki の HTTP エンドポイント アドレス (例: http://loki:3100/loki/api/v1/push)。
  • default_labels_enabled (オプション): デフォルトのラベル (エクスポーター、ジョブ、インスタンス、レベル) のマッピングを無効にできます。 default_labels_enabled が省略されている場合は、デフォルトのラベルが追加されます。 default_labels_enabled でラベルの 1 つが省略されている場合は、そのラベルが追加されます。

すべてのデフォルト タグが無効になっており、追加のタグが追加されていない場合、ログ レコードを Loki に正常に書き込むには少なくとも 1 つのタグが存在する必要があるため、ログ エントリは破棄されます。メトリック otelcol_lokiexporter_send_failed_due_to_missing_labels は、ラベルが欠落しているためにドロップされたログ レコードの数を表示します。

Loki エクスポーターは、OTLP リソースとログ プロパティを Loki タグに変換し、インデックスを作成します。これを行うには、どのプロパティをラベルとして設定するかを指定する構成ヒントが必要です。ヒント自体はプロパティであり、Loki にエクスポートするときには無視されます。次の例では、属性プロセッサを使用して、Loki エクスポータに event.domain 属性をラベルとして設定するように要求し、リソース プロセッサを使用して、Loki エクスポータに service.name をラベルとして設定するように要求します。

 processors: attributes: actions: - action: insert key: loki.attribute.labels value: event.domain resource: attributes: - action: insert key: loki.resource.labels value: service.name

default_labels_enabled 設定で無効にしない限り、デフォルトのラベルは常に設定されます。

  • ジョブ=サービス.名前空間/サービス.名前
  • インスタンス=サービスインスタンスID
  • エクスポーター=OTLP
  • レベル=深刻度

service.name と service.namespace が存在する場合は、job=service.namespace/service.name を設定します。 service.name が存在し、service.namespace が存在しない場合は、job=service.name が設定されます。 service.name が存在せず、service.namespace が存在する場合、ジョブ ラベルは設定されません。 service.instance.id が存在する場合は、instance=service.instance.id を設定します。 service.instance.id が存在しない場合は、インスタンス ラベルは設定されません。

ここでの完全な構成は次のとおりです。

 loki: endpoint: http://loki-gateway/loki/api/v1/push timeout: 10s # 超时时间read_buffer_size: 200 write_buffer_size: 100 retry_on_failure: # 配置重试enabled: true initial_interval: 10s # 初始间隔max_interval: 60s # 最大间隔max_elapsed_time: 10m # 最大时间

タイムアウト、読み取りおよび書き込みバッファ サイズ、送信キュー、再試行などを構成しました。

read_buffer_size フィールドと write_buffer_size フィールドは、それぞれ OpenTelemetry エクスポーターの読み取りバッファと書き込みバッファのサイズを指定します。これらのバッファは、送信効率と信頼性を向上させるために、データを送信する前にキャッシュするために使用されます。

read_buffer_size フィールドは、エクスポーターがデータ ソースからデータを読み取るときに使用するバッファー サイズを指定します。データ ソースによって生成されたデータの量がバッファーのサイズを超える場合、エクスポーターはデータをバッチで読み取り、バッファーがいっぱいになるか、データ ソースにデータがなくなるまでバッファーにキャッシュします。

write_buffer_size フィールドは、エクスポータがメトリック データをターゲットに書き込むときに使用するバッファ サイズを指定します。エクスポータによって生成されたデータの量がバッファのサイズを超える場合、エクスポータはデータをバッチでターゲットに書き込み、バッファがいっぱいになるかターゲットが使用できなくなるまで、そのデータをバッファにキャッシュします。

これらのバッファのサイズを構成することで、OpenTelemetry エクスポーターのパフォーマンスと信頼性を制御できます。データ ソースが大量のデータを生成する場合は、read_buffer_size と write_buffer_size を増やして、エクスポーターのスループットと効率を向上させることができます。ターゲットがあまり安定していない場合やネットワークの信頼性があまり高くない場合は、write_buffer_size を減らしてデータ損失のリスクを軽減できます。

さらに、k8s.namespace.name、k8s.pod.name、k8s.container.name を Loki ラベルに変換して、Loki でインデックスを作成できるようにするリソース プロセッサが追加されました。

 resource: attributes: - action: insert key: loki.resource.labels value: k8s.namespace.name,k8s.pod.name,k8s.container.name

ファイルログレシーバー

このレシーバーは、ファイルからログ データを収集して解析するために使用されます。指定されたファイルからログ データを読み取り、OpenTelemetry Collector に送信します。

ここでは受信機を次のように設定します。

 filelog: exclude: - /var/log/pods/kube-otel_opentelemetry-collector*_*/opentelemetry-collector/*.log include: - /var/log/pods/*/*/*.log include_file_name: false include_file_path: true operators: - id: get-format routes: - expr: body matches "^\\{" output: parser-docker - expr: body matches "^[^ Z]+ " output: parser-crio - expr: body matches "^[^ Z]+Z" output: parser-containerd type: router - id: parser-crio regex: ^(?P<time>[^ Z]+) (?P<stream>stdout|stderr) (?P<logtag>[^ ]*) ?(?P<log>.*)$ timestamp: layout: 2006-01-02T15:04:05.999999999Z07:00 layout_type: gotime parse_from: attributes.time type: regex_parser - combine_field: attributes.log combine_with: "" id: crio-recombine is_last_entry: attributes.logtag == 'F' max_log_size: 102400 output: extract_metadata_from_filepath source_identifier: attributes["log.file.path"] type: recombine - id: parser-containerd regex: ^(?P<time>[^ ^Z]+Z) (?P<stream>stdout|stderr) (?P<logtag>[^ ]*) ?(?P<log>.*)$ timestamp: layout: "%Y-%m-%dT%H:%M:%S.%LZ" parse_from: attributes.time type: regex_parser - combine_field: attributes.log combine_with: "" id: containerd-recombine is_last_entry: attributes.logtag == 'F' max_log_size: 102400 output: extract_metadata_from_filepath source_identifier: attributes["log.file.path"] type: recombine - id: parser-docker output: extract_metadata_from_filepath timestamp: layout: "%Y-%m-%dT%H:%M:%S.%LZ" parse_from: attributes.time type: json_parser - id: extract_metadata_from_filepath parse_from: attributes["log.file.path"] regex: ^.*\/(?P<namespace>[^_]+)_(?P<pod_name>[^_]+)_(?P<uid>[a-f0-9\-]+)\/(?P<container_name>[^\._]+)\/(?P<restart_count>\d+)\.log$ type: regex_parser - from: attributes.stream to: attributes["log.iostream"] type: move - from: attributes.container_name to: resource["k8s.container.name"] type: move - from: attributes.namespace to: resource["k8s.namespace.name"] type: move - from: attributes.pod_name to: resource["k8s.pod.name"] type: move - from: attributes.restart_count to: resource["k8s.container.restart_count"] type: move - from: attributes.uid to: resource["k8s.pod.uid"] type: move - from: attributes.log to: body type: move start_at: beginning

構成が非常に長いことがわかります。まず、収集する必要のないログ ファイルを除外し、次に include を使用して、収集する必要があるログ ファイルを指定します。 Kubernetes クラスターは Containerd コンテナ ランタイムに基づいているため、収集されるログ ディレクトリは /var/log/pods/*/*/*.log です。次に、include_file_path を使用して、ファイル パスをプロパティ log.file.path として追加するかどうかを指定します。また、include_file_name を使用して、ファイル名をプロパティ log.file.name として追加するかどうかを指定します。

start_at は、起動時にログの読み取りを開始するファイル内の位置を示します。オプションは開始または終了で、デフォルトは終了です。

次に、ログ ファイルの処理方法を指定するために使用される最も重要な演算子属性があります。演算子は、ログ処理の最も基本的な単位です。各演算子は、ファイルから行を読み取ったり、フィールドから JSON を解析したりするなど、単一の責任を果たします。これらの演算子は連結されてパイプラインを形成し、目的の結果を実現します。

たとえば、ユーザーは file_input 演算子を使用してファイルからログ行を読み取ることができます。この操作の結果を regex_parser 演算子に送信して、正規表現に基づいてフィールドを作成できます。最後に、これらの結果を file_output オペレーターに送信して、ログをディスク上のファイルに書き込むことができます。

ここではまずルーター オペレーターを設定します。

 id: get-format routes: - expr: body matches "^\\{" output: parser-docker - expr: body matches "^[^ Z]+ " output: parser-crio - expr: body matches "^[^ Z]+Z" output: parser-containerd type: router

このオペレーターは、ログの内容に基づいてログを動的にルーティングすることを可能にします。この場合、containerd コンテナを実行すると、生成されたログ データは本文に「^[^ Z]+Z」が一致し、そのデータが parser-containerd オペレータにルーティングされます。

 id: parser-containerd regex: ^(?P<time>[^ ^Z]+Z) (?P<stream>stdout|stderr) (?P<logtag>[^ ]*) ?(?P<log>.*)$ timestamp: layout: "%Y-%m-%dT%H:%M:%S.%LZ" parse_from: attributes.time type: regex_parser

parser-containerd は、指定された正規表現を使用して以前にルーティングされたログ データを解析し、結果を time、stream、logtag、log などの属性に保存し、タイムスタンプをフォーマットする regex_parser 演算子です。

次に、連続するログは、再結合演算子によって 1 つのログに結合されます。

 combine_field: attributes.log combine_with: "" id: containerd-recombine is_last_entry: attributes.logtag == 'F' max_log_size: 102400 output: extract_metadata_from_filepath source_identifier: attributes["log.file.path"] type: recombine

上記の処理の後、extract_metadata_from_filepath 演算子に入ります。この演算子は、正規表現を使用してファイル パスからメタデータを抽出し、それを namespace、pod_name、uid、container_name、restart_count などの属性に保存します。

 id: extract_metadata_from_filepath parse_from: attributes["log.file.path"] regex: ^.*\/(?P<namespace>[^_]+)_(?P<pod_name>[^_]+)_(?P<uid>[a-f0-9\-]+)\/(?P<container_name>[^\._]+)\/(?P<restart_count>\d+)\.log$ type: regex_parser

次のステップは、move 演算子を使用して、フィールドをある場所から別の場所に移動 (または名前変更) することです。

 - from: attributes.stream to: attributes["log.iostream"] type: move - from: attributes.container_name to: resource["k8s.container.name"] type: move - from: attributes.namespace to: resource["k8s.namespace.name"] type: move - from: attributes.pod_name to: resource["k8s.pod.name"] type: move - from: attributes.restart_count to: resource["k8s.container.restart_count"] type: move - from: attributes.uid to: resource["k8s.pod.uid"] type: move - from: attributes.log to: body type: move

最後に、Loki データ ソースを Grafana に追加します。

Loki データソース

次に、エクスプローラー ページで Loki データ ソースに切り替えて、Loki のログ データを表示します。

ロキログ

k8sobjectシンクを有効にする

同様に、ゲートウェイ モードのコレクターの場合、k8sobject レシーバーを有効にして Kubernetes イベント データを収集し、otel-collector-deploy-values.yaml ファイルを更新することもできます。

 # otel-collector-deploy-values.yaml mode: deployment # 我们只需要一个收集器- 多了就会产生重复数据replicaCount: 1 presets: clusterMetrics: enabled: true kubernetesEvents: enabled: true config: exporters: loki: endpoint: http://loki-gateway/loki/api/v1/push timeout: 10s # 超时时间read_buffer_size: 200 write_buffer_size: 100 retry_on_failure: # 配置重试enabled: true initial_interval: 10s # 初始间隔max_interval: 60s # 最大间隔max_elapsed_time: 10m # 最大时间service: pipelines: logs: exporters: - loki

次に、OpenTelemetry Collector デプロイメントを再更新します。

 $ helm upgrade --install opentelemetry-collector-cluster ./opentelemetry-collector -f otel-collector-deploy-values.yaml --namespace kube-otel --create-namespace

ここでは、kubernetesEvents プリセットを有効にしており、対応する構成は次のようになります。

 k8sobjects: objects: - group: events.k8s.io mode: watch name: events

k8sobjects レシーバーを使用して、Kubernetes API サーバー内のオブジェクトをプルまたは監視できます。ここでは、グループ、モード、名前を使用して、プルする Kubernetes イベント オブジェクトを指定します。

最後に、Loki で対応するイベント ログ データを見つけることもできます。

<<:  クラウド ネイティブ アーキテクチャ: クラウドで回復力のあるアプリケーションを構築する

>>:  Kubernetes のエラスティック スケーリングの探索: KEDA を使用したイベント駆動型オートスケーラーの実装

推薦する

小さくて美しい O2O ビジネス事例 8 つ

国内のインターネットは王子たちの戦いのようで、BAT は世界を 3 つに分割し、インターネットのあら...

皆様、中秋節おめでとうございます!

中秋節は家族が集まるお祭りでもあります。お祭り期間中に訪れる Console Cat の熱狂的なファ...

Baidu が次にどのような改善を行うかを予測する

検索エンジンは互いに学び合いながら改善していきます。例えば、マクドナルドやKFCの店長は、自分の店の...

Baidu ウェブマスター プラットフォームの苦情ガイドにより苦情処理の効率が向上

8月6日、百度ウェブマスタープラットフォームの公式Weiboアカウントは声明を投稿した。「百度ウェブ...

3つのハイライトのレビュー:ホワイトホエール海外起業家キャンプの第2フェーズが成功裏に終了しました。

10月29日、4日間にわたるベルーガ海外起業家キャンプ第2フェーズ - インドとインドネシア向け海外...

OpenStack Foundationの推進により、OpenStack Infrastructure Summitが中国で開催される。

[51CTO.com からのオリジナル記事] OpenStack Foundation は 2012...

特別オファー: budgetvm-E3-1270V3/4X2T ハードディスク (raid10)/253IP/4 コンピュータルーム/Alipay

budgetvm の特別版サーバーは、非常にコスト効率が高いようです。ここで、この budgetvm...

ネットワークマーケティングで良い仕事をするための基本的なポイントについて簡単に説明します

オンラインマーケティングの発展と成長に伴い、従来のマーケティング手法は衰退し始めており、個人も企業も...

domain.com、すべてのドメイン名が30%オフ、各ドメイン名は最大5年間登録可能

老舗ドメイン名販売業者のdomain.comがプロモーションを実施しています。すべてのドメイン名が3...

Ele.me: システムは5億ドルの価値があるのでしょうか? このコンテストはケータリングサプライチェーンの変革に関するものである

O2Oは、オフラインからオンラインへの単純な転送ではなく、完全なサービスチェーンです。 2週間前、D...

マーケティングプロモーション:ゲーミフィケーションマーケティングを実装するための5つのステップ!

情報爆発の時代に人々の注目を集めたいなら、あなたの商品は興味深く、特別なものでなければなりません。こ...

【最新編集】信頼できる米国cn2 gia vpsのおすすめ、米国vpsレンタル業者のおすすめ!

公式サイト: https://bwh89.net 2004年に設立されたカナダの会社で、ハイエンドで...

公式アカウントのコンテンツをより強力にするには?

公開アカウントであっても、親アカウントであっても、コンテンツが王様であるというルールは依然として適用...

Baidu Bearのエコシステムパートナーは15万社を超え、インデックスされたデータソースは18億を超える

5月22日、2018年百度アライアンスエコシステムサミットが海口市で開催されました。同日午後に開催さ...

ウェブサイト最適化の効果を高める方法

ウェブサイトの最適化手法はあまりにも平凡、言い換えれば普通すぎる。その結果、維持されているウェブサイ...