クラスター間通信のための Collector の公開
Blog posts are not updated after publication. This post is more than a year old, so its content may be outdated, and some links may be invalid. Cross-verify any information before relying on it.
OpenTelemetry Collector を外部に公開するには、現時点ではいくつかの設定手順が必要です。 このブログ記事の目的は、異なる Kubernetes クラスター間にある 2 つの Collector 間で安全な通信を確立する方法を紹介することです。
CRD の詳細や依存関係のインストールについては、この記事では扱いません。
概要
Collector を公開するにあたって、まず思い浮かぶのは TLS によるユーザーデータの安全な伝送です。 しかし、認可されていないサービスからのデータ送信を防ぐため、サーバーへの認証も同様に重要です。
OpenTelemetry Collector はさまざまな認証方式をサポートしています。 よく使われるのは以下の方式です。
- TLS 認証
- OpenID Connect(OIDC 認証)
- HTTP Basic 認証
この記事ではシンプルさを重視して HTTP Basic 認証 に焦点を当てます。 鍵管理や追加のサードパーティサービスなしに、安全なセットアップを運用する方法を示すことを目的としています。
TLS の設定に関する詳細は、記事 How TLS provides identification, authentication, confidentiality, and integrity と、GitHub 上の Collector の TLS-Config の説明を参照してください。
外部の認証プロバイダーの利用に興味がある場合は、Juraci Paixão Kröhling による記事 Securing your OpenTelemetry Collector をご覧ください。 この記事では、 OIDC-Authenticator エクステンション を使用して OpenTelemetry Collector を保護する方法と、 Keycloak を認証プロバイダーとして設定する方法が説明されています。
Basic 認証
HTTP Basic 認証のメカニズムは非常にシンプルです。
HTTP ユーザーエージェント(たとえばウェブブラウザ)は、リクエストごとにユーザー名とパスワードの組み合わせを提供します。
送信される認証情報は、接続の確立時に HTTP ヘッダーのキー Authorization に含められます。
値としてはまず認証方式 basic が記述され、続いてエンコードされた認証情報が続きます。
認証情報の形式は username:password である点に注意してください。
以下の例では、dXNlci0xOjEyMzQK は username=user-1 と password=1234 の組み合わせをエンコードしたものです。
base64 の値をエンコードまたはデコードするには、以下を使用できます。
# HTTP ヘッダーの key: value ペア
Authorization: Basic <credentials-base64-encoded>
# 例: user: user-1 password: 1234
Authorization: Basic dXNlci0xOjEyMzQK
base64 CLI ツールを使用すれば、独自のユーザーパスワードの組み合わせを簡単に作成できます。
# エンコード
$ echo "user-1:1234" | base64
dXNlci0xOjEyMzQK
# デコード
$ echo "dXNlci0xOjEyMzQK" | base64 -d
user-1:1234
データフロー
以下のグラフは、ターゲットとなるトポロジーを示しています。 目的は、 テストアプリケーション によって生成されたトレースを、専用の Collector を経由して公開アクセス可能なクラスターに転送することです。 受信側の Collector は、送信された ‘Basic’ HTTP 認証 の認証情報を使用して、送信者がデータを保存する権限を持っているかどうかを確認します。 最後に、送信されたトレースは Jaeger in-memory に保存されます。

