Isovalent Enterprise Platform と Splunk Observability Cloud の統合

105 minutes   Author Alec Chamberlain

このワークショップでは、Isovalent Enterprise Platform と Splunk Observability Cloud の統合を実演し、eBPFテクノロジーを使用してKubernetesのネットワーキング、セキュリティ、ランタイム動作の包括的な可視性を提供する方法を説明します。

学習内容

このワークショップを完了すると、以下のことができるようになります:

  • ENIモードでCiliumをCNIとして使用するAmazon EKSをデプロイする
  • L7可視性を備えたネットワークオブザーバビリティのためのHubbleを設定する
  • ランタイムセキュリティ監視のためのTetragonをインストールする
  • OpenTelemetryを使用してeBPFベースのメトリクスをSplunk Observability Cloudと統合する
  • 統合ダッシュボードでネットワークフロー、セキュリティイベント、インフラストラクチャメトリクスを監視する
  • eBPFによるオブザーバビリティとkube-proxyの置き換えを理解する

セクション

ヒント

この統合は、Linuxカーネル内で直接、高性能で低オーバーヘッドのオブザーバビリティを実現するためにeBPF(Extended Berkeley Packet Filter)を活用しています。

前提条件

  • 適切な認証情報で設定されたAWS CLI
  • kubectl、eksctl、Helm 3.xがインストールされていること
  • EKSクラスター、VPC、EC2インスタンスを作成する権限を持つAWSアカウント
  • アクセストークンを持つSplunk Observability Cloudアカウント
  • 完全なセットアップに約90分

統合のメリット

Isovalent Enterprise PlatformをSplunk Observability Cloudに接続することで、以下のメリットが得られます:

  • 🔍 深い可視性: ネットワークフロー、L7プロトコル(HTTP、DNS、gRPC)、ランタイムセキュリティイベント
  • 🚀 高パフォーマンス: 最小限のオーバーヘッドでeBPFベースのオブザーバビリティを実現
  • 🔐 セキュリティインサイト: プロセス監視、システムコールトレーシング、ネットワークポリシーの適用
  • 📊 統合ダッシュボード: Cilium、Hubble、TetragonのメトリクスをインフラストラクチャおよびAPMデータと並べて表示
  • 効率的なネットワーキング: kube-proxyの置き換えとENIモードによるネイティブVPCネットワーキング

ソースリポジトリ

