Skyscanner: 24 の本番クラスターにまたがる OpenTelemetry Collector の管理
Johanna Öjeling(Grafana Labs)、 Juliano Costa(Datadog)、 Tristan Sloughter(community)、 Neil Fordyce(Skyscanner)著 | 2026年4月21日
このリファレンス実装では、スコットランドのエディンバラに拠点を置くグローバルな旅行検索プラットフォームである Skyscanner が、OpenTelemetry を大規模に運用している方法について説明します。
世界中に1,400人の従業員を擁し、24の本番 Kubernetes クラスターで1,000以上のマイクロサービスを運用する Skyscanner の OpenTelemetry 導入の歩みは、大規模に運用する組織にとって貴重な教訓を提供します。
組織構造
Hubble チームは6人のプラットフォームエンジニアで構成され、Skyscanner の Collector の大部分を管理しています。 より広範なプラットフォームエンジニアリング組織の一部として、Skyscanner の主に Java ベースのマイクロサービスアーキテクチャを実行するコンピュートプラットフォームを担当しています。
サービスチーム自身は、デプロイメントやテレメトリー収集インフラストラクチャから抽象化されています。 Java サービスでは、チームは事前設定済みの OpenTelemetry Java エージェントを含むベース Docker イメージを継承します。 Python や Node.js のサービスでは、プラットフォームチームが環境やリソース属性に基づいた適切なデフォルト値を設定するラッパーライブラリを提供しています。 これらのアプローチにより、ボイラープレートのセットアップが最小限に抑えられ、サービスチームは深い OpenTelemetry の知識を必要とせずにすぐにオブザーバビリティを利用できます。
OpenTelemetry の導入
Skyscanner の OpenTelemetry の導入は2021年に始まりました。 同社は社内で構築したオープンソーススタックから商用ベンダーへの移行を進めていました。 しかし、ベンダーロックインを避けたいと考えていました。
「ベンダーに依存しない形でベンダーに移行したかったのです」と、Skyscanner の Hubble プラットフォームチームのソフトウェアエンジニアである Neil Fordyce は説明しました。
このベンダーに依存しないアプローチが、テレメトリーインフラストラクチャの中核として OpenTelemetry Collector を採用することにつながりました。
アーキテクチャ: 集中ルーティング、分散収集
Skyscanner の Collector アーキテクチャは、Istio ベースのインテリジェントルーティングを備えた中央 DNS エンドポイントを特徴としています。 サービスがグローバルのどこで実行されているか、どのクラスターにいるかに関わらず、テレメトリーはこの単一のアドレスに送信されます。 Istio が最も近い利用可能な Collector へのリクエストルーティングを処理します。
デプロイメントは2つの異なる Collector パターンで構成されています。
Gateway Collector(Replica Set): ほとんどのサービスからの大量の OTLP トラフィック(トレースとメトリクス)を処理し、処理の大部分がここで行われます。
Agent Collector(DaemonSet): OTLP をネイティブにサポートしていないオープンソースおよびプラットフォームサービスから Prometheus エンドポイントをスクレイプします。