前提条件
インターフェイスと動作は将来変更される可能性があります。 そのため、このセットアップで使用されるバージョンを括弧内に記載しています。
- パブリックアドレスを持つ Kubernetes
v1.23.3クラスターに ingress-nginx-controllerv1.2.1がインストールされていること。 - テストクラスターを作成するための Kubernetes
v1.23.3エッジクラスター。 Kind の使用を推奨します。 - 両方のクラスターに OpenTelemetry Operator
v0.58.0がインストールされていること。 - パブリッククラスターに Jaeger Operator
v1.37.0がインストールされていること。 - パブリッククラスターに cert-manager
v1.9.1がインストールされていること。
リモートクラスターの設定
Jaeger バックエンド以外のすべてのコンポーネントは後続のコンポーネントに依存しているため、まずバックエンドのデプロイから始めます。
apiVersion: jaegertracing.io/v1
kind: Jaeger
metadata:
name: my-in-memory
次のステップでは、OpenTelemetryCollector CRD を使用して OpenTelemetry Collector を作成します。
最も重要なエントリは mode、image、および設定された basicauth エクステンションです。
以下のマニフェストでは、受信情報を処理する Collector Pod が少なくとも 1 つ利用可能であることを保証するため、モード deployment が選択されています。
さらに、デフォルトの Collector イメージは
contrib バージョンで上書きされています。
これは、core バージョン には
basicauth
エクステンションが含まれていないためです。
このエクステンションは basicauth/server という名前で設定され、otlp/basicauth に登録されています。
otlp exporter のエンドポイントとして Jaeger in-memory サービスが設定されています。
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: otel-collector-app
spec:
mode: deployment
image: otel/opentelemetry-collector-contrib:0.58.0
config: |
extensions:
basicauth/server:
htpasswd:
inline: |
<REPLACE: your backend credentials, e.g.: "user-1:1234">
receivers:
otlp/basicauth:
protocols:
grpc:
auth:
authenticator: basicauth/server
exporters:
otlp/jaeger:
endpoint: my-in-memory-collector:4317
tls:
insecure: true
insecure_skip_verify: true
service:
extensions: [basicauth/server]
pipelines:
traces:
receivers: [otlp/basicauth]
exporters: [otlp/jaeger]
インストールが成功すると、選択した名前空間に Jaeger バックエンド用の Pod と OpenTelemetry Collector 用の Pod が作成されます。
NAME READY STATUS RESTARTS AGE
my-in-memory-6c5f5f87c5-rnp99 1/1 Running 0 4m
otel-collector-app-collector-55cccf4b7d-llczt 1/1 Running 0 3m
また、以下のサービスが利用可能になります。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-in-memory-agent ClusterIP None <none> 5775/UDP,5778/TCP,6831/UDP,6832/UDP 7m
my-in-memory-collector ClusterIP 10.245.43.185 <none> 9411/TCP,14250/TCP,14267/TCP,14268/TCP,4317/TCP,4318/TCP 7m
my-in-memory-collector-headless ClusterIP None <none> 9411/TCP,14250/TCP,14267/TCP,14268/TCP,4317/TCP,4318/TCP 7m
my-in-memory-query ClusterIP 10.245.91.239 <none> 16686/TCP,16685/TCP 7m
otel-collector-app-collector ClusterIP 10.245.5.134 <none> 4317/TCP 5m
otel-collector-app-collector-headless ClusterIP None <none> 4317/TCP 5m
otel-collector-app-collector-monitoring ClusterIP 10.245.116.38 <none> 8888/TCP 5m
最後に、cert-manager を設定して Let’s Encrypt から TLS 証明書を自動的にリクエストし、Ingress の TLS 設定で利用できるようにします。
以下の ClusterIssuer と Ingress のエントリは otel-collector-app-collector サービスを公開します。
email と host フィールドの値を置き換える必要がある点に注意してください。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
namespace: cert-manager
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email-address-here@example.com # REPLACE
privateKeySecretRef:
name: letsencrypt
solvers:
- http01:
ingress:
class: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-otel
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: GRPC
cert-manager.io/cluster-issuer: letsencrypt
spec:
tls:
- hosts:
- your-host # REPLACE your domain endpoint, e.g., traces@example.com
secretName: letsencrypt
rules:
- host: your-host # REPLACE your domain endpoint, e.g., traces@example.com
http:
paths:
- pathType: Prefix
path: '/'
backend:
service:
name: otel-collector-app-collector
port:
number: 4317
エッジクラスターの設定
送信されたトレースの発信元を特定できるようにするため、 k8sattributes プロセッサー を使用して、スパンタグに識別用のメタデータを追加します。 これは OpenTelemetry Collector の contrib バージョンで利用できます。 次のステップでは、必要な権限を持つサービスアカウントを作成します。 K8s メタデータの詳細については、記事 「Improved troubleshooting using K8s metadata」を参照してください。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: attributes-role
rules:
- apiGroups:
- ''
resources:
- pods
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: attributes-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: attributes-role
subjects:
- kind: ServiceAccount
name: attributes-account
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: attributes-account
エッジ Collector の最も重要な設定を確認しましょう。
デプロイモードとして daemonset を使用し、ノードごとに 1 つの Collector インスタンスが存在するようにしています。
basicauth エクステンションには、公開されたリモート Collector に対して自身を識別するための username と password が含まれています。
コンテナやノードに固有の情報は、k8sattributes プロセッサーが Kubernetes の
Kubernetes downward-api
を介して提供します。
ここでカバーされていないのは、クラスターのアベイラビリティゾーンとクラスター名です。
報告されたスパンを後で識別できるようにするため、resource プロセッサーを使用して手動で挿入しています。
最後に、OTLP エクスポーターのエンドポイントにもプレースホルダーの値が設定されており、リモートクラスターのドメインに置き換える必要があります。
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: otel-collector-app
spec:
mode: daemonset
image: otel/opentelemetry-collector-contrib:0.58.0
serviceAccount: attributes-account
env:
- name: KUBE_NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
config: |
extensions:
basicauth/client:
client_auth: # 認証情報は受信側 Collector のものと一致している必要があります。
username: <REPLACE: your basicauth username, e.g.: "user-1">
password: <REPLACE: your basicauth password, e.g.: "1234">
receivers:
otlp:
protocols:
grpc:
processors:
resource:
attributes:
- key: cloud.availability_zone
value: <REPLACE: your availability zone, e.g.: "eu-west-1">
action: insert
- key: k8s.cluster.name
value: <REPLACE: your cluster name, e.g.: "edge-cluster-1">
action: insert
k8sattributes:
filter:
node_from_env_var: KUBE_NODE_NAME
exporters:
otlp:
endpoint: "<REPLACE: your domain endpoint, e.g.: "traces.example.com:443">"
auth:
authenticator: basicauth/client
logging:
service:
extensions: [basicauth/client]
pipelines:
traces:
receivers: [otlp]
processors: [k8sattributes]
exporters: [otlp,logging]
インストールが成功すると、otel-collector-app-collector という名前の daemonset が作成されます。
これにより、各クラスターノードにローカルの Collector インスタンスが起動して稼働していることが保証されます。
テストデータ生成用のトレースジェネレーターのデプロイ
apiVersion: apps/v1
kind: Deployment
metadata:
name: trace-gen
spec:
selector:
matchLabels:
app: trace-gen
template:
metadata:
labels:
app: trace-gen
spec:
containers:
- name: trace-gen
image: ghcr.io/frzifus/jaeger-otel-test:latest
args:
[
'-otel.agent.host=otel-collector-app-collector',
'-otel.agent.port=4317',
]
env:
- name: OTEL_SERVICE_NAME
value: 'local-test-service'
テスト
これで、エッジクラスターで生成されたスパンが発信元のメタデータで拡張されます。 その後、リモートクラスターに転送され、Jaeger バックエンドに保存されます。 Jaeger 自体が、送信されたデータを検査するための UI を提供しています。
UI にアクセスする簡単な方法は、ローカルシステムへのポートフォワーディングです。
$ kubectl port-forward deployments/my-in-memory 16686
Forwarding from 127.0.0.1:16686 -> 16686

まとめ
Ingress、ClusterIssuer、および OpenTelemetryCollector のクライアント側とサーバー側の設定は手動で行う必要があります。
インストールされている Kubernetes コンポーネントによって、設定は大きく異なります。
全体として、設定はエラーが起きやすいものです。
将来的には、OpenTelemetry Operator を活用して Collector の公開を簡素化すべきです。
開発状況に興味がある方は、
GitHub issue #902
をフォローして最新情報を確認してください。