このワークショップで参照されるすべての設定ファイル、Helm values、ダッシュボードJSONファイルは、以下のリポジトリで入手できます:

  • isovalent_splunk_o11y — Helm values、OTel Collector設定、SplunkダッシュボードJSONファイル、および完全な統合ガイド
  • isovalent-demo-jobs-app — デモシナリオで使用されるjobs-app Helm chart(エラーインジェクションと修復スクリプトを含む)
  • ステップ 1: Cilium Enterprise の設定 cilium-enterprise-values.yaml という名前のファイルを作成します。 を前のステップで取得したエンドポイントに置き換えてください(https:// プレフィックスは除きます)。

    Enable/disable debug logging debug: enabled: false verbose: ~ # Configure unique cluster name & ID cluster: name: isovalent-demo id: 0 # Configure ENI specifics eni: enabled: true updateEC2AdapterLimitViaAPI: true # Dynamically fetch ENI limits from EC2 API awsEnablePrefixDelegation: true # Assign /28 CIDR blocks per ENI (16 IPs) instead of individual IPs enableIPv4Masquerade: false # Pods use their real VPC IPs — no SNAT needed in ENI mode loadBalancer: serviceTopology: true # Prefer backends in the same AZ to reduce cross-AZ traffic costs ipam: mode: eni routingMode: native # No overlay tunnels — traffic routes natively through VPC # BPF / KubeProxyReplacement # Cilium replaces kube-proxy entirely with eBPF programs in the kernel. # This requires a direct path to the API server, hence k8sServiceHost. kubeProxyReplacement: “true” k8sServiceHost: k8sServicePort: 443 # TLS for internal Cilium communication tls: ca: certValidityDuration: 3650 # 10 years for the CA cert # Hubble: network observability built on top of Cilium’s eBPF datapath hubble: enabled: true metrics: enableOpenMetrics: true # Use OpenMetrics format for better Prometheus compatibility enabled: # DNS: query/response tracking with namespace-level label context - dns:labelsContext=source_namespace,destination_namespace # Drop: packet drop reasons (policy deny, invalid, etc.) per namespace - drop:labelsContext=source_namespace,destination_namespace # TCP: connection state tracking (SYN, FIN, RST) per namespace - tcp:labelsContext=source_namespace,destination_namespace # Port distribution: which destination ports are being used - port-distribution:labelsContext=source_namespace,destination_namespace # ICMP: ping/traceroute visibility with workload identity context - icmp:labelsContext=source_namespace,destination_namespace;sourceContext=workload-name|reserved-identity;destinationContext=workload-name|reserved-identity # Flow: per-workload flow counters (forwarded, dropped, redirected) - flow:sourceContext=workload-name|reserved-identity;destinationContext=workload-name|reserved-identity # HTTP L7: request/response metrics with full workload context and exemplars for trace correlation - “httpV2:exemplars=true;labelsContext=source_ip,source_namespace,source_workload,destination_namespace,destination_workload,traffic_direction;sourceContext=workload-name|reserved-identity;destinationContext=workload-name|reserved-identity” # Policy: network policy verdict tracking (allowed/denied) per workload - “policy:sourceContext=app|workload-name|pod|reserved-identity;destinationContext=app|workload-name|pod|dns|reserved-identity;labelsContext=source_namespace,destination_namespace” # Flow export: enables Hubble to export flow records to Timescape for historical storage - flow_export serviceMonitor: enabled: true # Creates a Prometheus ServiceMonitor for auto-discovery tls: enabled: true auto: enabled: true method: cronJob # Automatically rotate Hubble TLS certs on a schedule certValidityDuration: 1095 # 3 years per cert rotation relay: enabled: true # Hubble Relay aggregates flows from all nodes cluster-wide tls: server: enabled: true prometheus: enabled: true serviceMonitor: enabled: true timescape: enabled: true # Stores historical flow data for time-travel debugging # Cilium Operator: cluster-wide identity and endpoint management operator: prometheus: enabled: true serviceMonitor: enabled: true # Cilium Agent: per-node eBPF datapath metrics prometheus: enabled: true serviceMonitor: enabled: true # Cilium Envoy: L7 proxy metrics (HTTP, gRPC) envoy: prometheus: enabled: true serviceMonitor: enabled: true # Enable the Cilium agent to hand off DNS proxy responsibilities to the # external DNS Proxy HA deployment, so policies keep working during upgrades extraConfig: external-dns-proxy: “true” # Enterprise feature gates — these must be explicitly approved enterprise: featureGate: approved: - DNSProxyHA # High-availability DNS proxy (installed separately) - HubbleTimescape # Historical flow storage via Timescape ラベルコンテキストが重要な理由 各Hubbleメトリクスの labelsContext および sourceContext/destinationContext パラメータは、メトリクスをどのディメンションで分割するかを制御します。labelsContext=source_namespace,destination_namespace を設定すると、すべてのメトリクスにこれら2つのラベルが付与され、カーディナリティの爆発を起こすことなくSplunkでnamespaceによるフィルタリングが可能になります。workload-name|reserved-identity のフォールバックチェーンは、利用可能な場合はワークロード名を使用し、利用できない場合はセキュリティIDにフォールバックすることを意味します。

  • 概要 Splunk OpenTelemetry Collectorは、Prometheusレシーバーを使用してすべてのIsovalentコンポーネントからメトリクスをスクレイプします。各コンポーネントは異なるポートでメトリクスを公開しており、CiliumとHubbleは同じPodを共有しています(ポートが異なるだけです)。そのため、Podアノテーションに依存するのではなく、各コンポーネントに対して個別のレシーバーを設定します。 コンポーネント ポート 提供する情報 Cilium Agent 9962 eBPF データパス、ポリシー適用、IPAM、BPF マップ統計 Cilium Envoy 9964 L7 プロキシメトリクス(HTTP、gRPC) Cilium Operator 9963 クラスター全体のアイデンティティとエンドポイント管理 Hubble 9965 ネットワークフロー、DNS、HTTP L7、TCP フラグ、ポリシー判定 Tetragon 2112 ランタイムセキュリティ、ソケット統計、ネットワークフローイベント ステップ 1: 設定ファイルの作成 splunk-otel-collector-values.yaml という名前のファイルを作成します。認証情報のプレースホルダーを実際の値に置き換えてください。 terminationGracePeriodSeconds: 30 agent: config: extensions: # k8s_observer watches the Kubernetes API for pod and port changes. # This enables automatic service discovery without static endpoint lists. k8s_observer: auth_type: serviceAccount observe_pods: true receivers: kubeletstats: collection_interval: 30s insecure_skip_verify: true # Cilium Agent (port 9962) and Hubble (port 9965) both run in the # same DaemonSet pod, identified by label k8s-app=cilium. # We use two separate scrape jobs because they’re on different ports. prometheus/isovalent_cilium: config: scrape_configs: - job_name: ‘cilium_metrics_9962’ scrape_interval: 30s metrics_path: /metrics kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_label_k8s_app] action: keep regex: cilium - source_labels: [__meta_kubernetes_pod_ip] target_label: address replacement: ${__meta_kubernetes_pod_ip}:9962 - target_label: job replacement: ‘cilium_metrics_9962’ - job_name: ‘hubble_metrics_9965’ scrape_interval: 30s metrics_path: /metrics kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_label_k8s_app] action: keep regex: cilium - source_labels: [__meta_kubernetes_pod_ip] target_label: address replacement: ${__meta_kubernetes_pod_ip}:9965 - target_label: job replacement: ‘hubble_metrics_9965’ # Cilium Envoy uses a different pod label (k8s-app=cilium-envoy) prometheus/isovalent_envoy: config: scrape_configs: - job_name: ’envoy_metrics_9964’ scrape_interval: 30s metrics_path: /metrics kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_label_k8s_app] action: keep regex: cilium-envoy - source_labels: [__meta_kubernetes_pod_ip] target_label: address replacement: ${__meta_kubernetes_pod_ip}:9964 - target_label: job replacement: ‘cilium_metrics_9964’ # Cilium Operator is a Deployment (not DaemonSet), identified by io.cilium.app=operator prometheus/isovalent_operator: config: scrape_configs: - job_name: ‘cilium_operator_metrics_9963’ scrape_interval: 30s metrics_path: /metrics kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_label_io_cilium_app] action: keep regex: operator - target_label: job replacement: ‘cilium_metrics_9963’ # Tetragon is identified by app.kubernetes.io/name=tetragon prometheus/isovalent_tetragon: config: scrape_configs: - job_name: ’tetragon_metrics_2112’ scrape_interval: 30s metrics_path: /metrics kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_label_app_kubernetes_io_name] action: keep regex: tetragon - source_labels: [__meta_kubernetes_pod_ip] target_label: address replacement: ${__meta_kubernetes_pod_ip}:2112 - target_label: job replacement: ’tetragon_metrics_2112’ processors: # Strict allowlist filter: only forward metrics we’ve explicitly named. # Without this, Cilium and Tetragon can generate thousands of metric series # and overwhelm Splunk Observability Cloud with cardinality. filter/includemetrics: metrics: include: match_type: strict metric_names: # — Kubernetes base metrics — - container.cpu.usage - container.memory.rss - k8s.container.restarts - k8s.pod.phase - node_namespace_pod_container - tcp.resets - tcp.syn_timeouts # — Cilium Agent metrics — # API rate limiting — detect if the agent is being throttled - cilium_api_limiter_processed_requests_total - cilium_api_limiter_processing_duration_seconds # BPF map utilization — alerts when eBPF maps are near capacity - cilium_bpf_map_ops_total # Controller health — tracks background reconciliation tasks - cilium_controllers_group_runs_total - cilium_controllers_runs_total # Endpoint state — how many pods are in each lifecycle state - cilium_endpoint_state # Agent error/warning counts — early warning for problems - cilium_errors_warnings_total # IP address allocation tracking - cilium_ip_addresses - cilium_ipam_capacity # Kubernetes event processing rate - cilium_kubernetes_events_total # L7 policy enforcement (HTTP, DNS, Kafka) - cilium_policy_l7_total # DNS proxy latency histogram — key metric for catching DNS saturation - cilium_proxy_upstream_reply_seconds_bucket # — Hubble metrics — # DNS query and response counts — primary indicator in the demo scenario - hubble_dns_queries_total - hubble_dns_responses_total # Packet drops by reason (policy_denied, invalid, TTL_exceeded, etc.) - hubble_drop_total # Total flows processed — overall network activity volume - hubble_flows_processed_total # HTTP request latency histogram and total count - hubble_http_request_duration_seconds_bucket - hubble_http_requests_total # ICMP traffic tracking - hubble_icmp_total # Policy verdict counts (forwarded vs. dropped by policy) - hubble_policy_verdicts_total # TCP flag tracking (SYN, FIN, RST) — connection lifecycle visibility - hubble_tcp_flags_total # — Tetragon metrics — # Total eBPF events processed - tetragon_events_total # DNS cache health - tetragon_dns_cache_evictions_total - tetragon_dns_cache_misses_total - tetragon_dns_total # HTTP response tracking with latency - tetragon_http_response_total - tetragon_http_stats_latency_bucket - tetragon_http_stats_latency_count - tetragon_http_stats_latency_sum # Layer3 errors - tetragon_layer3_event_errors_total # TCP socket statistics — per-connection RTT, retransmits, byte/segment counts # These power the latency and throughput views in Network Explorer - tetragon_socket_stats_retransmitsegs_total - tetragon_socket_stats_rxsegs_total - tetragon_socket_stats_srtt_count - tetragon_socket_stats_srtt_sum - tetragon_socket_stats_txbytes_total - tetragon_socket_stats_txsegs_total - tetragon_socket_stats_rxbytes_total # UDP statistics - tetragon_socket_stats_udp_retrieve_total - tetragon_socket_stats_udp_txbytes_total - tetragon_socket_stats_udp_txsegs_total - tetragon_socket_stats_udp_rxbytes_total # Network flow events (connect, close, send, receive) - tetragon_network_connect_total - tetragon_network_close_total - tetragon_network_send_total - tetragon_network_receive_total resourcedetection: detectors: [system] system: hostname_sources: [os] service: pipelines: metrics: receivers: - prometheus/isovalent_cilium - prometheus/isovalent_envoy - prometheus/isovalent_operator - prometheus/isovalent_tetragon - hostmetrics - kubeletstats - otlp processors: - filter/includemetrics - resourcedetection autodetect: prometheus: true clusterName: isovalent-demo splunkObservability: accessToken: realm: # e.g. us1, us2, eu0 profilingEnabled: true cloudProvider: aws distribution: eks environment: isovalent-demo # Gateway mode runs a central collector deployment that receives from all agents. # Agents send to the gateway, which handles batching and export to Splunk. # This reduces the number of direct connections to Splunk’s ingest endpoint. gateway: enabled: true resources: requests: cpu: 250m memory: 512Mi limits: cpu: 1 memory: 1Gi # certmanager handles mTLS between the OTel Collector agent and gateway certmanager: enabled: true 重要: 以下を置き換えてください:
  • このデモで示すこと このデモは、すべての運用チームやプラットフォームチームが経験したことのあるストーリーを語ります。何かが壊れていて、ユーザーが不満を訴えていて、どこから始めればよいかわからない状況です。調査は通常の最初のステップを経由します — APMは問題なさそう、インフラストラクチャも問題なさそう — そしてネットワーク層へとピボットします。そこでIsovalentのHubbleオブザーバビリティがSplunkに流れ込み、本当の問題を明らかにします。それは他のすべてのツールからは完全に見えなかったDNS過負荷です。 アプリケーションは jobs-app で、tenant-jobs namespaceで実行されるシミュレートされたマルチサービスの採用プラットフォームです。フロントエンド(recruiter、jobposting)、中央API(coreapi)、バックグラウンドデータパイプライン(Kafka + resumes + loader)、および定期的にインターネットへHTTP呼び出しを行う crawler サービスがあります。このcrawlerがこのストーリーの悪役になります。 重要なポイント APMとインフラストラクチャのメトリクスは正常に見えます。根本原因であるDNS過負荷は、アプリケーション層より下に存在するため、SplunkのIsovalent Hubbleダッシュボードを通じてのみ見ることができます。 開始前の準備 これは誰もいない状態で行ってください。デモが始まるときには、クリーンで正常なダッシュボードの前に座っていたいものです — 人々が見ている中でkubectlをいじっているのではなく。 Jobs App のデプロイ まだ行っていない場合は、isovalent-demo-jobs-app リポジトリからjobs-app Helm chartをデプロイします。 helm dependency build . helm upgrade –install jobs-app . –namespace tenant-jobs –create-namespace すべてが実行中であることを確認 デモ中に驚かないよう、これらのチェックを実行します。
Last Modified 2026/03/30

Isovalent Splunk Observability 統合のサブセクション

Cilium のインストール

ステップ 1: Cilium Enterprise の設定

cilium-enterprise-values.yaml という名前のファイルを作成します。<YOUR-EKS-API-SERVER-ENDPOINT> を前のステップで取得したエンドポイントに置き換えてください(https:// プレフィックスは除きます)。

# Enable/disable debug logging
debug:
  enabled: false
  verbose: ~

# Configure unique cluster name & ID
cluster:
  name: isovalent-demo
  id: 0

# Configure ENI specifics
eni:
  enabled: true
  updateEC2AdapterLimitViaAPI: true   # Dynamically fetch ENI limits from EC2 API
  awsEnablePrefixDelegation: true     # Assign /28 CIDR blocks per ENI (16 IPs) instead of individual IPs

enableIPv4Masquerade: false           # Pods use their real VPC IPs — no SNAT needed in ENI mode
loadBalancer:
  serviceTopology: true               # Prefer backends in the same AZ to reduce cross-AZ traffic costs

ipam:
  mode: eni

routingMode: native                   # No overlay tunnels — traffic routes natively through VPC

# BPF / KubeProxyReplacement
# Cilium replaces kube-proxy entirely with eBPF programs in the kernel.
# This requires a direct path to the API server, hence k8sServiceHost.
kubeProxyReplacement: "true"
k8sServiceHost: <YOUR-EKS-API-SERVER-ENDPOINT>
k8sServicePort: 443

# TLS for internal Cilium communication
tls:
  ca:
    certValidityDuration: 3650        # 10 years for the CA cert

# Hubble: network observability built on top of Cilium's eBPF datapath
hubble:
  enabled: true
  metrics:
    enableOpenMetrics: true           # Use OpenMetrics format for better Prometheus compatibility
    enabled:
      # DNS: query/response tracking with namespace-level label context
      - dns:labelsContext=source_namespace,destination_namespace
      # Drop: packet drop reasons (policy deny, invalid, etc.) per namespace
      - drop:labelsContext=source_namespace,destination_namespace
      # TCP: connection state tracking (SYN, FIN, RST) per namespace
      - tcp:labelsContext=source_namespace,destination_namespace
      # Port distribution: which destination ports are being used
      - port-distribution:labelsContext=source_namespace,destination_namespace
      # ICMP: ping/traceroute visibility with workload identity context
      - icmp:labelsContext=source_namespace,destination_namespace;sourceContext=workload-name|reserved-identity;destinationContext=workload-name|reserved-identity
      # Flow: per-workload flow counters (forwarded, dropped, redirected)
      - flow:sourceContext=workload-name|reserved-identity;destinationContext=workload-name|reserved-identity
      # HTTP L7: request/response metrics with full workload context and exemplars for trace correlation
      - "httpV2:exemplars=true;labelsContext=source_ip,source_namespace,source_workload,destination_namespace,destination_workload,traffic_direction;sourceContext=workload-name|reserved-identity;destinationContext=workload-name|reserved-identity"
      # Policy: network policy verdict tracking (allowed/denied) per workload
      - "policy:sourceContext=app|workload-name|pod|reserved-identity;destinationContext=app|workload-name|pod|dns|reserved-identity;labelsContext=source_namespace,destination_namespace"
      # Flow export: enables Hubble to export flow records to Timescape for historical storage
      - flow_export
    serviceMonitor:
      enabled: true                   # Creates a Prometheus ServiceMonitor for auto-discovery
  tls:
    enabled: true
    auto:
      enabled: true
      method: cronJob                 # Automatically rotate Hubble TLS certs on a schedule
      certValidityDuration: 1095      # 3 years per cert rotation
  relay:
    enabled: true                     # Hubble Relay aggregates flows from all nodes cluster-wide
    tls:
      server:
        enabled: true
    prometheus:
      enabled: true
      serviceMonitor:
        enabled: true
  timescape:
    enabled: true                     # Stores historical flow data for time-travel debugging

# Cilium Operator: cluster-wide identity and endpoint management
operator:
  prometheus:
    enabled: true
    serviceMonitor:
      enabled: true

# Cilium Agent: per-node eBPF datapath metrics
prometheus:
  enabled: true
  serviceMonitor:
    enabled: true

# Cilium Envoy: L7 proxy metrics (HTTP, gRPC)
envoy:
  prometheus:
    enabled: true
    serviceMonitor:
      enabled: true

# Enable the Cilium agent to hand off DNS proxy responsibilities to the
# external DNS Proxy HA deployment, so policies keep working during upgrades
extraConfig:
  external-dns-proxy: "true"

# Enterprise feature gates — these must be explicitly approved
enterprise:
  featureGate:
    approved:
      - DNSProxyHA          # High-availability DNS proxy (installed separately)
      - HubbleTimescape     # Historical flow storage via Timescape
ラベルコンテキストが重要な理由

各Hubbleメトリクスの labelsContext および sourceContext/destinationContext パラメータは、メトリクスをどのディメンションで分割するかを制御します。labelsContext=source_namespace,destination_namespace を設定すると、すべてのメトリクスにこれら2つのラベルが付与され、カーディナリティの爆発を起こすことなくSplunkでnamespaceによるフィルタリングが可能になります。workload-name|reserved-identity のフォールバックチェーンは、利用可能な場合はワークロード名を使用し、利用できない場合はセキュリティIDにフォールバックすることを意味します。

ステップ 2: Cilium Enterprise のインストール

新しいノードがEKSクラスターに参加すると、そのノードのkubeletはすぐにCNIプラグインを探してネットワーキングをセットアップします。/etc/cni/net.d/ に存在するCNI設定を読み取り、それを使用してノードを初期化します。ノードグループを先に作成すると、AWS VPC CNI が最初に到達します — そして一度ノードが特定のCNIで初期化されると、別のCNIに切り替えるにはノードをドレインして再初期化する必要があります。

ノードが存在する前にCiliumをインストールすることで、CiliumのCNI設定が kube-system に既に存在し、ノードが起動した瞬間にピックアップされる準備ができていることを保証します。EC2インスタンスが起動すると、CiliumのDaemonSet Podがすぐにスケジュールされ、eBPFプログラムがロードされ、ノードは最初の瞬間からCiliumの制御下で Ready 状態になります。

これは、EKSセットアップのステップ3でクラスターが disableDefaultAddons: true で作成された理由でもあります — これがないと、AWS VPC CNIが自動的にインストールされ、Ciliumと競合することになります。

Helmを使用してCiliumをインストールします:

helm install cilium isovalent/cilium --version 1.18.4 \
  --namespace kube-system -f cilium-enterprise-values.yaml
Pending状態のジョブは正常です

インストール後、いくつかのジョブがPending状態になっているのが見えます — これは正常です。CiliumのHelmチャートにはHubble用のTLS証明書を生成するジョブが含まれており、そのジョブを実行するにはノードが必要です。次のステップでノードが利用可能になると、自動的に完了します。

ステップ 3: ノードグループの作成

nodegroup.yaml という名前のファイルを作成します:

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: isovalent-demo
  region: us-east-1
managedNodeGroups:
- name: standard
  instanceType: m5.xlarge
  desiredCapacity: 2
  privateNetworking: true

ノードグループを作成します(5〜10分かかります):

eksctl create nodegroup -f nodegroup.yaml

ステップ 4: Cilium インストールの確認

ノードの準備ができたら、すべてのコンポーネントを確認します:

# Check nodes
kubectl get nodes

# Check Cilium pods
kubectl get pods -n kube-system -l k8s-app=cilium

# Check all Cilium components
kubectl get pods -n kube-system | grep -E "(cilium|hubble)"

期待される出力:

  • 2つのノードが Ready 状態
  • Cilium Podが実行中(ノードごとに1つ)
  • Hubble relayとtimescapeが実行中
  • Cilium operatorが実行中

ステップ 5: 拡張ネットワークオブザーバビリティを備えた Tetragon のインストール

Tetragonはそのままでもランタイムセキュリティとプロセスレベルの可視性を提供します。Splunkとの統合 — 特にNetwork Explorerダッシュボード — には、TCP/UDPソケット統計、RTT、接続イベント、DNSをカーネルレベルで追跡する拡張ネットワークオブザーバビリティモードも有効にする必要があります。

tetragon-network-values.yaml という名前のファイルを作成します:

# Tetragon configuration with Enhanced Network Observability enabled
# Required for Splunk Observability Cloud Network Explorer integration

tetragon:
  # Enable network events — this activates eBPF-based socket tracking
  enableEvents:
    network: true

  # Layer3 settings: track TCP, UDP, and ICMP with RTT and latency
  # These enable the socket stats metrics (srtt, retransmits, bytes, etc.)
  layer3:
    tcp:
      enabled: true
      rtt:
        enabled: true     # Round-trip time per TCP flow
    udp:
      enabled: true
    icmp:
      enabled: true
    latency:
      enabled: true       # Per-connection latency tracking

  # DNS tracking at the kernel level (complements Hubble DNS metrics)
  dns:
    enabled: true

  # Expose Tetragon metrics via Prometheus
  prometheus:
    enabled: true
    serviceMonitor:
      enabled: true

  # Filter out noise from internal system namespaces — we only care about
  # application workloads, not the observability stack itself
  exportDenyList: |-
    {"health_check":true}
    {"namespace":["", "cilium", "tetragon", "kube-system", "otel-splunk"]}

  # Only include labels that are meaningful for the Network Explorer
  metricsLabelFilter: "namespace,workload,binary"

  resources:
    limits:
      cpu: 500m
      memory: 1Gi
    requests:
      cpu: 100m
      memory: 256Mi

# Enable the Tetragon Operator and TracingPolicy support.
# With tracingPolicy.enabled: true, the operator manages and deploys
# TracingPolicies (TCP connection tracking, HTTP visibility, etc.) automatically.
tetragonOperator:
  enabled: true
  tracingPolicy:
    enabled: true

これらの値でTetragonをインストールします:

helm install tetragon isovalent/tetragon --version 1.18.0 \
  --namespace tetragon --create-namespace \
  -f tetragon-network-values.yaml

インストールを確認します:

kubectl get pods -n tetragon

表示される内容: TetragonはDaemonSet(ノードごとに1つのPod)とオペレーターとして実行されます。

拡張ネットワークオブザーバビリティが追加するもの

layer3.tcp.rtt.enabled: true を設定すると、TetragonはカーネルのTCPソケット状態にフックし、ラウンドトリップタイム、再送回数、送受信バイト数、セグメント数を含む接続ごとのメトリクスを記録します。これらはSplunkのNetwork Explorerのレイテンシとスループットビューを動かす tetragon_socket_stats_* メトリクスに供給されます。これがないとイベントカウントのみが取得されますが、これがあると接続品質データが取得できます。

TracingPolicies(TCP接続追跡、HTTP可視性など)は、上記のHelm valuesで tetragonOperator.tracingPolicy.enabled: true が設定されている場合、Tetragon Operatorによって自動的に管理されます。

ステップ 6: Cilium DNS Proxy HA のインストール

cilium-dns-proxy-ha-values.yaml という名前のファイルを作成します:

enableCriticalPriorityClass: true
metrics:
  serviceMonitor:
    enabled: true

DNS Proxy HAをインストールします:

helm upgrade -i cilium-dnsproxy isovalent/cilium-dnsproxy --version 1.16.7 \
  -n kube-system -f cilium-dns-proxy-ha-values.yaml

確認します:

kubectl rollout status -n kube-system ds/cilium-dnsproxy --watch
成功

これでCilium CNI、Hubbleオブザーバビリティ、Tetragonセキュリティを備えた完全に機能するEKSクラスターが完成しました!

Last Modified 2026/03/30

Splunk Integration

概要

Splunk OpenTelemetry Collectorは、Prometheusレシーバーを使用してすべてのIsovalentコンポーネントからメトリクスをスクレイプします。各コンポーネントは異なるポートでメトリクスを公開しており、CiliumとHubbleは同じPodを共有しています(ポートが異なるだけです)。そのため、Podアノテーションに依存するのではなく、各コンポーネントに対して個別のレシーバーを設定します。

コンポーネントポート提供する情報
Cilium Agent9962eBPF データパス、ポリシー適用、IPAM、BPF マップ統計
Cilium Envoy9964L7 プロキシメトリクス(HTTP、gRPC)
Cilium Operator9963クラスター全体のアイデンティティとエンドポイント管理
Hubble9965ネットワークフロー、DNS、HTTP L7、TCP フラグ、ポリシー判定
Tetragon2112ランタイムセキュリティ、ソケット統計、ネットワークフローイベント

ステップ 1: 設定ファイルの作成

splunk-otel-collector-values.yaml という名前のファイルを作成します。認証情報のプレースホルダーを実際の値に置き換えてください。

terminationGracePeriodSeconds: 30
agent:
  config:
    extensions:
      # k8s_observer watches the Kubernetes API for pod and port changes.
      # This enables automatic service discovery without static endpoint lists.
      k8s_observer:
        auth_type: serviceAccount
        observe_pods: true

    receivers:
      kubeletstats:
        collection_interval: 30s
        insecure_skip_verify: true

      # Cilium Agent (port 9962) and Hubble (port 9965) both run in the
      # same DaemonSet pod, identified by label k8s-app=cilium.
      # We use two separate scrape jobs because they're on different ports.
      prometheus/isovalent_cilium:
        config:
          scrape_configs:
            - job_name: 'cilium_metrics_9962'
              scrape_interval: 30s
              metrics_path: /metrics
              kubernetes_sd_configs:
                - role: pod
              relabel_configs:
                - source_labels: [__meta_kubernetes_pod_label_k8s_app]
                  action: keep
                  regex: cilium
                - source_labels: [__meta_kubernetes_pod_ip]
                  target_label: __address__
                  replacement: ${__meta_kubernetes_pod_ip}:9962
                - target_label: job
                  replacement: 'cilium_metrics_9962'
            - job_name: 'hubble_metrics_9965'
              scrape_interval: 30s
              metrics_path: /metrics
              kubernetes_sd_configs:
                - role: pod
              relabel_configs:
                - source_labels: [__meta_kubernetes_pod_label_k8s_app]
                  action: keep
                  regex: cilium
                - source_labels: [__meta_kubernetes_pod_ip]
                  target_label: __address__
                  replacement: ${__meta_kubernetes_pod_ip}:9965
                - target_label: job
                  replacement: 'hubble_metrics_9965'

      # Cilium Envoy uses a different pod label (k8s-app=cilium-envoy)
      prometheus/isovalent_envoy:
        config:
          scrape_configs:
            - job_name: 'envoy_metrics_9964'
              scrape_interval: 30s
              metrics_path: /metrics
              kubernetes_sd_configs:
                - role: pod
              relabel_configs:
                - source_labels: [__meta_kubernetes_pod_label_k8s_app]
                  action: keep
                  regex: cilium-envoy
                - source_labels: [__meta_kubernetes_pod_ip]
                  target_label: __address__
                  replacement: ${__meta_kubernetes_pod_ip}:9964
                - target_label: job
                  replacement: 'cilium_metrics_9964'

      # Cilium Operator is a Deployment (not DaemonSet), identified by io.cilium.app=operator
      prometheus/isovalent_operator:
        config:
          scrape_configs:
            - job_name: 'cilium_operator_metrics_9963'
              scrape_interval: 30s
              metrics_path: /metrics
              kubernetes_sd_configs:
                - role: pod
              relabel_configs:
                - source_labels: [__meta_kubernetes_pod_label_io_cilium_app]
                  action: keep
                  regex: operator
                - target_label: job
                  replacement: 'cilium_metrics_9963'

      # Tetragon is identified by app.kubernetes.io/name=tetragon
      prometheus/isovalent_tetragon:
        config:
          scrape_configs:
            - job_name: 'tetragon_metrics_2112'
              scrape_interval: 30s
              metrics_path: /metrics
              kubernetes_sd_configs:
                - role: pod
              relabel_configs:
                - source_labels: [__meta_kubernetes_pod_label_app_kubernetes_io_name]
                  action: keep
                  regex: tetragon
                - source_labels: [__meta_kubernetes_pod_ip]
                  target_label: __address__
                  replacement: ${__meta_kubernetes_pod_ip}:2112
                - target_label: job
                  replacement: 'tetragon_metrics_2112'

    processors:
      # Strict allowlist filter: only forward metrics we've explicitly named.
      # Without this, Cilium and Tetragon can generate thousands of metric series
      # and overwhelm Splunk Observability Cloud with cardinality.
      filter/includemetrics:
        metrics:
          include:
            match_type: strict
            metric_names:
            # --- Kubernetes base metrics ---
            - container.cpu.usage
            - container.memory.rss
            - k8s.container.restarts
            - k8s.pod.phase
            - node_namespace_pod_container
            - tcp.resets
            - tcp.syn_timeouts

            # --- Cilium Agent metrics ---
            # API rate limiting — detect if the agent is being throttled
            - cilium_api_limiter_processed_requests_total
            - cilium_api_limiter_processing_duration_seconds
            # BPF map utilization — alerts when eBPF maps are near capacity
            - cilium_bpf_map_ops_total
            # Controller health — tracks background reconciliation tasks
            - cilium_controllers_group_runs_total
            - cilium_controllers_runs_total
            # Endpoint state — how many pods are in each lifecycle state
            - cilium_endpoint_state
            # Agent error/warning counts — early warning for problems
            - cilium_errors_warnings_total
            # IP address allocation tracking
            - cilium_ip_addresses
            - cilium_ipam_capacity
            # Kubernetes event processing rate
            - cilium_kubernetes_events_total
            # L7 policy enforcement (HTTP, DNS, Kafka)
            - cilium_policy_l7_total
            # DNS proxy latency histogram — key metric for catching DNS saturation
            - cilium_proxy_upstream_reply_seconds_bucket

            # --- Hubble metrics ---
            # DNS query and response counts — primary indicator in the demo scenario
            - hubble_dns_queries_total
            - hubble_dns_responses_total
            # Packet drops by reason (policy_denied, invalid, TTL_exceeded, etc.)
            - hubble_drop_total
            # Total flows processed — overall network activity volume
            - hubble_flows_processed_total
            # HTTP request latency histogram and total count
            - hubble_http_request_duration_seconds_bucket
            - hubble_http_requests_total
            # ICMP traffic tracking
            - hubble_icmp_total
            # Policy verdict counts (forwarded vs. dropped by policy)
            - hubble_policy_verdicts_total
            # TCP flag tracking (SYN, FIN, RST) — connection lifecycle visibility
            - hubble_tcp_flags_total

            # --- Tetragon metrics ---
            # Total eBPF events processed
            - tetragon_events_total
            # DNS cache health
            - tetragon_dns_cache_evictions_total
            - tetragon_dns_cache_misses_total
            - tetragon_dns_total
            # HTTP response tracking with latency
            - tetragon_http_response_total
            - tetragon_http_stats_latency_bucket
            - tetragon_http_stats_latency_count
            - tetragon_http_stats_latency_sum
            # Layer3 errors
            - tetragon_layer3_event_errors_total
            # TCP socket statistics — per-connection RTT, retransmits, byte/segment counts
            # These power the latency and throughput views in Network Explorer
            - tetragon_socket_stats_retransmitsegs_total
            - tetragon_socket_stats_rxsegs_total
            - tetragon_socket_stats_srtt_count
            - tetragon_socket_stats_srtt_sum
            - tetragon_socket_stats_txbytes_total
            - tetragon_socket_stats_txsegs_total
            - tetragon_socket_stats_rxbytes_total
            # UDP statistics
            - tetragon_socket_stats_udp_retrieve_total
            - tetragon_socket_stats_udp_txbytes_total
            - tetragon_socket_stats_udp_txsegs_total
            - tetragon_socket_stats_udp_rxbytes_total
            # Network flow events (connect, close, send, receive)
            - tetragon_network_connect_total
            - tetragon_network_close_total
            - tetragon_network_send_total
            - tetragon_network_receive_total

      resourcedetection:
        detectors: [system]
        system:
          hostname_sources: [os]

    service:
      pipelines:
        metrics:
          receivers:
            - prometheus/isovalent_cilium
            - prometheus/isovalent_envoy
            - prometheus/isovalent_operator
            - prometheus/isovalent_tetragon
            - hostmetrics
            - kubeletstats
            - otlp
          processors:
            - filter/includemetrics
            - resourcedetection

autodetect:
  prometheus: true

clusterName: isovalent-demo

splunkObservability:
  accessToken: <YOUR-SPLUNK-ACCESS-TOKEN>
  realm: <YOUR-SPLUNK-REALM>           # e.g. us1, us2, eu0
  profilingEnabled: true

cloudProvider: aws
distribution: eks
environment: isovalent-demo

# Gateway mode runs a central collector deployment that receives from all agents.
# Agents send to the gateway, which handles batching and export to Splunk.
# This reduces the number of direct connections to Splunk's ingest endpoint.
gateway:
  enabled: true
  resources:
    requests:
      cpu: 250m
      memory: 512Mi
    limits:
      cpu: 1
      memory: 1Gi

# certmanager handles mTLS between the OTel Collector agent and gateway
certmanager:
  enabled: true

重要: 以下を置き換えてください:

  • <YOUR-SPLUNK-ACCESS-TOKEN> をSplunk Observability Cloudのアクセストークンに
  • <YOUR-SPLUNK-REALM> をレルム(例: us1、us2、eu0)に
厳格なメトリクス許可リストを使用する理由

Ciliumは、ワークロード、名前空間、プロトコルの詳細に関するすべてのラベルの組み合わせを考慮すると、数千のユニークなメトリクスシリーズを出力する可能性があります。filter/includemetrics 許可リストがないと、負荷の高いクラスターでは50,000以上のアクティブシリーズが簡単に生成され、Splunkのインジェストに過負荷をかける可能性があります。上記のリストは、CiliumとHubbleのダッシュボードを動作させるために必要なメトリクスと、Network Explorerに必要なTetragonソケット統計を正確に含むようにキュレートされています。後で新しいダッシュボードを追加する場合は、このリストにメトリクスを追加できます。

Tetragonソケット統計で可能になること

tetragon_socket_stats_* メトリクスは、SplunkのNetwork Explorerで接続ごとのレイテンシとスループット分析を可能にするものです。srtt_count/srtt_sum は、ワークロードごとの平均TCPラウンドトリップタイムを提供します。retransmitsegs_total は、パケットロスと輻輳を表面化します。txbytes/rxbytes は、接続ごとの帯域幅を示します。これらはAPMや標準のインフラストラクチャメトリクスでは確認できません。

ステップ 2: Splunk OpenTelemetry Collector のインストール

コレクターをインストールします:

helm upgrade --install splunk-otel-collector \
  splunk-otel-collector-chart/splunk-otel-collector \
  -n otel-splunk --create-namespace \
  -f splunk-otel-isovalent.yaml

ロールアウトが完了するまで待ちます:

kubectl rollout status daemonset/splunk-otel-collector-agent -n otel-splunk --timeout=60s

ステップ 3: メトリクス収集の確認

コレクターがメトリクスをスクレイプしていることを確認します:

kubectl logs -n otel-splunk -l app=splunk-otel-collector --tail=100 | grep -i "cilium\|hubble\|tetragon"

各コンポーネントのスクレイプが成功していることを示すログエントリが表示されるはずです。

次のステップ

メトリクスがSplunk Observability Cloudに送信されています!ダッシュボードを確認するには、検証に進んでください。

Last Modified 2026/03/30

デモ — Isovalent と Splunk を使用した DNS 問題の調査

このデモで示すこと

このデモは、すべての運用チームやプラットフォームチームが経験したことのあるストーリーを語ります。何かが壊れていて、ユーザーが不満を訴えていて、どこから始めればよいかわからない状況です。調査は通常の最初のステップを経由します — APMは問題なさそう、インフラストラクチャも問題なさそう — そしてネットワーク層へとピボットします。そこでIsovalentのHubbleオブザーバビリティがSplunkに流れ込み、本当の問題を明らかにします。それは他のすべてのツールからは完全に見えなかったDNS過負荷です。

アプリケーションは jobs-app で、tenant-jobs namespaceで実行されるシミュレートされたマルチサービスの採用プラットフォームです。フロントエンド(recruiterjobposting)、中央API(coreapi)、バックグラウンドデータパイプライン(Kafka + resumes + loader)、および定期的にインターネットへHTTP呼び出しを行う crawler サービスがあります。このcrawlerがこのストーリーの悪役になります。

重要なポイント

APMとインフラストラクチャのメトリクスは正常に見えます。根本原因であるDNS過負荷は、アプリケーション層より下に存在するため、SplunkのIsovalent Hubbleダッシュボードを通じてのみ見ることができます。


開始前の準備

これは誰もいない状態で行ってください。デモが始まるときには、クリーンで正常なダッシュボードの前に座っていたいものです — 人々が見ている中でkubectlをいじっているのではなく。

Jobs App のデプロイ

まだ行っていない場合は、isovalent-demo-jobs-app リポジトリからjobs-app Helm chartをデプロイします。

helm dependency build .
helm upgrade --install jobs-app . --namespace tenant-jobs --create-namespace

すべてが実行中であることを確認

デモ中に驚かないよう、これらのチェックを実行します。

# Confirm your nodes are healthy
kubectl get nodes

# Confirm Cilium and Hubble are running on both nodes
kubectl get pods -n kube-system | grep -E "(cilium|hubble)"

# Confirm the Splunk OTel Collector is running — this is what ships metrics to Splunk
kubectl get pods -n otel-splunk

# Confirm the jobs-app is fully deployed and healthy
kubectl get pods -n tenant-jobs
重要

続行する前に、すべてのPodが Running 状態である必要があります。OTel Collectorが起動していない場合、Splunkにメトリクスが表示されず、デモが成功しません。

アプリを正常なベースラインにリセット

crawlerが穏やかで通常のペースで実行されていることを確認します — 1レプリカ、0.5から5秒ごとにクロール:

helm upgrade jobs-app . --namespace tenant-jobs --reuse-values \
  --set crawler.replicas=1 \
  --set crawler.crawlFrequencyLowerBound=0.5 \
  --set crawler.crawlFrequencyUpperBound=5 \
  --set resumes.replicas=1

その後、少なくとも 5 分待ちます。Splunkがクリーンなベースラインを取り込む時間が必要で、これから作成するスパイクが視覚的に明らかになります。これをスキップすると、チャートが明確なストーリーを伝えません。

問題を注入

デモ開始の約5〜10分前(または効果を出すためにデモ中にライブで)、以下を実行します:

helm upgrade jobs-app . --namespace tenant-jobs --reuse-values \
  --set crawler.replicas=5 \
  --set crawler.crawlFrequencyLowerBound=0.2 \
  --set crawler.crawlFrequencyUpperBound=0.3 \
  --set resumes.replicas=2

これによりcrawlerが1 Podから5にスケールアップし、クロール間隔が0.2〜0.3秒に短縮されます。各crawler Podは api.github.com にHTTPリクエストを行い、それらのリクエストごとに最初にDNSルックアップが必要です。5つのPodが毎秒複数回DNSを叩くと、約15〜25のDNSクエリが持続的に発生します — DNSプロキシを飽和させ、応答レイテンシを蓄積させるのに十分な量です。DNSに依存するnamespace内の他のサービスが断続的な障害を経験し始めます。これがまさにチケットに記載されている内容です。


Act 1 — チケットが届く

まず状況を描写します。まだ何もクリックする必要はありません — シーンを設定するだけです。

「普通の午後で、ITSM チケットが届きました。jobs アプリケーションチームから、エンドユーザーが recruiter と job posting ページで断続的な 500 エラーを報告していて、過去 15 分ほどでロード時間が明らかに悪化したと言っています。P2 にエスカレートされました。調査しましょう。」

チケットINC-4072
優先度P2 — 高
概要jobs-app での断続的な障害と応答時間の遅延
説明Recruiter と job posting ページが断続的に 500 エラーを返しています。ユーザーは過去 15 分間でページロードが大幅に遅くなったと報告しています。エンジニアリングは最近のデプロイメントを行っていません。
報告者アプリケーションサポートチーム
影響を受ける namespacetenant-jobs

「最近のデプロイメントはない — これが実は興味深い点です。責めるべき明らかな変更イベントがありません。だから自分たちで何が変わったかを把握する必要があります。どこから始めましょう?APM です。」


Act 2 — APM を確認(行き止まり)

ここはほとんどの人が最初に行くところで、それがポイントです。APMを表示し、役に立たないことを見つけ、それを使ってより深いものが必要であるケースを構築します。

移動先: Splunk Observability Cloud → APMService Map

tenant-jobs 環境のサービスマップはトポロジーを示します:recruiterjobposting は両方とも coreapi を呼び出し、coreapiはElasticsearchに接続します。resumesloader サービスはバックグラウンドでKafkaを介して通信します。

「これがサービスマップです。すべてのサービスが点灯しています — すべて応答していて、すべて接続されています。数字が実際に何を示しているか見てみましょう。

リクエストレートは正常に見えます。レイテンシはわずかに上昇しているかもしれませんが、ユーザー向けのエラーを説明するほどのものではありません。coreapi のエラーレートを見てください — 約 10% です。これが問題だと思うかもしれませんが、そうではありません。このアプリはセットアップの一部として設定可能なエラーレートが組み込まれています。10 パーセントはベースラインであり、リグレッションではありません。

つまり APM が教えてくれるのは:サービスは生きていて、トラフィックは流れていて、エラーレートは変化していないということです。アプリケーショントレースには根本原因を示すものがありません。インフラストラクチャを試してみましょう。」

なぜAPMではこれが見えないのか

APMはアプリケーションコードを計装します — サービス内部で何が起こっているかを観察します。接続が確立される前にネットワーク層で何が起こっているかは見えません。DNS解決、接続の切断、パケットレベルのイベントは、設計上APMからは見えません。


Act 3 — インフラストラクチャを確認(行き止まり)

インフラを表示し、クリーンであることを見つけ、聴衆にまだ答えがないフラストレーションを感じさせます。

移動先: Splunk Observability Cloud → InfrastructureKubernetes → Cluster: isovalent-demo

「クラスター自体を見てみましょう。何かリソースが制約されているかもしれません — ノードが高負荷、Pod が OOMKilled されている、そのようなことです。

両方のノードは正常に見えます。CPU とメモリは正常範囲内です。Pod を掘り下げると — すべて Running 状態で、再起動なし、退去もされていません。コンテナ自体もリソース制限に達していません。

これで少し不快な状況になりました。チケットにはユーザーがエラーを見ていると書いてあります。APM はアプリが実行中だと言っています。インフラストラクチャはクラスターが正常だと言っています。これでどうなりますか?

これは実際に非常によくある状況です。アプリケーション層より下、インフラストラクチャ層より下に存在する問題のクラス全体があります — 従来のモニタリングツールでは単純に見えないネットワークレベルで起こっていること。DNS 障害、接続の切断、ポリシー拒否、トラフィックの非対称性。これらはトレースや Pod メトリクスには現れません。ネットワーク自体を観察できるものが必要です。そこで Isovalent の出番です。」


Act 4 — ネットワークが真実を語る

これがデモの核心です。ここはゆっくり時間をかけてください。

移動先: Splunk Observability Cloud → DashboardsHubble by Isovalent

「Cilium — 私たちの CNI、すべてのノードで実行されているネットワーキング層 — には Hubble という組み込みのオブザーバビリティコンポーネントがあります。Hubble は eBPF を使用してクラスター内のすべてのネットワークフローをリアルタイムで監視します。サンプリングではなく、近似でもなく — すべての接続、すべての DNS リクエスト、すべてのパケットドロップ。そして OpenTelemetry Collector がそれらの Hubble メトリクスをスクレイプして Splunk に転送するように設定しているので、APM やインフラストラクチャを見ていたのと同じプラットフォームでそれらすべてを見ることができます。

Hubble ダッシュボードを表示しましょう。」

DNS クエリが制御不能

DNS Queries チャートを指し、次に DNS Overview タブに移動します。

「ありました。DNS クエリ量を見てください — 約 15 分前に急激にスパイクしています。このタイムスタンプはチケットが開かれた時間とぴったり一致します。

見ているのは hubble_dns_queries_total で、ソース namespace ごとに分類されています。スパイクは完全に tenant-jobs — アプリケーション namespace から来ています。アプリケーション内の何かが大量の DNS トラフィックを生成し始め、DNS プロキシが追いつくのに苦労し始めました。

しかし右下を見てください — Missing DNS Responses チャートです。これはアラートが発火しているものです。値が深くマイナスになっています。これは DNS クエリが送信されているのに、応答が一度も戻ってこないことを意味します。DNS プロキシが圧倒され、接続は静かにタイムアウトしています。これがユーザーの 500 エラーとして現れている波及効果です。」

Hubble DNS Overview showing Missing DNS Responses alert firing as values go deeply negative Hubble DNS Overview showing Missing DNS Responses alert firing as values go deeply negative

トップ DNS クエリが原因を明らかに

Top 10 DNS Queries チャートを指します。

「これらすべての DNS リクエストを行っているものを特定しましょう。Top 10 DNS Queries チャートは最も頻繁にクエリされるドメインを分類しており、1 つの名前が圧倒的に目立っています:api.github.com

これはクラスター内部のサービスではありません — 外部エンドポイントです。そしてアプリ内で外部エンドポイントと通信するのは crawler サービスだけです。crawler はジョブシミュレーションの一部として外部 URL への HTTP 呼び出しを行います。その HTTP 呼び出しを行うたびに、最初に DNS を通じて api.github.com を解決する必要があります。

通常これは問題ありません。1 つの crawler Pod が数秒ごとにリクエストを行うのは完全に管理可能です。しかし、どれだけ積極的に実行されているかについて何かが明らかに変化しています。」

ドロップされたフローが影響範囲を示す

Dropped Flows チャートを指します。

「Dropped Flows チャートは別の注目すべきことを示しています。Hubble は成功した接続だけを追跡するのではありません — 拒否またはドロップされたすべての接続と、その理由コードをキャプチャします。DNS スパイクと全く同じ時間にドロップの増加が見られます。

これらのドロップは DNS 過負荷の下流の結果です。namespace 内のサービスが接続を試み、DNS が遅すぎるか失敗すると、それらの接続試行はタイムアウトしてドロップされます。これが APM がレイテンシの上昇として見ていたものです — しかし APM にはその下に DNS 問題があることは全くわかりませんでした。」

ネットワークフロー量がパターンを確認

Metrics & Monitoring タブに移動します。

「そして Metrics & Monitoring タブを見ると、全体像がさらに明確になります。ノードごとの処理フロー数が垂直に上昇しています — これは生のネットワークトラフィック量です。Forwarded vs Dropped チャートは、それらのフローのかなりの割合が転送されずにドロップされていることを示しています。そして Drop Reason の内訳は、TTL_EXCEEDED と DROP_REASON_UNKNOWN の混合であることを教えてくれます — DNS タイムアウトがカスケードし始めたときにまさに予想されるものです。特定の時点で何かが変わり、その時点以降のすべてがベースラインとは異なって見えます。」

Hubble Metrics & Monitoring showing flow spike, forwarded vs dropped, and drop reasons Hubble Metrics & Monitoring showing flow spike, forwarded vs dropped, and drop reasons

L7 HTTP トラフィックが興味深いストーリーを語る

L7 HTTP Metrics タブに移動します。

「L7 HTTP Metrics タブで指摘する価値のあることがあります。これは実際に APM が役に立たなかった理由を補強するからです。受信リクエスト量はゼロではありません — トラフィックはまだ流れています。成功率チャートはほとんど緑に見えます。HTTP レベルの可視性だけを見ていた場合、アプリは問題ないと結論づけるかもしれません。

しかし Incoming Requests by Source チャートを見てください。crawler が不釣り合いなシェアのトラフィックを生成しています — 他のサービスから分離しているのが見えます。HTTP 呼び出しを成功させているので、APM はフラグを立てません。問題は 1 つ下の層、DNS で、HTTP 接続が確立される前に起こっています。」

Hubble L7 HTTP Metrics showing crawler traffic spike with high request volume Hubble L7 HTTP Metrics showing crawler traffic spike with high request volume


Act 5 — 根本原因の確認

ここで点と点をつなぎ、証明します。

「これが全体像です:ある時点で、crawler サービスが 1 レプリカから 5 にスケールアップされ、クロール間隔が非常に積極的に設定されました — 0.2 から 0.3 秒ごと。これは 5 つの Pod が、それぞれ api.github.com を解決するために DNS ルックアップを毎秒複数回発火させています。合計すると、毎秒 15 から 25 の DNS クエリが持続的に発生します。DNS プロキシは単一のワークロードからそのような負荷を処理するようには作られていないので、キューイング、スローダウン、そして最終的にはリクエストのドロップを開始します。DNS 解決を必要とする namespace 内の他のすべてのサービスが巻き添えを食います。

それが何を見ているか確認しましょう。」

# Confirm the current crawler replica count — you'll see 5
kubectl get deploy crawler -n tenant-jobs

# Pull the environment config to see the crawl frequency settings
kubectl get deploy crawler -n tenant-jobs \
  -o jsonpath='{.spec.template.spec.containers[0].env}' | jq .

オプションとして、Cilium by Isovalent dashboard → Policy: L7 Proxy タブに切り替えます。

「Hubble 側ではなく Cilium 側からこれを見たい場合は、Cilium by Isovalent dashboard に切り替えて Policy: L7 Proxy タブを見てください。FQDN の L7 Request Processing Rate — これが DNS です — が 21,000 リクエストを超えています。これは分あたりではありません。DNS プロキシは非常に大量の FQDN ルックアップを処理しており、すべて受信されて転送されているため、バックアップし始めました。このビューは DNS Proxy Upstream Reply レイテンシも表示しており、プロキシが圧力下にあることを確認できます。」

Cilium Policy: L7 Proxy showing FQDN request processing rate spiking to 21k+ Cilium Policy: L7 Proxy showing FQDN request processing rate spiking to 21k+

「ありました。5 レプリカ、0.2 から 0.3 秒ごとにクロール。

APM ではこれが見えません。コードを計装しているのであって、DNS ではないからです。インフラストラクチャモニタリングでもこれは見えません。Pod は正常です — 設定されたとおりに正確に動作しています。これをキャッチできる唯一のツールは、eBPF レベルで動作し、すべてのパケット、すべての DNS リクエスト、すべての接続試行をリアルタイムで監視するものです。それが Hubble です。そして Splunk に接続しているので、他のすべてに使用しているのと同じダッシュボードでキャッチしました。」


Act 6 — ライブで修正

この部分は満足感があります。チャートがリアルタイムで回復するのを見ることができるからです。

「修正は簡単です — crawler をスケールダウンして、通常のクロール間隔を復元します。」

helm upgrade jobs-app . --namespace tenant-jobs --reuse-values \
  --set crawler.replicas=1 \
  --set crawler.crawlFrequencyLowerBound=0.5 \
  --set crawler.crawlFrequencyUpperBound=5 \
  --set resumes.replicas=1

Hubble by Isovalent ダッシュボードに戻り、1分ほど待ちます。

「DNS Queries チャートを見てください — ほぼ即座に下がってくるのが見えます。1〜2 分以内にベースラインに戻ります。ドロップされたフローはゼロになります。ネットワークフロー量は通常に戻ります。

そして今 APM に戻ると、レイテンシが正常化し、エラーレートが予想される 10% のベースラインに落ち着くのが見えるでしょう。

チケットをクローズできます。根本原因:crawler の設定ミスによる DNS 飽和。解決策:Helm を使用して crawler のレプリカ数とクロール間隔を元に戻す。解決までの時間:チケットが開かれてから約 15 分。」

修復完了

DNSクエリレートがベースラインに戻り、ドロップされたフローがクリアされ、アプリケーションの健全性が回復します — すべてHubbleダッシュボードでライブで確認できます。


Act 7 — これが実際に意味すること

ズームアウトして、価値のステートメントを具体的に感じさせて終わります。

「ここで何が起こったか考えてみましょう。本番スタイルの本当の問題がありました — エンドユーザーにとって何かが壊れていて — 標準的なプレイブックを経由しました。APM は何も問題ないと言いました。インフラストラクチャも何も問題ないと言いました。Hubble がなければ、次のステップはおそらく戦争部屋の通話、ログを見つめる人々、namespace 全体の再起動を期待して行うことだったでしょう。

代わりに、Hubble ダッシュボードを開いた瞬間から 3 分以内に見つけました。私たちが賢いからではなく、正しい層への可視性があったからです。

これが機能する理由は eBPF です。Cilium の Hubble コンポーネントは Linux カーネルにフックし、ソースでネットワークイベントを観察します — アプリケーションコードに到達する前に、Pod ログに現れる前に、APM のトレースになる前に。そして OpenTelemetry Collector を通じてそれらのメトリクスを Splunk に送信することで、APM データやインフラストラクチャデータと同じプラットフォームに並んでいます。ツールを切り替えたり、5 つの異なるダッシュボード間でコンテキストスイッチする必要はありません。以前なかった可視性の層を追加し、チームがすでに知っているワークフローに保持します。

これがストーリーです。ネットワークオブザーバビリティはニッチなニーズではありません — APM とインフラストラクチャモニタリングが残すギャップです。Isovalent がそのギャップを埋め、Splunk でそれを見ることができます。」


クイックリファレンス

問題を注入(デモの約10分前に実行):

helm upgrade jobs-app . -n tenant-jobs --reuse-values \
  --set crawler.replicas=5 \
  --set crawler.crawlFrequencyLowerBound=0.2 \
  --set crawler.crawlFrequencyUpperBound=0.3 \
  --set resumes.replicas=2

修復(Act 6でライブ実行):

helm upgrade jobs-app . -n tenant-jobs --reuse-values \
  --set crawler.replicas=1 \
  --set crawler.crawlFrequencyLowerBound=0.5 \
  --set crawler.crawlFrequencyUpperBound=5 \
  --set resumes.replicas=1

設定ミスを確認:

kubectl get deploy crawler -n tenant-jobs
kubectl get deploy crawler -n tenant-jobs \
  -o jsonpath='{.spec.template.spec.containers[0].env}' | jq .

Splunk ナビゲーションパス: APM → Service Map → (クリーンであることを表示) → Infrastructure → Kubernetes → (クリーンであることを表示) → Dashboards → Hubble by Isovalent → (DNS スパイクを表示)

タイミングガイド

セクション概算時間
Act 1 — チケット約 1 分
Act 2 — APM(行き止まり)約 2〜3 分
Act 3 — インフラストラクチャ(行き止まり)約 1〜2 分
Act 4 — Hubble ダッシュボード約 4〜5 分
Act 5 — 根本原因の確認約 2 分
Act 6 — ライブで修正約 2 分
Act 7 — 価値のまとめ約 2 分
合計約 14〜17 分