Timee Product Team Blog

タイミー開発者ブログ

ECS FargateでスタンドアロンなDatadog Agentを運用してDatabase Monitoringを適用する方法とマルチアカウント運用における工夫

はじめに

この記事は Datadog Advent Calendar 2025  9日目の記事です。

こんにちは!絶賛採用中 のタイミーのDevPlatformチームの @MoneyForest です。

今回は、ECS Fargate上でスタンドアロンなDatadog Agentをホストし、Database Monitoring(DBM)を活用してAurora MySQLのオブザーバビリティを向上した取り組みについてご紹介します。

背景

タイミーではAurora MySQLをメインのデータベースとして運用しています。オブザーバビリティ基盤にはDatadogを採用しており、AWS IntegrationによりCloudWatchメトリクスを収集していますが、データベースのパフォーマンス分析においては限界がありました。

CloudWatchメトリクスの限界

CloudWatchで取得できるメトリクスは、AWS API経由で取得できる情報 になります。つまり、マシンリソースやAWSサービスとしてのAuroraの状態に関する情報が中心となります:

メトリクス 内容
CPUUtilization CPU使用率
FreeableMemory 利用可能メモリ
DatabaseConnections 接続数
ReadIOPS / WriteIOPS I/O操作数
CommitLatency / DDLLatency 各種レイテンシ

一方、実際にデータベースのパフォーマンスを分析する際に重要になってくるのは、InnoDBやperformance_schemaといったMySQL内部のアーキテクチャに基づく情報です。

例えば:

  • どのクエリがどれだけ実行されているか
  • クエリごとのロック待ち時間
  • バッファプールのヒット率
  • InnoDBの行ロック競合

これらはMySQLに直接接続してperformance_schemainformation_schemaSHOW ENGINE INNODB STATUSなどから取得する必要があり、CloudWatch(AWSのレイヤー)では取得できません。(あくまでDatadogに連携できないだけであり、AWSではPerformance Insights という機能が提供されており、そこで一部確認可能です。)

そこで活用するのが、Datadog AgentによるMySQLインテグレーションとDBM(Database Monitoring)です。

Datadog MySQLインテグレーションとDBM

Datadog AgentはMySQLに直接接続し、MySQLインテグレーションを通じてMySQL内部の情報を収集します。

MySQLインテグレーションは、標準機能とDBM(Database Monitoring)機能で構成されています(integrations-core mysql-15.11.0)。

設定ファイルでのDBM機能の有効化は以下のように行います:

instances:
  - host: localhost
    username: datadog
    password: <PASSWORD>
    dbm: true  # この設定でDBM機能が有効化される

標準機能で取得できる情報

標準機能では以下の情報を収集します:

機能 概要 公式ドキュメント
Metrics スループット、接続、エラー、InnoDBメトリクスに関連するメトリクス Data Collected

DBM有効化で追加される機能

