Cloud Run で Datadog Agent をサイドカーとして動かす

## はじめに
:::note info
この記事は、「[Cloud RunでOpenTelemetry Collectorをサイドカーとして動かす](https://zenn.dev/google_cloud_jp/articles/20230516-cloud-run-otel)」を参考に執筆しています。
:::

こんにちは、Datadog Japan で Sales Engineer をしている [**AoTo**](https://qiita.com/AoTo0330) です。

今回は先日**パブリックプレビューとして発表**された、[Cloud Run でサイドカーをデプロイする機能](https://cloud.google.com/run/docs/deploying?hl=en#sidecars)を利用して Datadog Agent をデプロイしてトレースデータを Datadog に送信してみました:dog:[^1]

[^1]:この手順に準じた各注意点は、「[Cloud Run に Datadog Agent をサイドカーでデプロイする際の注意点](https://zenn.dev/aotolog/articles/cr-sidecar-dda-notes)」にまとめています。

:::note warn
この手順は技術検証を目的としており、**公式ではサポートされていません**。

Datadog は [Cloud Run ドキュメント](https://docs.datadoghq.com/ja/serverless/google_cloud_run/)の通り、専用のエージェントを用いた **Cloud Run シングルコンテナ**のトレース・ログ・カスタムメトリクスの送信を正式にサポートしています。(2023年8月17日に**一般公開(GA)** されました)
:::

:::note info
~~公式には別のサイドカー専用コンテナイメージを利用する方法が [**Private beta**](https://www.datadoghq.com/private-beta/google-cloud-run-sidecar/) で公開されています。(2024/7/10時点)~~
サイドカーコンテナを用いた Cloud Run の監視は 2025年2月に GA(一般公開)となりました🎉🎉🎉🎉
:::


また、Google Cloud のリソースや Cloud Run のメトリクスデータを Datadog に収集したい場合は、[Google Cloud Integration](https://docs.datadoghq.com/ja/integrations/google_cloud_platform/#log-collection) をご活用ください。インテグレーションのアーキテクチャについては「[3大クラウドのDatadog Integrations アーキテクチャ](https://qiita.com/AoTo0330/items/545a229fd33d92c01562)」で解説しています。

https://qiita.com/AoTo0330/items/545a229fd33d92c01562

## Cloud Run のサイドカーデプロイ
Google Cloud の Cloud Run でサイドカーがデプロイ可能になり、マルチコンテナ構成が可能になりました。
ただし、外部からの通信を受け取れる **Ingress コンテナは1つまで**しかデプロイできず、**サイドカーコンテナは localhost で通信**を行う必要があります。

そのため、以下の[ユースケース](https://cloud.google.com/run/docs/deploying?hl=en#use_cases)でサイドカーを利用できるようになります。
> - アプリケーションの監視、ロギング、トレース
> - アプリケーションコンテナの前でNginx、Envoy、またはApache2をプロキシとして使用する
> - 認証および認可フィルターの追加 (Open Policy Agent など)
> - Alloy DB Auth プロキシなどのアウトバウンド接続プロキシの実行

今回はこの内、「アプリケーションの監視、ロギング、トレース」の用途で Datadog Agent をサイドカーとしてデプロイし、Python アプリケーションのトレースデータを Datadago に送信するところまでやってみました。

この時、Cloud Run 内のリソースは図のようなアーキテクチャとなります。
![cr-sidecar-dda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/e682ca97-2372-28e9-5425-408624235fb3.png)

## コンテナイメージの準備
今回は、[Datadog の公式ガイド](https://docs.datadoghq.com/ja/tracing/guide/tutorial-enable-python-containers/)で公開されている[チュートリアル用の Calendar Python アプリケーション](https://github.com/DataDog/apm-tutorial-python/tree/main/calendar_app)をもとに Docker イメージを作成して、Datadog Agent と共に Cloud Run マルチコンテナでデプロイします。

https://github.com/DataDog/apm-tutorial-python/tree/main

[Docker に対応した Datadog Agent](https://docs.datadoghq.com/ja/containers/docker/?tab=%E6%A8%99%E6%BA%96) は [Amazon ECR](https://gallery.ecr.aws/datadog/agent)・[Docker Hub](https://hub.docker.com/r/datadog/agent)・[Container Registry (GCR)](https://console.cloud.google.com/gcr/images/datadoghq/GLOBAL/agent)のパブリックレジストリ上で公開されています。

アプリケーション用の`Dockerfile`はこのようになります。
```dockerfile:Dockerfile.app
FROM python:3

ENV DD_SERVICE="calendar"
ENV DD_ENV="dev"
ENV DD_VERSION="0.1.0"

WORKDIR /home

COPY requirements.txt /home
COPY /calendar /home/calendar

RUN pip install -r requirements.txt

# Run the application with Datadog
CMD ["ddtrace-run", "python", "calendar/app.py"] 
```
```txt:requirements.txt
flask==2.2.2
psycopg2-binary==2.9.6
requests==2.28.1
ddtrace
```

アプリケーションには手を加えず、`Dockerfile`に Python トレーサーをインストールし必要な環境変数を定義します。トレーサーはデータをデフォルトで `http://localhost:8126` に送信するようになっています。

これにより、サイドカーとしてデプロイされた Datadog Agent を経由してトレースデータを Datadog に送信することができます。

https://docs.datadoghq.com/ja/tracing/trace_collection/dd_libraries/python/


次に、Datadog Agent 用の`Dockerfile`はこのようになります。
```dockerfile:Dockerfile.dd
FROM gcr.io/datadoghq/agent:latest
COPY config.yaml /etc/datadog-agent/datadog.yaml

EXPOSE 8126

ENV DD_API_KEY=<DD_API_KEY>
ENV DD_SITE=datadoghq.com
ENV DD_APM_ENABLED=true
```
ここでは明示的にトレースデータを受信するポートとしてデフォルトの`8126`ポートを`EXPOSE`しています。
`<DD_API_KEY>`には利用している Datadog Organizations で発行した API key の値を入れてください。安全な方法としては、[Secret Manager](https://cloud.google.com/build/docs/securing-builds/use-secrets?hl=ja) を利用して API Key を参照してください。

以上の内容で、2つの Docker イメージをビルドして Cloud Run 上からアクセス可能なコンテナレジストリに保存すれば準備は完了です。

## Cloud Run へのデプロイ
Cloud Run へのデプロイは以下のコマンドを利用して、YAML ファイルの内容に基づいてデプロイを行います。

```
gcloud run services replace multicontainers.yaml --region asia-northeast1
```

YAML ファイルの記述は以下のようになります。

```yaml:multicontainers.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
    run.googleapis.com/launch-stage: BETA
  name: datadog-sidecar
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/minScale: "1"
        run.googleapis.com/cpu-throttling: "false"
        run.googleapis.com/execution-environment: gen2
        run.googleapis.com/container-dependencies: '{"calendar":["dd-agent"]}'
    spec:
      containers:
        - image: ${REGISTRY}/dd-agent:latest
          name: dd-agent
        - image: ${REGISTRY}/calendar:latest
          name: calendar
          ports:
            - containerPort: 8080
```

この YAML ファイルでは、`annotations`で以下の内容を定義しています。

- `cpu-throttling`で各コンテナに CPU が常に割り当てられる[^2]
- `container-dependencies`で Datadog Agent の起動後にアプリケーションとトレーサーが起動する

[^2]:`resouces:requests:` `resouces: limits:` で使用する CPU・メモリの大きさを明示的に指定できます。

:::note warn
`container-dependencies`は[公式ドキュメント](https://cloud.google.com/run/docs/configuring/containers#container-ordering)のまま記載すると`type error`となるため、`""` や `''` で依存関係の記述を囲うようにしてください。
:::

この内容を含めることで、Datadog Agent が準備された状態でアプリケーションが起動し、Agent に常にリソースが割り当てられた状態となるので、アプリケーションのトレースデータをアプリケーションの起動時から常に Datadog に送信することができます。

## Datadog でのトレースデータの確認
デプロイが完了し、アプリケーションにリクエストを送信すると、Datadog の [APM] > [Traces] からリアルタイムでトレースデータを確認することができます。

Datadog 上ではトレースデータは Flame Graph によって可視化され、それぞれの処理でかかった時間が分かりやすく表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2363567/211af2ea-7fbd-cf97-45da-c60b4ef74512.png)

:::note warn
サイドカーデプロイの場合、Google Cloud Integration を経由して Cloud Run のメトリクスデータを取得することができません。(2023/5/20 現在)
Infrastructure タブからメトリクスデータを参照したい場合は [Datadog 公式の Cloud Run ドキュメント](https://docs.datadoghq.com/ja/serverless/google_cloud_run/)を参考に、シングルコンテナでのデプロイをご検討ください。
:::

## サイドカーデプロイのメリット
ここまでサイドカーデプロイでの Datadog Agent の利用方法を説明してきましたが、そもそもサイドカーを利用するメリットは何なんでしょうか？
ここでは最後に、Google のコンテナによる分散システムのデザインパターンに関する論文 [Design patterns for container-based distributed systems](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/45406.pdf) を参考に、サイドカーパターンでコンテナをデプロイするメリットを、監視エージェントに利用することを念頭にまとめました。


- アプリケーションに優先的にリソースを与えて、エージェントは最小限のリソースで稼働できる
- コンテナの単位でデプロイを分離し、それぞれのアップグレードやロールバックを独立して行える
- コンテナの単位で依存関係を分離し、エージェントの障害によるアプリケーションへの影響を最小限に留めることができる
- コンテナの単位で責任範囲や所有を分離し、エージェントとアプリケーションを別チームで管理することができる
- 単一のエージェントコンテナを用意することで、複数のアプリケーションの監視に再利用できる

特に、Cloud Run のようなサーバレスなサービスを利用する場合、アプリケーションはリクエストに応じてスケールし、エージェントは一定のリソースを利用して稼働するようなことができれば理想的かもしれません。

## おわりに
今回、Cloud Run でサイドカーが利用できるようになったことで、Datadog Agent もサイドカーとしてデプロイすることができることがわかりました。**パブリックプレビュー**とはなりますが、Cloud Run と Datadog をご利用になる際は是非ご検討ください。

また、繰り返しとはなりますが Datadog Agent による Cloud Run のトレース・ログ・カスタムメトリクスの収集は、**シングルコンテナ**での実装が [Datadog 公式の Cloud Run ドキュメント](https://docs.datadoghq.com/ja/serverless/google_cloud_run/)によって提供されています。シングルコンテナの構成で問題がない場合は是非こちらの方法もご検討ください。