TL;DR
- Cloud Runでサイドカー機能が23/05/16にプレビューが発表されました
- サイドカーコンテナとしてdatpadog agentを並走させ、APMのトレースを取得を試しました
About
Cloud Runにサイドカーがプレビューとしてリリースされました。
モニタリングやプロキシなど、Cloud Runで対応が難しかったケースへの大きな選択肢になります。
今回はCloud Runのサイドカーとして、datadog agentを立てAPMのトレースを取得を行います。
いままでのトレースの取得方法
Cloud Run(やコンテナ実行環境)でdatadogのAPMは パブリックベータ として使用可能です。
どの様にdatadog agentのプロセスを扱うかと言うと、コンテナ実行時のコマンドを(ランタイムやバイナリではなく)datadogが提供するプロセスに対してキックする形で利用可能です。
例えばgolangであれば以下のようなDockerfileになります。
FROM alpine # docker hubのdatadog/serverless-initイメージからdatadog-initを取得 COPY --from=datadog/serverless-init /datadog-init /app/datadog-init : # 取得したdatadog-initを使用してバイナリを実行 ENTRYPOINT ["/app/datadog-init"] CMD ["/path/to/your-go-binary"]
ref: https://docs.datadoghq.com/serverless/google_cloud_run/?code-lang=go#install-agent-with-dockerfile
機能として必要十分ではありますが、これはアンチパターンや最終手段ではないかなと個人的に感じていました。
また、親プロセスとしての実行を要求するサービスが増えてしまうと複雑なイメージになってしまい「1コンテナ1プロセス」もしくは「1コンテナ1つの関心事」の掟を破ってしまうこと(アプリケーションの実行と監視の2(以上)つの関心事を持ったコンテナになってしまうこと)に違和感を感じていました。
このアップデートは最後の1ピースとして埋まってくれ、個人的にCloud Runが技術選定の際の最初の選択肢になりました。
Version
- datadog agent
- datadog/agent:7
- python
- python:3.12.0b1-slim
- ddtrace
- 1.13.4
コード
learn-gcp/cloudrun.yaml at main · y-ohgi/learn-gcp
構築
実行用コードの用意
DataDogの公式を参考にPythonで動かします。
Getting Started with Tracing
from flask import Flask app = Flask(__name__) @app.route('/') def home(): return 'hello world!' if __name__ == '__main__': app.run(host='0.0.0.0', port=5050)
# syntax=docker/dockerfile:1 FROM python:3.12.0b1-slim WORKDIR /app RUN <<EOL apt-get update apt-get -y install build-essential pip install flask pip install ddtrace EOL COPY . . EXPOSE 5050 CMD ["ddtrace-run", "python", "hello.py"]
ローカル環境の構築
同じく公式を参考にdocker-compose.yamlを書きます。
Compose and the Datadog Agent
version: "3.9" services: app: build: . environment: - DD_SERVICE=hello - DD_AGENT_HOST=datadog - DD_ENV=local volumes: - .:/app:delegated ports: - "5050:5050" datadog: image: datadog/agent:7 environment: - DD_API_KEY=${DD_API_KEY} - DD_SITE=ap1.datadoghq.com - DD_APM_ENABLED=true volumes: - /var/run/docker.sock:/var/run/docker.sock - /proc/:/host/proc/:ro - /sys/fs/cgroup:/host/sys/fs/cgroup:ro
ローカル環境での実行
APIキーを作成し、環境変数へ格納し、docker-composeを起動します。
export DD_API_KEY=<DATADOG_API_KEY> docker compose up
ローカルでFlaskを叩き、暫く待ってからAPMにトレースが反映されることを確認します。
curl localhost:5050
Cloud Runで実行
前提
GCPの各種APIは有効化されていることを前提とします
Artifact Registryへイメージをpush
Artifact Registryへ認証を行います。
gcloud auth configure-docker \ asia-northeast1-docker.pkg.dev
Dockerfileのbuildとpushを行います。
docker build -t asia-northeast1-docker.pkg.dev/<PROJECT>/learn/hello-py . docker push asia-northeast1-docker.pkg.dev/<PROJECT>/learn/hello-py
Secret ManagerへDataDogのAPIキーを追加
Cloud Runで使用するDataDogのAPIキーをSecret Managerへ保管します
echo -n ${DD_API_KEY} | gcloud secrets create dd-api-key2 --data-file=-
Cloud RunからSecret Managerへのアクセス権限を追加
プロダクションであれば新しくIAMを追加するべきですが、今回はCloud RunのデフォルトIAMへSecret Managerのアクセスロールを追加します。
gcloud projects add-iam-policy-binding <PROJECT_ID> \ --member user:<USER_EMAIL> \ --role roles/secretmanager.secretAccessor
Cloud Runのデプロイ
Cloud Run設定用yamlを書きます。
# cloudrun.yaml apiVersion: serving.knative.dev/v1 kind: Service metadata: name: python-with-datadog annotations: # 現状サイドカーはプレビューなので、プレビュー機能の有効化 run.googleapis.com/launch-stage: BETA spec: template: metadata: annotations: run.googleapis.com/execution-environment: gen2 run.googleapis.com/container-dependencies: '{"app":["datadog"]}' run.googleapis.com/cpu-throttling: "false" spec: containers: - image: asia-northeast1-docker.pkg.dev/<PROJECT ID>/learn/hello-py:latest name: app env: - name: DD_SERVICE value: hello - name: DD_ENV value: dev ports: - containerPort: 5050 - image: datadog/agent:7 name: datadog env: # 各リージョンに合わせてドメインを変更 - name: DD_SITE value: ap1.datadoghq.com - name: DD_APM_ENABLED value: "true" - name: DD_HOSTNAME value: cloudrun # Secret ManagerへDataDog APIキーを取得 - name: DD_API_KEY valueFrom: secretKeyRef: name: dd-api-key key: latest
デプロイ
gcloud run services replace cloudrun.yaml --region=asia-northeast1
Cloud Runはデフォルトでは認証が必要なため、公開状態にします。
# policy.yaml bindings: - members: - allUsers role: roles/run.invoker
gcloud run services set-iam-policy python-with-datadog policy.yaml
動作確認
以下のコマンドを実行した際に得られるURLへcurlを行います。
gcloud run services replace cloudrun.yaml --region=asia-northeast1 : New configuration has been applied to service [python-with-datadog]. URL: https://xxxxxxxxxxx-an.a.run.app
curl https://xxxxxxxxxxx-an.a.run.app
DataDogでAPMのトレースを確認して成功です。
制約
個人的に疑問に思った点のまとめです
コンテナの起動順を決められるか
DataDogのような監視やProxyなど、起動順を定義するケースがあります。
それに対してCloud Runのサイドカーは依存関係を定義することが可能です。
spec: template: metadata: annotations: # コンテナ名"app"はコンテナ名"datadog"が起動しているという依存関係を定義 run.googleapis.com/container-dependencies: '{"app":["datadog"]}'
リソース(CPU/Memory)はどう共有するのか
Cloud Run内でコンテナ同士のCPU/Memoryの割り当てを定義できるかについてです。
1つのコンテナがリソースを食いつぶしてしまう(OOM Killerなど)ケースへの考慮です。
これはCloud Runインスタンスだけでなく、各コンテナのリソースを指定することが可能です(ただ。インスタンス内のコンテナのリソースのメトリクス取得はこれから...?
spec: containers: - name: app image: <IMAGE URI> ports: - containerPort: 5050 resources: limits: cpu: 1000m memory: 512Mi - name: datadog image: datadog/agent:7 resources: limits: cpu: 1000m memory: 256Mi
ヘルスチェックは可能か
k8s同様 startupProbe
が使用可能です。
Cloud Runは定義されていない場合、自動的に以下のヘルスチェックを行ってくれます。
containers: - name: app image: <IMAGE> startupProbe: timeoutSeconds: 240 periodSeconds: 240 failureThreshold: 1 tcpSocket: port: 5050
所感
素直に「これが欲しかった!」という所感です。喜ばしい!
Cloud Runはカジュアルにコンテナイメージを動かせて、他のGCPサービスとの連携もスムーズで好きなサービスの1つでした。
ただ、サイドカーが必要な場合はAutopilotを選定していました。Autopolotはカジュアルにコンテナイメージを動かせるわけではないため(IngressやDeploymentの定義など。)、腰が重かったところがあります。
この中間点をCloud Run自身が埋めてくれたというイメージが強いです。
二度目になりますが、個人的にCloud Runが技術選定時の最初の選択肢になりました。