この記事は ReviCo Advent Calendar 2025 の24日目の記事です。
昨日はReviCoのかむりさんによる「ポ。~POに取り組む際に意識したこと二選~」でした。
はじめに
こんにちは。ReviCoのレコメンドチームで開発をしている おと です。
レコメンドチームでは、アプリケーションの実行基盤として Azure Container Apps(以下ACA) を採用しています。
ACAで パスベースルーティングをやりたくて、当時は標準機能だと要件を満たせなかったので、「ACAの上にTraefikを立てて入口で捌く」構成を組んでいました。
さらに 「入口のアクセスログが欲しい」 という要件があったので、Traefikの OTLP(OpenTelemetry Logs) 機能を使って New Relic にログを直送していました(Collectorなし)。
ただし今は、ACAの Rule-based Routing が Ignite’25 で GA になり、「もう余計なリバプロを立てなくてもよい」世界になっています。 (TECHCOMMUNITY.MICROSOFT.COM)
現行はすぐ移行できないので、移行前の供養として記事に残します。
この記事でやること・やらないこと
やること:
- Traefikで PathRegexp を使ったパスベースルーティング
- Traefikの Access Log を OTLP/HTTP で New Relic に送る
やらないこと:
- アプリ側のトレース計装(今回は 「アクセスログが欲しい」が主目的)
ざっくり検証前提
- Traefik Proxy:v3系想定(
experimental.otlpLogsを使うため) (Traefik Docs) - New Relic:OTLP ingest(
api-keyヘッダ必須) (New Relic Docs) - Azure Container Apps:環境内の他アプリへは アプリ名 or FQDN で到達可能 (Microsoft Learn)
ざっくり全体構成
- 外部公開:Traefik(external ingress)
- 内部:test1 / test2(internal ingress)
- 観測:Traefik access log → OTLP → New Relic
Traefikのルーティング設定(dynamic file)
今回Traefikは file provider(/etc/traefik/dynamic/)でルーティング定義しています。
http:
services:
test1:
loadBalancer:
passHostHeader: false
servers:
- url: 'https://test-1.internal.{{ env "CONTAINER_APP_ENV_DNS_SUFFIX" }}'
test2:
loadBalancer:
passHostHeader: false
servers:
- url: 'https://test-2.internal.{{ env "CONTAINER_APP_ENV_DNS_SUFFIX" }}'
routers:
test1:
rule: "PathRegexp(`/api/v[0-9]{1}/.+/test1(/.*)?$`)"
service: test1
priority: 20
test2:
rule: "PathRegexp(`/api/v[0-9]{1}(/|$).*(/|$).*`)"
service: test2
priority: 10
ここで一言:{{ env "..." }} は何?
Traefikの file provider は Go Templating をサポートしていて、dynamic config ファイル内でテンプレ展開できます。
ただし注意点として、Go Templating は “dynamic config 専用ファイル” でのみ有効で、静的設定ファイルでは使えません。 (Traefik Docs)
また ACA 側には、環境の DNS サフィックスを参照できる CONTAINER_APP_ENV_DNS_SUFFIX が用意されています。 (Microsoft Learn)
Traefikの静的設定
NewRelicへアクセスログを連携するのは環境設定で制御可能です。
1) 入口(443)と file provider
TRAEFIK_ENTRYPOINTS_WEB_ADDRESS=:443
TRAEFIK_PROVIDERS_FILE_DIRECTORY=/etc/traefik/dynamic/
TRAEFIK_LOG_LEVEL=INFO
2) Access Log → OTLP(experimental)→ New Relic
Traefikの OTLP Logs は experimental で、experimental.otlpLogs=true が必須です。 (Traefik Docs)
# access log を有効化
TRAEFIK_ACCESSLOG=true
# OTLP Logs を有効化(experimental)
TRAEFIK_EXPERIMENTAL_OTLPLOGS=true
# OTLP/HTTP の送信先(path込み)
TRAEFIK_ACCESSLOG_OTLP_HTTP_ENDPOINT=https://otlp.nr-data.net:4318/v1/logs
# New Relic は api-key ヘッダ必須(license key)
TRAEFIK_ACCESSLOG_OTLP_HTTP_HEADERS_API-KEY=<NEW_RELIC_LICENSE_KEY>
# New Relic 側で見分けやすいように(任意)
TRAEFIK_ACCESSLOG_OTLP_SERVICENAME=<your-service-name>
/v1/logs を入れる理由
New Relicは、signal-specific endpoint を使う場合 適切な path を含めないと 404 になると明記しています。 (New Relic Docs)
また api-key ヘッダ(ライセンスキー)が無いと認証エラーになります。 (New Relic Docs)
3) “最低限ほしいヘッダだけ残す”(任意)
TRAEFIK_ACCESSLOG_FIELDS_HEADERS_NAMES_User-Agent=keep
TRAEFIK_ACCESSLOG_FIELDS_HEADERS_NAMES_Referer=keep
できあがり
ハマりどころ
“アプリ名で通信” と “FQDNで通信” の使い分け
ACAは、環境内通信に アプリ名も使えます。 (Microsoft Learn)
ただしアプリ名呼び出しはHTTP前提なので、HTTPS-only(allowInsecure:false)や internal ingress(.internal. FQDN)構成では、結果的にFQDN(HTTPS)で統一した方が扱いやすかったので、FQDNで通信を採用しました。
Traefik3.5バージョンアップ後にOTel周りでKubernetes検知が走ってエラーになった
TraefikはKubernetes上で動いている場合、Pod/NamespaceなどのKubernetes属性を自動検知してresource attributesに付与します。
ただしACAではKubernetes APIへアクセスできる前提ではないため、検知処理が失敗して起動時エラーになることがありました。
Unable to create access logger error="setting up OpenTelemetry logger provider: building resource: error detecting resource: creating in cluster config: open /var/run/secrets/kubernetes.io/serviceaccount/token: no such file or directory"
Kubernetesのin-cluster判定に使われがちな KUBERNETES_SERVICE_HOST/PORT を空にし、あわせてresource detectorの対象から k8s を外す設定を追加することで回避しました。
供養:いまは ACA 標準のルールベースルーティングが GA
Ignite’25 の公式ブログで、ACAの Rule-based Routing が GAになり、ホスト名やパスで環境内のアプリへルーティングできるようになった、と説明されています。さらに「NGINXのような追加リバプロは不要」と明言されています。 (TECHCOMMUNITY.MICROSOFT.COM)
今から新規で作るなら、まずは ACA標準のルールベースルーティングを検討するのがたぶん正解です。