設定: シンプルに始めて、徐々に進化させる
Skyscanner が2021年に Collector を最初にデプロイしたとき、設定はメモリリミッター、バッチプロセッサー、トレース用の OTLP エクスポーターという最小限のものでした。
時間の経過とともに、設定は自然に進化しました。 メトリクスパイプラインの追加、Istio スパンの取り込みの統合、スパンからメトリクスへの変換の実装、ノイズを削減しコストを管理するためのフィルタープロセッサーの追加などが行われました。
Istio サービスメッシュのスパンをプラットフォームメトリクスに変換する
Skyscanner の Collector の最も革新的な活用法の1つは、Istio サービスメッシュのスパンからメトリクスを生成することです。
Istio のネイティブメトリクスには、Prometheus デプロイメントを圧倒するカーディナリティ爆発の問題がありました。 さらに、Skyscanner はコードを所有していないものの、一貫したメトリクスが必要な多くの既製サービスを運用しています。
彼らの解決策は次のとおりです。 Istio がスパンを発行するように設定し(元々は Zipkin 形式でしたが、現在 Istio は OTLP をサポートしています)、Zipkin レシーバーを使用して Collector に取り込み、セマンティック規約に合わせて変換し、span metrics connector を使用して、アプリケーションの計装なしで一貫したメトリクスを生成するというものです。
「アプリケーションの所有者がコードを計装することなく、プラットフォームレベルでそれを実現できるのです」と Neil は述べました。
span metrics connector の設定は、スパンから主要なディメンションを抽出します。
connectors:
spanmetrics:
aggregation_temporality: AGGREGATION_TEMPORALITY_DELTA
dimensions:
- name: http.status_code
- name: grpc.status_code
- name: rpc.service
- name: rpc.method
- name: prot
- name: flag
- name: k8s.deployment.name
- name: k8s.replicaset.name
- name: destination_subset
dimensions_cache_size: 15000000
histogram:
exponential:
max_size: 160
unit: ms
metrics_flush_interval: 30s
Collector はこれらのメトリクスを http.client.duration や http.server.duration などのセマンティック規約の名前を使用するように変換し、クラスター、サービス名、HTTP ステータスコード別に集約します。
これにより、コード変更なしですべてのサービスにプラットフォームレベルの HTTP メトリクスが提供され、セマンティック規約に準拠した一貫した命名が実現し、ネイティブの Istio メトリクスよりも低いカーディナリティが得られます。
404 エラーの課題
Collector 設定に関する注目すべき課題の1つは、キャッシュサービスがキャッシュにエントリが存在しないことを示すために HTTP 404 を返すケースでした。 Collector はこれらの 404 をエラーとして扱い、実際には正常な高頻度の動作に対して 100% のトレースサンプリングをトリガーしていました。
解決策は、これらの特定の 404 レスポンスに対してエラーステータスを解除するフィルタープロセッサーを追加することでした。
processors:
span/unset_cache_client_404:
include:
attributes:
- key: http.response.status_code
value: ^404$
- key: server.address
value: ^(service-x\.skyscanner\.net|service-y\.skyscanner\.net|service-z\.skyscanner\.net|service-z-\w{2}-\w+-\d\.int\.\w{2}-\w+-\d\.skyscanner\.com)$
match_type: regexp
regexp:
cacheenabled: true
cachemaxnumentries: 1000
status:
code: Unset
このプロセッサーは、特定のキャッシュサービスからの 404 ステータスコードを持つスパンに一致させ、そのエラーステータスを解除することで、エラーベースのサンプリングがトリガーされるのを防ぎます。
「最初からフィルタープロセッサーがあれば、より高品質で使いやすいトレースが得られたでしょう」と Neil は振り返りました。
しかし、Neil は OpenTelemetry SDK の宣言的設定が最近導入されたことで、このようなフィルタリングは中央の Collector 設定を変更する必要なく、サービスチーム自身が分散的に設定できるようになったと述べています。
設定の詳細
Skyscanner は、これらのパターンを実際に理解してもらうために、本番環境の Collector 設定を共有しています。
Gateway Collector
Gateway Collector は処理の大部分を担当します。
- サービスからの OTLP メトリクスとトレース、および Istio からの Zipkin スパンを受信する
- span metrics connector を使用して Istio スパンからメトリクスを生成する
- 広範な transform プロセッサーを使用して Istio 属性をセマンティック規約にマッピングする
- キャッシュサービスに対する 404 フィルタリングロジックを実装する
- メトリクスとトレースを OTLP 経由でオブザーバビリティベンダーにエクスポートする
この図は、OTLP メトリクスとトレース、および Istio スパンがこれらの Gateway Collector にどのように到達するかを示しています。

