Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ECSでのinit_containerを利用したOpen_Telmetry自動計装.pdf

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for clouddev-code clouddev-code
September 17, 2026
5

 ECSでのinit_containerを利用したOpen_Telmetry自動計装.pdf

Avatar for clouddev-code

clouddev-code

September 17, 2026

More Decks by clouddev-code

Transcript

  1. JAWS-UG コンテナ支部 #30 — ECSサービスチーム来日スペシャル「AI時代のリアルなECS運用」 ECSでのinit containerを利用した OpenTelemetry自動計装 Next.js on

    ECS Fargate — アプリのコード変更なしで分散トレースを取得し、ADOT Collector 経由で AWS X-Ray に送信。インフラは AWS CDK (TypeScript) で構築。 蛭田 聡司 (Soushi Hiruta) · @web_se 実装 & ローカルE2E検証 完了 AWS実デプロイ & X-Rayトレース確認 完了 ECSでのinit containerを利用したOpenTelemetry自動計装 01 / 16
  2. 02 — 自己紹介 自己紹介 蛭田 聡司 Soushi Hiruta 基盤設計構築 写真

    / アイコン Community 興味 AWS Community Builder 2025 (Container KubeCon EU 2023〜2026 参加 / コンテナ基盤 / Category) Observability X @web_se · GitHub clouddev-code ECSでのinit containerを利用したOpenTelemetry自動計装 02 / 16
  3. 03 — 対象読者 この発表は誰向けか こんな人に こんな人に こんな人に ECS Fargate で

    Node.js / Next.js を運用している アプリに手を入れずにトレースを 取りたい Application Signals の採用可 否を検討中 前提知識 話さないこと ECS / Docker の基本、OpenTelemetry の用語(trace / span) OTel SDK の手動計装、メトリクス / ログの収集 ECSでのinit containerを利用したOpenTelemetry自動計装 03 / 16
  4. 14 — 検討して断念した選択肢 CloudWatch Application Signals はコストで断念 魅力だった点 断念した理由 :

    トラフィック量に比例する課金 — エージェント常駐のみ、アプリのコード変更が不要 Signal Ingestion(リクエスト課金) ~92% — トレース・メトリクス・サービスマップ・SLO が標準装備 Trace / Span Storage ~6% — AWS マネージドで運用負荷が低い Metrics / その他 ~2% ※ 参考事例の内訳構成比。サンプリング無し・自動計装そのままの状態。 開発環境では 商用トラフィックではシグナル送信数が支配的になり、請求が想定の トラフィックが低く、月額コストはほぼ無視できる範囲。問題は見えな ×10 超 に。CloudWatch Agent / ADOT 経由でも送信先が かった。 Application Signals なら課金体系は変わらない。 採用 ADOT Collector(sidecar)→ X-Ray の構成に決定。サンプリング・フィルタ・送信先を Collector 設定で自分たちが制御でき、Application Signals のリクエスト課金から離脱できる。 ECSでのinit containerを利用したOpenTelemetry自動計装 14 / 16
  5. 04 — 前提: ECS で init container を実現する 前回の話 :

    initContainer を ECS で実現したい Kubernetes の initContainer メインコンテナ起動前に処理させるコンテナ。設定ファイルの置換、初 期ファイルのコピー、計装モジュールの配置などを、イメージを環境ご ECS での組み方 : 3点セット essential: false init 用コンテナは終了しても Task を止めない とに作り分けずに実現できる。 — Nginx 設定 / istio injection などメイン起動前の前処理 dependsOn: condition = SUCCESS app は init の正常終了を待ってから起動 — Application Signals 向け javaagent (OTel) モジュールの配置 volumes + mountPoints (bind mount) 揮発性の共有ボリュームでファイルを受け渡し ECS には initContainer という機能はない。ECS Service はデーモン起動 注意: 起動上限 ECS_CONTAINER_START_TIMEOUT(Fargate は最大 が前提で、非 essential でないコンテナが終了すると Task が終了する。 180s)。Fluent Bit / CloudWatch Agent のような常駐 sidecar は essential のまま。 今回 Java の javaagent 配置で使っていたこのパターンを、Node.js (Next.js) の ADOT 自動計装に適用する。 https://speakerdeck.com/cloudevcode/initcontainerwoecsdeshi-xian-sitai ECSでのinit containerを利用したOpenTelemetry自動計装 04 / 16
  6. 05 — 設計の経緯 計装モジュールと設定をアプリイメージから外に出した理由 Before: イメージに焼き込む 課題 # Dockerfile COPY

    javaagent.jar /opt/ ENV JAVA_TOOL_OPTIONS=-javaagent:... ENV OTEL_EXPORTER_OTLP_ENDPOINT=... — 計装 (jar / autoinstrumentation) のバージョンアップ = アプリの再 ビルド・再リリース After: Task Definition 側で差し込む 採用 init container → 共有ボリューム 計装モジュールは ADOT 公式イメージから cp。バージョンはイメージタ グで管理 environment / secrets NODE_OPTIONS・OTEL_* は Task Definition の環境変数。 Collector 設定は SSM Parameter Store — 送信先・サンプリングなどの環境差分がイメージに混入し、環境ごと にイメージが分岐 — アプリチームの Dockerfile に基盤側の都合が入り、責務が混ざる アプリイメージは素のまま Dockerfile に OTel の記述ゼロ。ローカルと同じイメージがそのまま本 番へ 計装の有無・バージョン・送信先を基盤側 (CDK) だけで切り替えられ る。アプリと計装のライフサイクルを分離。 ECSでのinit containerを利用したOpenTelemetry自動計装 05 / 16
  7. 06 — 検証構成について 本番投入済みの構成を、最小限に切り出して検証 本番環境 検証構成(本日の内容) 2026.09.15 投入 最小限 init

    container + ADOT Collector sidecar による自動計装を、実 自動計装に関わる部分だけを切り出し、サンプルアプリと CDK 1 サービスの ECS Fargate 構成に組み込んで稼働中。 スタックで再構築。同じ挙動になることを確認。 — 複数サービス・複数環境、既存の VPC / ALB / CI/CD に依存 → ✓ Next.js サンプル 1 サービス(2ホップの内部 fetch のみ) — 業務ロジック・認証・DB など計装と無関係な要素が多い ✓ VPC / ALB / ECS / IAM / SSM を CDK 1 スタックに集約 — そのままでは公開・再現ができない ✓ Task Definition の init / app / collector 構成は本番と同一パターン NOTE 以降のスライドの構成図・コード・検証結果は、この切り出した最小構成のもの。 ECSでのinit containerを利用したOpenTelemetry自動計装 06 / 16
  8. 07 — 背景・目的 検証のゴール 01 02 03 コード変更なしの自動計装 分散トレースを X-Rayで可視化

    IaCで再現可能な環境 アプリ側に OpenTelemetry の依存を一切 ADOT Collector を経由してトレースを ECS / ALB / VPC / IAM を AWS CDK 追加せず、ADOT の自動計装だけでトレー AWS X-Ray に送信し、サービスマップ上 (TypeScript) で構築し、誰でも同一構成を スを取得できるかを確認する。 で相関を確認できる状態にする。 再現できるようにする。 検証スコープ Next.js アプリ実装 完了 CDK インフラ実装 完了 ローカル E2E 検証 完了 AWS 実デプロイ 完了 AWS 実環境にデプロイし、X-Ray でトレースを確認済み。CloudWatch Application Signals も検討したがコスト面で断念(後述)。 ECSでのinit containerを利用したOpenTelemetry自動計装 07 / 16
  9. 08 — アーキテクチャ ECS Fargateタスク: 3コンテナ構成 ECS TASK · FARGATE

    / ARM64 OtelInit App OtelCollector 計装ファイルを共有ボリューム Next.js (App Router) OTLP受信 → X-Rayへ送信 に配置 standalone essential: true essential: false essential: true ① cp -a → 共有ボリューム ② OTLP gRPC :4317 → AWS X-Ray ③ awsxray exporter → → Service Map / Traces AWS managed // App コンテナの環境変数 NODE_OPTIONS=--require /otel-auto-instrumentation-node/autoinstrumentation.js dependsOn: OtelInit = SUCCESS, OtelCollector = START NOTE ADOT の Node.js 自動計装イメージは自動コピーの ENTRYPOINT を持たないため、OtelInit の command で明示的に cp -a を実行する必要 がある(Java 版の javaagent 方式とは異なる挙動)。 ECSでのinit containerを利用したOpenTelemetry自動計装 08 / 16
  10. 09 — コンテナ構成の詳細 3コンテナの役割 OtelInit OtelCollector App init container ·

    essential: false sidecar · essential: true essential: true # IMAGE public.ecr.aws/aws-observabil # IMAGE public.ecr.aws/aws-observabil # BUILD Next.js (App Router) ity/adot-autoinstrumentation- ity/aws-otel-collector:v0.50. standalone build node:v0.12.0 0 # NODE_OPTIONS --require # COMMAND cp -a /autoinstrumentation/. # 受信 / 送信 OTLP gRPC:4317 / HTTP:4318 → awsxray exporter /otel-auto-instrumentation-no de/autoinstrumentation.js /otel-auto-instrumentation-no de 自動計装ファイルを共有ボリュームに配置して OTLP を受信し X-Ray に送信。Collector 設定 計装を自動ロードし Collector にトレース送信。 は SSM Parameter Store 経由で環境変数とし dependsOn: OtelInit=SUCCESS, て注入。 OtelCollector=START。 終了する。Java の javaagent 方式と同じ発想 を Node.js に適用したもの。 ECSでのinit containerを利用したOpenTelemetry自動計装 09 / 16
  11. 10 — ネットワーク構成 VPC: 2AZ + NAT Gateway + VPCエンドポイント

    Internet / public.ecr.aws VPC Endpoints ↓ (PrivateLink) VPC · 2 AZ Internet Gateway S3 (Gateway) ecr.api Application Load Balancer · :80 → :3000 ecr.dkr logs ssm xray PUBLIC SUBNET (AZ-a) PUBLIC SUBNET (AZ-b) NAT なし(AZ-aを共用) NAT Gateway ×1 (Regional) ※ public.ecr.aws (ECR Public) は対応外 → NAT Gateway は PRIVATE SUBNET (AZ-a · egress) PRIVATE SUBNET (AZ-b · egress) ECS Fargate Task 維持 スケールアウト先(タスク未配置) 3 containers · ARM64 NAT経由 egress AWS API呼び出し (NAT不要) → ECSでのinit containerを利用したOpenTelemetry自動計装 10 / 16
  12. 11 — サンプルアプリの動作 アプリ内 2ホップの分散トレース Client ↓ HTTP Trace 1-5f2d3a10-8b91c4f0a2e1d9b7c3f84a22

    console exporter ログより ALB :80 Server Component (outer span) GET / ↓ :3000 App (1 container) GET / Server Component ↓ fetch 127.0.0.1:3000 GET /api/hello fetch GET /api/hello GET /api/hello 送信側 span (client) 受信側 span (server / Route Handler) 同一 Trace ID の中に送信側 span (fetch) と受信側 span (Route Handler) が両方出現 — 2ホップの相関を確認 Route Handler ECSでのinit containerを利用したOpenTelemetry自動計装 11 / 16
  13. 12 — ローカルE2E検証結果 実機構成での動作確認 ✓ init コンテナ相当 (cp -a) で共有ボリュームに計装ファイルを配置

    検証環境 ✓ アプリ起動時に "AWS Distro of OpenTelemetry automatic Docker (OrbStack) 上で init → 共有ボリューム → instrumentation started successfully" を確認 NODE_OPTIONS の一連の流れを実機構成で再現。 OTEL_TRACES_EXPORTER=console でコンソール出力から ✓ / と /api/hello への curl → 両方 スパンの相関を直接確認。 200 ✓ 同一 traceId 内で送信側 / 受信側スパンの相関を確認(2ホップ分散トレース) 既知の無害な警告 ✓ npx tsc --noEmit → エラーなし ✓ npx cdk synth → 成功(コンテナ定義 / dependsOn / mountPoints / IAMポリシー / SSM Secret参照が意図通り) ECSでのinit containerを利用したOpenTelemetry自動計装 Cannot execute the operation on ended Span ... ADOT 自動計装と Next.js 内部トレーシングの二重 span 操作 によるもの。トレース自体は正しくエクスポートされる。 12 / 16
  14. 13 — 実装上のハマりどころ 2つの落とし穴 1 HOSTNAME バインド問題 2 CDK L2構成の選択

    原因 原因 Next.js standalone の server.js は process.env.HOSTNAME init コンテナの起動順序制御(containerDependencies )と共有 にバインドする。Docker はコンテナ起動時に HOSTNAME をコンテナ ボリュームのマウント指定が必要。 IDに自動設定するため、何もしないと 127.0.0.1 宛ての fetch が ApplicationLoadBalancedFargateService は ECONNREFUSED になる。 essential: false の init container 構成に不向き。 対処 対処 ENV HOSTNAME=0.0.0.0 Dockerfile に追加(ローカル / ECS本番どちらも必須) ECSでのinit containerを利用したOpenTelemetry自動計装 FargateTaskDefinition + addContainer を直接組み立てて、起動順序とマウントを明示的に制御 13 / 16
  15. 15 — 現在のステータスと今後 ステータス / Next Steps 実装 & ローカル

    E2E検証 完了 AWS 実デプロイ & X-Ray トレース確認 完了 AWS にデプロイし、ALB 経由のリクエストが X-Ray サービスマップ / Traces に表示されることを確認。以下はゼロから再現する場合の手順。 デプロイ手順 $cd infra $npm install $npx cdk bootstrap terminal デプロイ後に確認したこと 1 ALB の DNS名に curl(/ と /api/hello) 2 数分後、X-Ray コンソールのサービスマップで nextjs-app のト レースを確認 $npx cdk deploy ECSでのinit containerを利用したOpenTelemetry自動計装 15 / 16
  16. 16 — TAKEAWAYS 持ち帰れること 01 02 ECS Fargate でも init

    コンテナ + 共有ボリュームで Node.js の自動計装はコード変更なしで動く Next.js standalone は HOSTNAME=0.0.0.0 を忘れる と内部 fetch が落ちる ADOT イメージは自動コピーしないため cp -a を明示。dependsOn で起動 Docker が HOSTNAME をコンテナIDに上書きするため。ローカル / ECS 順を制御。 共通の必須設定。 03 04 Application Signals は開発環境のコストで判断しない (追加の学びを記入) 差し替え用の枠 リクエスト課金は本番トラフィックでスケールする。料金体系を分解してから 採用判断。 ECSでのinit containerを利用したOpenTelemetry自動計装 16 / 16