mackerel-agent タスクをコンテナインスタンスごとに起動して ECS のメトリクスを取得する

最近 Mackerel を使って ECS のメトリクスを取得する方法を検証している.ポイントとしては,ALB の動的ポートマッピングを使うところで,コンテナインスタンスの中で複数のタスク(コンテナ)が起動されるため,全てのタスクのメトリクスを取得する必要がある.

パターン

Mackerel を使って ECS をモニタリングする場合,アーキテクチャとしては大きく2パターンが考えられる.

  • パターン1 : mackerel-agent タスクをコンテナインスタンスごとに起動する
  • パターン2 : コンテナインスタンスに mackerel-agent をインストールする

今回の記事では「パターン1 : mackerel-agent タスクをコンテナインスタンスごとに起動する」の検証結果をまとめようと思う.

メリデメ

最初に「パターン1」のメリデメを整理しておく.

  • メリット
    • コンテナインスタンスをプロビジョニングしなくても Mackerel が使える
    • mackerel-agent タスクからコンテナインスタンスのメトリクスを取得できる
    • mackerel-plugin-docker が Docker API からメトリクスを取得するため,動的ポートマッピングでタスクが増えた場合も,基本的なメトリクスは取得できる
  • デメリット
    • 動的ポートマッピングで起動されたタスク特有のメトリクス(mackerel-plugin を使って取得するようなもの)を取得できない

構成図

まず,今回は以下のような構成で検証をした.実際に動かすタスクは Golang で書いたサンプル API で,API Service に乗せた.

f:id:kakku22:20170516004413j:plain

ECS : タスク定義

今回 mackerel-agent という名前でタスク定義を作成した.タスク定義に必要な設定は,全てドキュメントに載っていたので,参考になった.ただし,ドキュメントには -role オプションの記載が無かったため,ここは別途追加している.

mackerel.io

タスク定義の画面としては,以下のようになり,ザッとポイントを挙げておく.

  • コンテナの定義
    • コンテナイメージ
      • mackerel/mackerel-agent を利用する
    • 環境変数
      • apikey = xxx
      • enable_docker_plugin = true
      • auto_retirement = false
      • opts = -v -role=yyy:zzz
    • マウントポイント
      • Docker ホストの /var/run/docker.sock を参照できるようにする
      • Docker ホストの /var/lib/mackerel-agent/ を参照できるようにする
  • ボリューム
    • /var/run/docker.sock
    • /var/lib/mackerel-agent/

f:id:kakku22:20170516004445p:plain

ECS : タスク定義 (JSON)

もし AWS CLI でタスク定義を作成する場合は,以下のように実行する.

$ aws ecs register-task-definition --cli-input-json file://register-task-definition.json

register-task-definition.json はこんな感じに定義した.

{
  "family": "mackerel-agent",
  "containerDefinitions": [
    {
      "name": "mackerel-agent",
      "image": "mackerel/mackerel-agent",
      "cpu": 0,
      "memory": 128,
      "essential": true,
      "mountPoints": [
        {
          "containerPath": "/var/run/docker.sock",
          "sourceVolume": "docker-sock"
        },
        {
          "containerPath": "/var/lib/mackerel-agent/",
          "sourceVolume": "mackerel-agent"
        }
      ],
      "environment": [
        {
          "name": "apikey",
          "value": "xxx"
        },
        {
          "name": "auto_retirement",
          "value": "false"
        },
        {
          "name": "enable_docker_plugin",
          "value": "true"
        },
        {
          "name": "opts",
          "value": "-v -role=yyy:zzz"
        }
      ]
    }
  ],
  "volumes": [
    {
      "host": {
        "sourcePath": "/var/run/docker.sock"
      },
      "name": "docker-sock"
    },
    {
      "host": {
        "sourcePath": "/var/lib/mackerel-agent/"
      },
      "name": "mackerel-agent"
    }
  ]
}