dbm: true を設定すると、クエリレベルのメトリクス、ライブおよび履歴クエリスナップショット、待機イベント分析、データベース負荷、クエリ実行計画を使えるようになります。(mysql.py#L429-L434)。

if self._config.dbm_enabled:
    dbm_tags = list(set(self.service_check_tags) | set(tags))
    self._statement_metrics.run_job_loop(dbm_tags)
    self._statement_samples.run_job_loop(dbm_tags)
    self._query_activity.run_job_loop(dbm_tags)
    self._mysql_metadata.run_job_loop(dbm_tags)
機能 概要 公式ドキュメント
追加のQuery Metrics 標準機能よりさらに詳細なクエリレベルのメトリクス Data Collected で (DBM only)と書かれているメトリクス
Query Samples 実行されたクエリのスナップショット。実際のパラメータ付きクエリ、Explainプラン、コスト情報を確認可能 Exploring Query Samples
Database Hosts ホストごとのアクティブな接続、ブロッキングクエリ、待機イベントを可視化。クラスタトポロジも表示 Exploring Database Hosts
Schema Explorer テーブル構造、カラム、インデックス、外部キーを確認。スキーマの変更履歴も追跡可能(collect_schemas: enabled: trueで有効化) Exploring Database Schemas

これらの情報を活用することで、「CPUが高い」という現象から「このテーブルのこのクエリがインデックスなしでフルスキャンしている」という原因まで、Datadogという1つのプラットフォーム上で一気通貫で追跡できるようになります。APMとDBMを繋げる機能 などもあるため、APMからEXPLAINまで見ることができ非常に便利です。

次に、弊社におけるECS Fargate環境でDBMをホスティングする際の運用にまつわる課題と工夫を見ていきます。

DBMをECS Fargateでホスティングする際の課題

タイミーではコンピューティング基盤としてECS Fargateをメインで採用しています。

DBMを導入する以前から、APMやログ収集のためにDatadog Agentをサイドカー構成で運用していました。

flowchart TB
    subgraph task["ECS Task (Fargate)"]
        app["Application Container"]
        agent["Datadog Agent (Sidecar)"]
    end

この既存のサイドカーにDBM機能を追加することも技術的には可能です。しかし、サイドカー方式はAPMやログ収集といったアプリケーション単位の監視に適している一方、DBMはデータベース単位の監視であり、役割が異なります。DBM機能をサイドカーに同居させると以下の問題が想定されます

  • 接続数の爆発: タスク数分のDB接続が発生し、max_connectionsを圧迫しそう
  • Autodiscoveryの重複: 各サイドカーが個別にAuroraクラスタを検出し、無駄なAuroraのAPI呼び出しが発生しそう
  • メトリクスの重複: 複数Agentが同じDBから収集し、メトリクスやイベントが重複してしまう可能性がありそう

スタンドアロン構成の必要性

これらの問題を踏まないため、DBM専用のスタンドアロンなDatadog Agentを別のECSサービスとして構築することにしました。(DBM用のEC2を立ち上げるなどの手段もありますが、運用面を考えると避けたいところでしょう。)

平たくいうとDatadog Agentをサイドカーではなくメインコンテナとして1タスクだけ別のサービスとして立ち上げるというものです。以後これを便宜的にスタンドアロン構成と呼称します。

flowchart TB
    subgraph appTasks["Application ECS Tasks (Fargate)"]
        subgraph task1["Task ×N"]
            app1["App + Datadog Agent (Sidecar)"]
        end
        note1["Agentの役割: APM/ログ収集"]
    end
    subgraph dbmTask["Datadog DBM ECS Task (Fargate)"]
        subgraph task2["Task ×1"]
            agent2["Datadog Agent (Standalone)"]
        end
        note2["Agentの役割: DBM"]
    end

スタンドアロン構成であれば、1つのAgentがリージョン内のAuroraクラスタを自動検出しメトリクスを収集するため、先に挙げた懸念は考慮しなくて良くなります。

Fargateにホストする方法ですが、Datadogの公式ドキュメント(Setting Up Database Monitoring for Aurora managed MySQL)にはDocker向けの手順が用意されており、Docker Labelsを使用した定義が紹介されています。

FROM gcr.io/datadoghq/agent:7.36.1

LABEL "com.datadoghq.ad.check_names"='["mysql"]'
LABEL "com.datadoghq.ad.init_configs"='[{}]'
LABEL "com.datadoghq.ad.instances"='[{"dbm": true, "host": "<AWS_INSTANCE_ENDPOINT>", "port": 3306,"username": "datadog","password": "ENC[datadog_user_database_password]"}]'

タイミーでは複数のAWSアカウントでDBMを運用しており、環境ごとにAuroraのエンドポイントやDatadogのタグなどが異なります。

公式手順のDocker Labelsではシンタックスハイライトなどが効かないため、設定のミスが多くなりそうですし、環境ごとにDockerfileを用意するのも冗長です。

そこでDocker Labelsではなく、環境ごとのconf.yamlを生成してDatadog AgentのDockerイメージのconf.d/mysql.dに焼く方式を採用しました。

生成にはCUEを使用することでミスのないコンフィグを作成しやすくしています。

ここからは、実際のECSタスク定義やAurora Autodiscoveryの設定、CUEによる設定生成など、具体的な実装を紹介します。

アーキテクチャ

まず、全体のアーキテクチャを示します。

flowchart TB
    subgraph aws["AWS Account"]
        subgraph ecs["ECS Cluster"]
            subgraph task["Datadog Agent Task (Fargate)"]
                agent["datadog-agent<br/>- DBM enabled<br/>- Autodiscovery"]
            end
        end
        aurora[("Aurora MySQL<br/>(Autodiscovered)")]
        ssm["SSM Parameter Store<br/>- DD_API_KEY<br/>- DATABASE_PASSWORD"]
    end
    datadog["Datadog<br/>(Metrics)"]

    agent --> aurora
    agent --> datadog
    ssm -.-> task

ディレクトリマップ

次にディレクトリ構成を示します。

datadog-dbm/
├── Dockerfile
├── etc/
│   └── datadog-agent/
│       ├── datadog.yaml                    # Agent全体の設定
│       └── conf.d/mysql.d/
│           ├── schema.cue                  # CUE共通スキーマ
│           └── environments/               # 環境ごとの差分
│               ├── product-a-prod.cue
│               ├── product-a-stg.cue
│               └── ...
└── opt/
    ├── secrets.sh                          # シークレット展開スクリプト
    └── secrets.json.tmpl                   # シークレットテンプレート

それでは、各コンポーネントの実装を見ていきましょう。

実装の詳細

1. Datadog Agent設定

まず、Datadog Agentの設定ファイル(datadog.yaml)でDBMとAurora Autodiscoveryを有効化します:

site: datadoghq.com
database_monitoring:
  autodiscovery:
    aurora:
      enabled: true
      region: ap-northeast-1
secret_backend_command: /opt/secrets.sh
dogstatsd_metrics_stats_enable: true

ポイント

  • database_monitoring.autodiscovery.aurora.enabled: true で、リージョン内のAuroraクラスタを自動検出
  • secret_backend_command でシークレット管理を外部スクリプトに委譲

2. シークレット管理

データベースのパスワードは、Datadog Agentの標準機能であるSecrets Managementを活用して取得しています。

本実装ではsecret_backend_commandで独自スクリプトを使用しています。なお、Agent 7.70以降ではsecret_backend_typeを使うことで、AWS Secrets Manager等に直接アクセスできるようになっています。

/opt/secrets.sh

#!/usr/bin/env bash
set -eu
cat /opt/secrets.json.tmpl | envsubst

/opt/secrets.json.tmpl

{
  "DATABASE_PASSWORD": {
    "value": "${DATABASE_PASSWORD}"
  }
}

この仕組みにより:

  1. ECSタスク定義でSSM Parameter StoreからDATABASE_PASSWORDを環境変数として取得
  2. Datadog Agentがsecret_backend_commandを実行
  3. envsubstで環境変数を展開し、JSONとしてAgentに渡す

3. Dockerイメージ

FROM datadog/agent:7.72.2

RUN apt update && echo Y | DEBIAN_FRONTEND=noninteractive apt install -y gettext

COPY ./etc /etc/
COPY ./opt /opt/

RUN chown -R dd-agent:root /var/log/datadog/
RUN chmod 700 /opt/secrets.sh

gettextパッケージはenvsubstコマンドを使うためにインストールしています。

4. ECSタスク定義

{
  "containerDefinitions": [
    {
      "name": "datadog-agent",
      "image": "<ECR_REGISTRY>:latest",
      "dockerLabels": {
        "com.datadoghq.ad.check.id": "_dbm_mysql_aurora"
      },
      "environment": [
        { "name": "ECS_FARGATE", "value": "true" }
      ],
      "secrets": [
        { "name": "DD_API_KEY", "valueFrom": "/datadog/DD_API_KEY" },
        { "name": "DATABASE_PASSWORD", "valueFrom": "/datadog/DATABASE_PASSWORD" }
      ],
      "essential": true
    }
  ],
  "cpu": "2048",
  "memory": "4096",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"]
}

ポイント

  • シークレットはSSM Parameter Storeから取得

5. Aurora側の設定

DBMを利用するためには、Aurora側にも設定が必要です:

  • DBパラメータグループでperformance_schemaを有効化
  • Datadog Agent用のMySQLユーザー作成と権限付与(GRANT)

詳細な手順は公式ドキュメントを参照してください:

参考: Setting Up Database Monitoring for Aurora managed MySQL

基本的な実装は以上ですが、タイミーでは実際に複数環境でこの構成で運用しています。次に、マルチアカウント運用における設定管理の工夫を紹介します。

マルチアカウント運用:CUEによる設定生成

タイミーでは複数のAWSアカウントでこの構成を運用しています。

課題となったのは、環境ごとに異なるDatadog Agentの設定ファイル(conf.d/mysql.d/conf.yaml)をどう管理するかという点です。各環境で以下のような差分があります:

  • AWSアカウント名(タグに使用)
  • schemas_collectionの有効/無効(プロダクトにより必要性が異なる)

CUEによる設定管理

この課題を解決するため、CUEを使って設定を管理しています。

etc/datadog-agent/conf.d/mysql.d/
├── schema.cue              # 共通スキーマ定義
└── environments/
    ├── product-a-prod.cue  # 環境ごとの差分
    ├── product-a-stg.cue
    ├── product-b-prod.cue
    └── ...

共通スキーマ(schema.cue)

package datadog

#DatadogConfig: {
  ad_identifiers: ["_dbm_mysql_aurora"]
  init_config: {}
  instances: [#Instance]
}

#Instance: {
  host:     "%%host%%"
  port:     "%%port%%"
  username: "datadog"
  password: "ENC[DATABASE_PASSWORD]"
  dbm:      true
  // schemas_collectionが有効な場合のみブロックを含める
  if schemas_collection_enabled {
    schemas_collection: {
      enabled: true
    }
  }
  aws: {
    instance_endpoint: "%%host%%"
  }
  tags: [
    "dbclusteridentifier:%%extra_dbclusteridentifier%%",
    "region:%%extra_region%%",
    "account:\\(account)"  // CUEの文字列補間
  ]
}

