🚧

ECSでDatadog Trace Agentの起動を待つ

2024/12/19に公開

やりたいこと

ECS Fargateで、DatadogのTrace Agentが完全に立ち上がってからアプリを起動するようにしたい。

もう少し詳しく

ECS Fargateで、アプリのコンテナとDatadog Agentのコンテナを入れたタスクを運用している。
Datadog Agentのコンテナは、アプリのAPMトレースをDatadogに転送するために使用している。

Datadog Agent内のTrace AgentというやつがAPMトレースをDatadogに転送する役割を担っているのだが、Trace Agentは立ち上がりが遅い。Trace Agentが立ち上がる前にアプリから送信されたAPMトレースは失われてしまう。

Datadog Agentのコンテナを同時に起動したのでは、アプリ起動直後のトレースが失われてしまうし、
ECSのコンテナの依存関係の設定コンテナの起動順をDatdog Agentのコンテナ→アプリコンテナの順にしても、Trace Agentの起動の遅さに対応できず、やはりアプリ起動直後のトレースが失われてしまう。

この問題を解消するために、Trace Agentの起動を待ってから、アプリを起動するようにしたい。

どうやってTrace Agentが起動したと判断するか

Trace Agentは、デフォルト設定だと、http://localhost:8126でAPMトレースを受け付ける。
つまり、http://localhost:8126にリクエストを送ってレスポンスを得られれば、Trace Agentが起動したと判断できる。
起動したかの判断のためにリクエストを送るエンドポイントは、何かしらのレスポンスが返却されさえすれば何でも良い。ただ、Datadog Agentのバージョンアップで影響を受ける可能性が少ないものが好ましいだろう。

候補は以下:

  • GET /
    • 現行バージョンではエンドポイントが設定されておらず、ステータスコード404のレスポンスが得られる。
  • GET /info
    • Trace Agentの設定情報を返却するエンドポイントが設定されている。ステータスコード200のレスポンスが得られる。
    • 将来のバージョンアップでこのエンドポイントがなくなることは考えづらい。

ちなみに、Datadog Agentの本体プログラムにはヘルスチェックの機能が備わっているが、このヘルスチェック機能はTrace Agentの状態は確認しないので、今回の目的には使えない。

方法1:ECSのヘルスチェックを使う

方法概要:

  • Datadog Agentコンテナのヘルスチェック(healthCheck)に、Trace Agentの起動を確認するコマンドを設定する
  • アプリのコンテナの依存関係(dependsOn)に、Datadog AgentコンテナのHEALTHYを設定する

これによって、以下の順序が保証される。

  1. Datadog Agentコンテナが起動する
  2. Datadog Agentのヘルスチェックが成功する(つまりTrace Agentが起動する)
  3. アプリのコンテナが起動する

なお、ECSでは、依存関係がコンテナの起動に対して定義されている場合、コンテナ停止時の依存関係は逆になる。これは HEALTHY を指定した場合にも当てはまり、今回の場合だとアプリが先に停止してからDatadog Agentコンテナが停止する。

Datadog Agentのヘルスチェックには、以下のコマンドを使用する:

curl -f http://localhost:8126/info` || exit 1

Datadog Agentのコンテナにはcurlコマンドが入っている。

これをECSのタスク定義として書くと以下のようになる:

"healthCheck": {
  "command": [
    "CMD-SHELL",
    "curl -f http://localhost:8126/info || exit 1"
  ]
}

参考: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#container_definition_healthcheck

ヘルスチェックの以下のパラメタは状況に応じて設定する。Trace Agentの起動が遅いことを考えると、startPeriodは設定した方がよいだろう。

  • interval:ヘルスチェックの間隔。デフォルト値は30秒。
  • timeout:ヘルスチェックのタイムアウト。デフォルト値は5秒。
  • retries:ヘルスチェックの再試行回数。デフォルト値は3回。
  • startPeriod:コンテナ起動後してから最初のヘルスチェックを行うまでの待機時間。デフォルトは0秒。

タスク定義の例(関連部分のみ抜粋):

{
  "taskDefinitionArn": ...,
  "containerDefinitions": [
    {
      "name": "app",
      "essential": true,
      "dependsOn": [
        {
          "containerName": "datadog-agent",
          "condition": "HEALTHY"
        }
      ],
      ...
    },
    {
      "name": "datadog-agent",
      "image": "public.ecr.aws/datadog/agent:latest",
      "portMappings": [
        {
          "containerPort": 8126,
          "hostPort": 8126,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      "healthCheck": {
        "command": [
          "CMD-SHELL",
          "curl -f http://localhost:8126/info || exit 1"
        ],
        "interval": 15,
        "timeout": 10,
        "retries": 3,
        "startPeriod": 20
      },
      ...
    }
  ],
  ...
}

方法2:Trace Agentの起動を待つだけのコンテナを追加する [WIP]

方法概要:

  • タスクに、Trace Agentの起動確認を行うコンテナを追加する
    • 依存関係(dependsOn)に、Datadog AgentコンテナのSTARTを設定する
    • Trace Agentの起動を確認できたら、終了コード0で完了する
  • アプリのコンテナの依存関係(dependsOn)に以下を設定する
    • Trace Agent起動確認コンテナのSUCCESS
    • Datadog AgentコンテナのSTART

これによって、以下の順序が保証される。

  1. Datadog Agentコンテナが起動する
  2. Trace Agent起動確認コンテナが起動する
  3. Trace Agent起動確認コンテナがTrace Agent起動したことを確認する
  4. Trace Agent起動確認コンテナが終了コード0で完了する
  5. アプリのコンテナが起動する

Trace Agent起動確認に使うコンテナは、curlコマンドが使えるものを用意する。
curlの以下のオプションを指定することで、リクエストが成功するまでリトライさせることができる。

curl --retry 10 --retry-delay 5 --retry-all-errors http://localhost:8126/info
  • --retry <num>:一時的なエラーが起きた場合にリトライする回数。
  • --retry-delay <seconds>:リトライ間隔。指定しない場合は初期値1秒の指数バックオフ時間でリトライする。
  • --retry-all-errors
  • --retry-connrefused

Discussion