JSON で1点注意するところがあり,管理コンソールでタスク定義 (JSON) を見ると,mountPoints の値が "readOnly": null となっている.このままだと以下のエラーが出たため,削除してから実行した.

$ aws ecs register-task-definition --cli-input-json file://register-task-definition.json

Parameter validation failed: Invalid type for parameter containerDefinitions[0].mountPoints[0].readOnly, value: None, type: <type 'NoneType'>, valid types: <type 'bool'>
Invalid type for parameter containerDefinitions[0].mountPoints[1].readOnly, value: None, type: <type 'NoneType'>, valid types: <type 'bool'>

ECS : サービス定義

サービス定義で意識するのは,タスク配置制約を One Task Per Host (distinctInstance) にするところで,この設定にすることで,コンテナインスタンスに対して必ず1タスクが配置されるようになる.ちなみに 4/26 時点だと,管理コンソールから distinctInstance でタスクを配置しても,コンテナインスタンスに複数のタスクが配置されるというバグがあり,AWS サポート側に報告した.現在は既に修正されている.

f:id:kakku22:20170516004510p:plain

docs.aws.amazon.com

mackerel-plugin-docker とは?

mackerel-agent タスクの環境変数で enable_docker_plugin = true を設定することで,mackerel-plugin-docker が使えるようになる.これは,簡単に言うと Docker のソケットファイル docker.sock に対して Docker API を叩くことによってメトリクスを取得していて,複数コンテナが起動している場合でも問題なく対応できる.メトリクス名としては -name-format name というオプションがデフォルトで設定されているため,コンテナ名で区別することができる.ただ,取得できるメトリクスは限られていて,CPU 関連,メモリ関連,IO 関連となる.

github.com

実際に Mackerel でメトリクスを確認した

上記のように mackerel-agent タスクを起動すると,すぐにメトリクスを確認できるようになる.Docker Memory のグラフを見るとわかりやすいが,途中でサービス定義を変更して,コンテナインスタンスに配置するタスク数を増やしても,ちゃんとメトリクスを取得できていた.

  • Docker CPU
  • Docker Memory
  • Docker BlkIO Bytes
  • Docker BlkIO IOPS

f:id:kakku22:20170516004539p:plain

mackerel-agent タスクだと難しいこと

上記のように,動的ポートマッピングを使う場合でも,タスクごとに CPU 関連などの基本的なメトリクスを取得することができるが,例えば gostats など,mackerel-plugin を使って取得するようなタスク特有のメトリクスを取得できないという課題がある.動的ポートマッピングを使わないのであれば,ポートが決まっているし,Docker の link オプションを使えば良いが,今回の要件を満たすのは難しそうだった.

ロールグラフも難しい

あくまでこれは,コンテナインスタンスのメトリクスなので,Auto Scaling のことを考えると,コンテナインスタンスをあまり意識したくなく,ロール単位でメトリクスを見たくなってくる.ただ,今の状態だとメトリクス名がコンテナごとに異なるため,ロールグラフを作れなかった.もしかしたら,拡張グラフ機能を使えばできるのかもしれないけど,うまく書けなかった.

mackerel.io

まとめ

  • Mackerel を使って ECS をモニタリングする場合,アーキテクチャとしては大きく2パターンある
  • 今回は「パターン1 : mackerel-agent タスクをコンテナインスタンスごとに起動する」を検証した
  • mackerel-agent 用のタスク定義はドキュメントを参照して環境変数やボリュームを設定する
  • 動的ポートマッピングを使う場合でも,タスクごとに基本的なメトリクスは取得できるが,タスク特有のメトリクスは取得できなかった
  • ロール単位でメトリクスを見る方法もうまく実現できなかった
  • 結果として「パターン1」の採用は見送ることにした

次回

実際に採用することにした「パターン2 : コンテナインスタンスに mackerel-agent をインストールする」の検証結果をまとめる予定!

最近書いた ECS 関連記事

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com