// 環境差分として定義する変数
schemas_collection_enabled: bool
account: string

環境ごとの差分(例:product-a-prod.cue)

package datadog

config: #DatadogConfig

// 環境差分
account: "product-a-prod"
schemas_collection_enabled: true  // product-aはスキーマ収集を有効化

環境ごとの差分(例:product-b-stg.cue)

package datadog

config: #DatadogConfig

// 環境差分
account: "product-b-stg"
schemas_collection_enabled: false  // product-bは無効

設定ファイルの生成

デプロイ時にCUEコマンドでYAMLを生成します:

cue export -e config \\
  ./etc/datadog-agent/conf.d/mysql.d/schema.cue \\
  ./etc/datadog-agent/conf.d/mysql.d/environments/product-a-prod.cue \\
  --out yaml > ./etc/datadog-agent/conf.d/mysql.d/conf_aws_aurora.yaml

CUEを採用したメリット

  1. 型安全性: スキーマ定義により設定ミスを防止
  2. DRY: 共通部分を一箇所で管理し、環境差分のみを各ファイルに記述
  3. 条件分岐: if schemas_collection_enabled のように、フラグに応じた設定の出し分けが可能
  4. 可読性: 環境ファイルは数行で済み、差分が一目瞭然

マルチアカウントへのデプロイ