Agent Collector
Agent Collector は、各ノードからのインフラストラクチャおよびプラットフォームレベルのメトリクスの収集に特化しています。
- さまざまなソース(node exporter、kube-state-metrics、kubelet)から Prometheus エンドポイントをスクレイプする
- 最小限の処理(メモリ制限、バッチ処理、属性のクリーンアップ)を実行する
- メトリクスを OTLP 経由でオブザーバビリティベンダーにエクスポートする
計装戦略
Skyscanner の Java 中心の環境は、OpenTelemetry の自動計装機能から大きな恩恵を受けています。 ベース Docker イメージに事前設定された Java エージェントにより、HTTP と gRPC のスパン生成がすぐに利用可能です。
独自方針の自動計装
チームは自動計装に対して意図的に独自の方針を持ったアプローチをとっています。 デフォルトですべてを有効にするのではなく、逆のアプローチをとっています。 共有ベース Docker イメージですべての計装を無効にし、厳選されたセットのみを明示的に有効にしています。
「逆のアプローチなのです。すべてを無効にしてから、必要なものだけを有効にします」と Neil は説明しました。
ベースイメージの環境変数を使用して、Skyscanner はデフォルトでランタイム、HTTP、gRPC 関連の計装の厳選されたセットを有効にしています。 これには、JAX-RS、gRPC、Jetty、一般的な HTTP クライアント、executor 計装、ロギングコンテキスト伝搬が含まれます。 サービスチームはこれらのデフォルトを自動的に継承しますが、必要に応じて自身のサービス定義でオーバーライドしたり、追加の計装を有効にしたりできます。
このモデルにより、数百のサービスにわたる一貫性を確保しつつ、必要な場合には柔軟性も維持できます。
Java エージェントのセットアップ
以下のスニペットは、共有 Java ベースイメージの一例です。 OpenTelemetry Java エージェントをイメージにバンドルし、組織全体のデフォルトを設定し、共通のランチャースクリプトをインストールします。
# OpenTelemetry Java エージェントのソースとして使用するイメージ
FROM ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:2.25.0 AS otel
# すべての Java マイクロサービスが拡張する共通ベースイメージを定義する
FROM image/registry/public-java-image:x.y.z
# OTel イメージから OpenTelemetry Java エージェントをコピーする
COPY --from=otel /javaagent.jar $OPEN_TELEMETRY_DIRECTORY/opentelemetry-javaagent.jar
ENV OTEL_AGENT=$OPEN_TELEMETRY_DIRECTORY/opentelemetry-javaagent.jar
# 組織全体で適切なデフォルトを設定する
ENV OTEL_METRICS_EXPORTER="otlp"
ENV OTEL_TRACES_EXPORTER="otlp"
ENV OTEL_LOGS_EXPORTER="none"
ENV OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE="DELTA"
ENV OTEL_EXPERIMENTAL_METRICS_VIEW_CONFIG="otel-view.yaml"
ENV OTEL_EXPORTER_OTLP_ENDPOINT="http://otel.skyscanner.net"
ENV OTEL_INSTRUMENTATION_COMMON_DEFAULT_ENABLED="false"
ENV OTEL_INSTRUMENTATION_RUNTIME_TELEMETRY_ENABLED="true"
ENV OTEL_INSTRUMENTATION_ASYNC_HTTP_CLIENT_ENABLED="true"
ENV OTEL_INSTRUMENTATION_APACHE_HTTPCLIENT_ENABLED="true"
COPY run.sh /usr/bin/run.sh
そのランチャースクリプト run.sh は、デプロイメントが提供する環境変数から -javaagent フラグと otel.resource.attributes を構築します。
# OTel リソース属性をセットアップするために使用する
# サービス起動時に環境変数から検出できるもの
# これらの変数はデプロイメントシステムによって自動的に設定される
# 一部の環境変数は繰り返しを避けるために省略されている
setup_otel_agent() {
if [[ -n "$AWS_REGION" ]]; then CLOUD_REGION="cloud.region=${AWS_REGION},"; else CLOUD_REGION=""; fi
if [[ -n "$AWS_ACCOUNT" ]]; then CLOUD_ACCOUNT_ID="cloud.account.id=${AWS_ACCOUNT},"; else CLOUD_ACCOUNT_ID=""; fi
if [[ -n "$CLUSTER_NAME" ]]; then K8S_CLUSTER_NAME="k8s.cluster.name=${CLUSTER_NAME},"; else K8S_CLUSTER_NAME=""; fi
if [[ -n "$SERVICE" ]]; then SERVICE_NAME="service.name=${SERVICE}"; else SERVICE_NAME=""; fi
echo -n "-javaagent:$OTEL_AGENT" \
"-Dotel.resource.attributes=${CLOUD_REGION}${CLOUD_ACCOUNT_ID}${K8S_CLUSTER_NAME}${SERVICE_NAME}"
}
JAVA_OPTS="-D64 -server -showversion $(setup_otel_agent) ${ADDITIONAL_JAVA_OPTS:-}"
exec java $JAVA_OPTS "$@"
最後に、個々のサービスの Dockerfile は同じベースを拡張し、そのサービスに必要な追加の計装のみを追加します。
FROM image/registry/skyscanner-java-base:x.y.z
COPY my-service.jar
# my-service が他のデフォルト以外の計装を有効にしたい場合、簡単に拡張できる
ENV OTEL_INSTRUMENTATION_OPENAI_ENABLED=true
ENV OTEL_INSTRUMENTATION_OKHTTP_ENABLED=true
CMD exec /usr/bin/run.sh -jar my-service.jar server
スパンは有効、メトリクスは無効(デフォルト)
Skyscanner の戦略で特に興味深い点は、メトリクスとトレースの扱い方です。 HTTP と gRPC の計装は有効になっていますが、チームは SDK が生成する HTTP および RPC メトリクスのほとんどを意図的にドロップしています。 これは、前述のとおり、Istio サービスメッシュのスパンから一貫性があり、低カーディナリティのプラットフォームメトリクスをすでに導出しているためです。
計装を完全に無効にする(スパンも削除される)のではなく、OpenTelemetry SDK ビューを使用してメトリクスの集約をドロップしつつ、トレースは維持しています。
- HTTP と RPC のメトリクスはグローバルにドロップされる
- スパンは通常どおり発行され続ける
- サービスチームは、Istio が提供するものを超える追加の粒度が必要な場合、特定のメトリクス(たとえばサーバーサイドのレイテンシー)を選択的に再有効化できる
チームが SDK メトリクスを再度有効にする場合、既存の Istio 由来のメトリクスとの衝突や二重カウントを避けるために、通常はメトリクス名を変更します。
先ほど示した Java ベースイメージでは、OTEL_EXPERIMENTAL_METRICS_VIEW_CONFIG が Skyscanner のデフォルトの otel-view.yaml を指しており、ビューファイル設定を使用しています。
# Skyscanner のデフォルトメトリクスビュー設定
# OTEL_EXPERIMENTAL_METRICS_VIEW_CONFIG が指すファイルに保存される
# Istio からのメトリクスがすでにあるため、http と rpc のメトリクスをドロップする
# 計装自体を無効にするのではなく、トレースは引き続き機能させたい
- selector:
instrument_name: http.*
view:
aggregation: drop
- selector:
instrument_name: rpc.*
view:
aggregation: drop
サービスが特定のメトリクスを保持する必要がある場合、同じファイルを拡張できます。
一般的なユースケースは、http.route ごとにリクエストを分類することです。
# このドロップ動作は、リストを拡張して保持するメトリクスを
# 明示的に選択するビューを追加することで変更できる。
# 例: http.server.request.duration メトリクスを保持しつつ、
# http.client.* メトリクスは引き続きドロップする
- selector:
instrument_name: http.server.request.duration
view:
# Istio メトリクスにすでに http.server.request.duration という名前のメトリクスがあるため、
# 衝突や二重カウントを避けるためにリネームする
name: app.http.server.request.duration
attribute_keys:
- http.request.method
- http.route
- http.response.status_code
このアプローチにより、Skyscanner は高価値の分散トレースを維持し、メトリクスの重複を回避し、カーディナリティを制御し、取り込みコストを削減できます。 これらすべてをサービスオーナーが OpenTelemetry の内部を深く理解する必要なく実現しています。
全体として、この戦略は強力なプラットフォームマインドセットを反映しています。 スケールで機能する適切なデフォルトを提供し、ノイズを最小限に抑え、「正しいこと」を「簡単なこと」にしつつ、高度なニーズを持つチームがさらに先に進む余地を残しています。
デプロイメントとリリース管理
Skyscanner は、必要なものがすべて含まれていたため、OpenTelemetry Collector Contrib ディストリビューションを使用しています。 チームは Contrib が本番環境での使用には推奨されていないことを認識しており、必要なコンポーネントのみを含むカスタム Collector イメージの構築を検討する予定です。
Skyscanner は約6か月ごとに Collector を更新しますが、特定の機能や重要な修正を追跡している場合はより頻繁にアップグレードします。 リリース情報を把握するために RSS フィードや CNCF Slack チャンネルをフォローしています。
ロールアウト戦略では、クラスター階層間での段階的なプロモーションを使用します。 Dev クラスター、次に3つの Alpha 本番クラスター、続いて8つの Beta 本番クラスター、最後に残りの13の本番クラスターという順序です。 Argo CD を使用してデプロイメントを行い、階層間の変更はプルリクエストを通じてプロモーションされます。
「開発テストクラスターで確実に問題を起こしたことはありますが、さらにプロモーションする前に修正しました」と Neil は言いました。
この段階的なアプローチにより、設定上の問題を本番環境に到達する前にキャッチできました。 OpenTelemetry Collector のデプロイメントに対する自動化されたテストやロールバック機能はまだありませんが、これらの改善は今後予定されています。
うまくいっていること
本番環境で OpenTelemetry を導入して以来、チームの経験は非常にポジティブなものでした。
「本当にほとんど痛みがなかったです」と Neil は振り返りました。
柔軟性が Collector の最大の強みとして際立っています。
「やろうとしたことはすべて実現できました。それは Collector がいかに柔軟であるかを物語っていると思います」と Neil は説明しました。
その他のハイライトとしては、OTLP プロトコルがシンプルな設定によるベンダー非依存性を提供していること、明確で整理されたリリースノート、そしてチームメンバーが Collector コンポーネントのメモリリークを発見して修正に貢献した際のコミュニティの対応力があります。
教訓と課題
Skyscanner は一部のパイプラインで古い不安定な HTTP セマンティック規約をまだ使用しています。 アップグレードには、Istio 属性をセマンティック規約の名前にマッピングする複数の transform プロセッサールールの更新が必要で、ドキュメントを手動で照合し、設定文字列を埋める作業が伴います。
チームはセマンティック規約の管理に Weaver があることを認識していますが、まだワークフローに統合していません。
6か月ごとにアップグレードすることは、一度に複数の破壊的変更に直面することを意味します。 リリースノートはよく書かれており、変更が明確に文書化されていますが、6か月分の更新を一度にレビューするのは、リリースペースに追随する場合と比べて負担が大きくなります。
他の組織へのアドバイス
本番環境での経験に基づき、Skyscanner チームは以下のアドバイスを提供しています。
- シンプルに始める: メモリリミッター、バッチプロセッサー、基本的なエクスポーターだけから始めましょう。 必要が生じたときにのみ複雑さを追加してください。
- メモリリミッターは初日から: スケールアップに伴うメモリの問題を防ぐために、すぐにセットアップしましょう。
- フィルタープロセッサーの早期検討: アプリケーションのステータスコードのセマンティクスを理解し、高頻度の「偽陽性」をフィルタリングしてコストを管理しましょう。
- 回復性を過度に設計しない: テレメトリーデータには、シンプルなインメモリバッチ処理で十分な場合が多いです。
- 段階的なロールアウトで問題をキャッチ: 環境階層間での段階的なプロモーションは、貴重な検証を提供します。
まとめ
Skyscanner の事例は、少人数のプラットフォームエンジニアリングチームが、比較的低い運用オーバーヘッドで大規模な OpenTelemetry Collector インフラストラクチャを成功裏に管理できることを示しています。
フィードバック
このページは役に立ちましたか?
Thank you. Your feedback is appreciated!
Please let us know how we can improve this page. Your feedback is appreciated!