ECSとGoで構築したシステムにDatadogを導入する
追記: GoのアプリケーションをOpenMetricsを使ってObservableにする方法については別エントリを書きました。 → https://songmu.jp/riji/entry/2020-05-18-go-openmetrics.html
ECSとGoで運用しているシステムに対するDatadogの日本語知見があまり無さそうだったので書いてみる。ちなみに以下の環境です。
- ECS on EC2 (not Fargate)
- アプリケーションコンテナのネットワークモードはbridgeモード
- 動的ポートマッピングも利用
背景として3月にNature Remoのインフラアーキテクチャ改善をしていて、その前にもうちょっと監視を整えたほうが良いな、ということでDatadogを導入したのがある。テストがないとリファクタリングできないように、監視がないとアーキテクチャのアップデートもやりづらいという話。元々はCloudwatchで頑張っていたが厳しくなった。今もまだ併用はしているがDatadogに寄せたいと考えている。
元々Datadogで便利そうだなーと思っていたのは、アプリケーション固有のメトリクス監視を簡単に設定できそうであったこと、具体的には「アプリケーションコンテナがhealth endpointでOpenMetrics等を吐いておけば、datadog agentが自動でそれをディスカバリしてDatadog側にメトリクスを送信してくれる」という点。OpenMetricsというのはPrometheusで使われているメトリクスフォーマットのことです。
で、実際以下を実現できたので良かった。
- 監視エージェント含め監視設定を全部ECS上でおこなえるようになった
- ecspressoも導入しているのでタスク定義で完結するようになった
- EC2ホストのプロビジョニングが一切必要なくなった
- アプリケーション側のDocker Labelを設定するだけで勝手に監視が始まる
- 監視エージェント側に設定を追加する必要はない
やったことは主に以下の2つ。メトリクス監視中心に設定した。それぞれ解説していく。
- Datadog Agentの導入
- アプリケーションコンテナの監視設定
Datadog Agentの導入
ECSのEC2モードだとDaemon setのコンテナを各EC2に立てることになる(ちなみにFargateだと当然sidecarになる)。Datadog公式のECSのヘルプに丁寧に設定方法が書いてあるが、ここにタスク定義の雛形があるので、これをコピペして、ECSのDaemonとして立てればいいだけなので非常に簡単。コンテナとして起動するわけだけど、EC2のホストOSの監視もやってくれるので便利。
Datadog Agent側には以降設定を追加する必要もない。アプリケーション側でディスカバリの設定をすれば勝手にAgentが監視対象を見つけて、メトリクスを収集してDatadog側に投げてくれる。これは非常に便利。
アプリケーションコンテナの監視設定
ECSに限らずDatadogでコンテナのカスタム監視設定はDocker Labelを使っておこなう。これは、Docker Integrations Autodiscoveryに書いてある。
ECSの場合については書かれてないが、アプリケーション側のタスク定義のcontainerDefinitions
キー配下に以下のような感じで設定を書けばいいということが分かった。
"dockerLabels": {
"com.datadoghq.ad.instances": "[{\"prometheus_url\":\"http://%%host%%:%%port%%/status/metrics\",\"namespace\":\"api\",\"metrics\":[\"*\"]}]",
"com.datadoghq.ad.check_names": "[\"openmetrics\"]",
"com.datadoghq.ad.init_configs": "[{}]",
"name": "api"
},
これは、APIのコンテナの、http://%%host%%:%%port%%/status/metrics
にアクセスすれば、OpenMetricsフォーマットでメトリクスが取れるということ。%%host%%
や%%port%%
はこれでよくて、動的に補完されてそれをDatadog Agentがよしなに見つけてくれる。
com.datadoghq.ad.instances
のmetricsに、ここでは["*"]
を指定してエンドポイントが吐く全てのメトリクスを取り込むようにしているが、個々の設定を調整して必要なメトリクスのみを取り込むようにできるのも地味に嬉しいポイント。
ちなみに、"com.datadoghq.ad.check_names"に設定できる項目に"openmetrics"じゃなくて"prometheus"というのもあるが、自前でprometheusを立ててる場合でないのなら、"openmetrics"を使うのが今は正解のようです。
com.datadoghq.ad.instances
への設定値は各インテグレーションのヘルプページを参照する。OpenMetricsの場合はここ。
OpenMetrics以外の監視にも当然対応している。社内で導入したのは以下。
memcachedは以下の具合。(実際には社内でmemcachedを使っているわけでなく、katsubushiの監視のためにこの設定を入れている)
"dockerLabels": {
"com.datadoghq.ad.check_names": "[\"mcache\"]",
"com.datadoghq.ad.init_configs": "[{}]",
"com.datadoghq.ad.instances": "[{\"url\": \"%%host%%\",\"port\": \"11212\"}]"
},
また、Nginxだと以下のような感じ。これはタスク定義ではなくDockerfile上にLABELを直書きしているが、こういうことも可能である。
LABEL "com.datadoghq.ad.check_names"='["nginx"]'
LABEL "com.datadoghq.ad.instances"='[{"nginx_status_url":"http://%%host%%:%%port%%/nginx_status"}]'
LABEL "com.datadoghq.ad.init_configs"='[{}]'
このように、監視対象側が監視の口を空けておけば、Datadog Agentが勝手に見つけてメトリクスを収集してくれるのは非常に良い体験だった。
GoアプリケーションがOpenMetricsを吐くようにする
あとはGoアプリケーションがOpenMetricsを吐くようにすればOK。ちなみにDatadogにはexpvarを使ったGoアプリケーション監視のインテグレーションもあるのだが、これは使わなかった。以下の理由。
- goroutineの数が取れない
- アプリケーション固有のカスタムメトリクスの追加ができない
GoのアプリケーションにOpenMetricsを吐くためには、github.com/prometheus/client_golang/prometheus/promhttp
を使うのがお手軽。以下のようにするだけで基本的なメトリクスが出力できる。
import (
"http"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
func main() {
...
http.Handle("/status/metrics", promhttp.Handler())
...
}
カスタムメトリクスの追加もここでは触れませんが簡単です。Prometheusのデータモデルをある程度理解する必要がありますが、その辺りはPromethesの公式ヘルプや書籍に軽く目を通すと良いでしょう。
タグ付け等、メトリクスに対するMulti dimension data modelの考え方はDatadogでも共通なので、この辺りを理解しておけば、Datadog上でダッシュボードを作る際にも役立ちます。この辺りはまた別途エントリを書こうと思う。
監視コンテナの追加
アプリケーションに従属しないカスタムメトリクスを取りたい場合も、監視コンテナを一つ立ててOpenMetricsを吐かせれば簡単に実現できる。これもECSクラスタ上に"watchdog"というサービスを作って1タスクを動かしている。これもecspresso管理でサクッとできるのでお手軽。
(余談)プロビジョニングが消えた
ecspressoとDatadog導入、その他システム改善により、マネージドサービス以外のほとんどのものをECS上で管理できるようにした結果、EC2のプロビジョニングが不要になった。
元々は、監視スクリプトの追加などのためにプロビジョニングを実施していて、Packerを使って定期的にゴールデンイメージを焼く運用だった。しかしそこも仕組み化されきっておらず古いイメージを使い続けてしまうなどの問題もあった。
現在は、Amazon ECS-optimized AMIの最新を使うだけにして、独自のAMI管理をせずとも良くなったので楽になった。
結果として、インスタンスの入れ替えの手間や心理的障壁も減り、2018年から残存していたインスタンスがあったのだがそれを滅ぼすことができた。なんなら2019年に起動したインスタンスもいなくなり、インスタンス台数もかなり削減できた。やっぱ監視系含めてこの辺りちゃんとやるの大事ですね。
Datadog所感
最後にDatadogの所感を書き出しておきます。
Pros
- 改めてだけど、Datadog Agent側の設定を弄らずに、アプリケーション側に設定を書けば勝手に監視が追加されるのは疎結合で嬉しい
- 複雑なグラフやダッシュボードもGUI上で作れて、それをコードとして落とすことができるところもかなり体験が良い
- 直近のアプリケーションメトリクスは5秒毎に更新されるのでdeploy時などの見守りに安心感がある
- グラフの凡例のトグル操作が慣れると便利
- 特定の系列だけの表示や、逆の特定の系列を除いた表示などが簡単にできる
- カスタムメトリクスでカウンター値が直接扱えるのは嬉しい
- カスタムメトリクスも含めてあらゆるメトリクスを長期保存してくれるのは良い
Cons
- OpenMetricsの場合、エンドポイントから値が取れなくなっても、最後の値が5分くらい最新の値として残存してしまう?現象に地味に困っている
- 系列が激しめに入れ替わる場合等にグラフの色の選択がイマイチ
- ダッシュボードがいい感じに画面にフィットしてくれない
- レスポンシブデザイン的になっていない
- 特にモバイル体験が壊滅的…
Consに対しては公式の対応を望むのと、なんか良い方法あれば教えて下さい。
また、この辺りのシステム改善に取り組みたいという方も歓迎なので、ぜひ採用に応募してきて下さい。お待ちしています。