CDワークフローで環境ごとのconfigファイルを指定してDockerイメージをビルドすることで、1つのリポジトリから複数AWSアカウントのECRにイメージをpushしてデプロイできます。

# .github/workflows/deploy.yml
jobs:
  deploy:
    strategy:
      matrix:
        include:
          - env-name: product-a-prod
          - env-name: product-a-stg
          - env-name: product-b-prod
          - env-name: product-b-stg
    steps:
      - name: Generate configuration
        run: |
          cue export -e config \\
            ./etc/datadog-agent/conf.d/mysql.d/schema.cue \\
            ./etc/datadog-agent/conf.d/mysql.d/environments/${{ matrix.env-name }}.cue \\
            --out yaml > ./etc/datadog-agent/conf.d/mysql.d/conf_aws_aurora.yaml

      - name: Build and push
        # 環境ごとの設定を含んだイメージをビルド・push

      - name: Deploy
        # 各アカウントのECSにデプロイ

これにより、設定は環境ごとに分離しつつ、Datadog Agentのバージョンアップなどの共通作業はまとめて行えるようになりました。

まとめ

ECS Fargateでスタンドアロン構成のDatadog Agentを運用し、DBMを導入することで、Aurora MySQLのオブザーバビリティを向上できました。

Datadogという1つのプラットフォーム上でメトリクスと合わせてダッシュボード、ウィジェットを作成できたり、APMとDBMの結合やExplainの確認など、Performance Insightよりも便利で充実した内容を見ることができます。

また、タイミーにおける以下の工夫点が参考になれば幸いです。

  • ECS FargateではDBMをスタンドアロン構成でホスティング
  • Docker Labelではなくconfを使用する
  • CUEでマルチアカウントの設定差分を型安全に管理

おわりに

Datadog AgentのMySQLインテグレーションはOSSとして公開されています。

datadog-agent 7.69.0にアップデートしたところ、Aurora ReaderのInnodbメトリクス取れなくなる事象が発生し、少しの修正ですがPRを出しました。

DBMは便利ですがたまに壊れたりもしますので、integrations-core を何かあったら直していければなと思います。(この記事で利用者が増えたらいいな)


タイミーでは一緒に働くエンジニアを募集しています!興味のある方はぜひカジュアル面談でお話ししましょう。

採用情報はこちら