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 を使用したイベント駆動型オートスケーラーの実装

推薦する

安定性とウェブサイトの最適化の関係について

検索エンジンの観点から見ると、ウェブサイトの安定性は非常に重要です。したがって、Webサイトを構築す...

ブログマーケティングを通じて口コミを構築する方法についての母子企業からの3つの啓示

優れたブログは、企業にとって独立した販売チャネルとなり、顧客関係を維持するためのプラットフォームとな...

今年の新バージョン(編集済み):最も安いVPSリスト、海外の安いVPSの推奨事項、Alipay支払いをサポート

安価な VPS は常に話題になっています。私たちは常に、海外の安価な VPS、米国の安価な VPS、...

百度のアルゴリズムは「無期限に変更」ウェブマスターの対応が鍵

数日前、Baidu 検索で突然、一時的なエラーが発生しました。このエラーは長くは続きませんでしたが、...

初日興行収入3億突破! 「生き残るために死ぬ」の背後にあるコミュニケーションの秘密の解釈

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています今、劇場で...

分散KV-1スタンドアロンKVの実装

[[437220]]この記事はWeChatの公開アカウント「roseduanの執筆場所」から転載した...

Linode ブラックフライデーイベント、25 ドルをプレゼント!

Linode も毎年恒例のブラックフライデーに参加しています。Linode がユーザーに特典を提供す...

6年間の技術革新:アリババのグローバル化とコンプライアンスへの挑戦と探求

グローバル化されたテクノロジーは、グローバル化されたビジネスに根ざしています。 5段階の進化を経て、...

KVMの概念、アーキテクチャ、機能、一般的なツール、仮想化の展開に関する詳細な説明

[[326014]]概要一般的に、仮想化には 2 つのタイプがあります。ハイパーバイザーはホストのロ...

Baidu による旅行ウェブサイトのプロモーションに関する経験と洞察

2012年に旅行会社にSEOスーパーバイザーとして入社してから1年以上が経ちました。いろいろな思いが...

PolarDB クラウドネイティブ データベースは、過去 5 年間でどのようにパフォーマンスが最適化されてきましたか?

著者 |ジェユ、バオティアオクラウド データベースは、コンピューティングとストレージを分離し、コンピ...

SEOに適したコンテンツ表示

検索エンジンのランキングに影響を与える要因は数多くあります。今日は主に、優れたコンテンツ構築が検索エ...

HostSolutions: 月額 1.56 ドル、KVM/512M メモリ/1T ハードディスク/5T トラフィック、著作権侵害苦情、DDOS の高度な防御保護

ルーマニアのホスティングプロバイダー HostSolutions は、ハロウィーンの前に大規模なプロ...

人民の声を含む107の違法ウェブサイトが法律に従って閉鎖された

北京ニュースの記者は、中国サイバースペース管理局から、全国で行われているインターネットニュースと情報...