All Articles

Docker上で起動したPrometheusを使って、Micrometerで収集したメトリクス可視化する

Amazon Managed Service for Prometheusが値下げされるという 記事 を見かけて、「そろそろMicrometerのモニタリングシステムをCloud Watchから乗り換えるか」って気持ちになったのでPrometheusをサクッと試してみました。

Prometheusとは

Prometheusは、SoundCloudが2012年に作ったOSSのシステムモニタリングとアラートのツールです。

機能

  • メトリクス名とkey/valueペアによって識別された時系列データを持つ多次元のデータモデル
  • この次元を利用するための柔軟性のあるクエリ言語のPromQLを提供
  • 依存しない分散型ストレージ。シングルサーバノードが独立している
  • メトリクスの収集方法はプル型
  • 中間ゲートウェイ経由でプッシュ型もサポートしている
  • サービスディスカバリや静的な設定経由で、ターゲットが検出される
  • グラフ化やダッシュボード化のいくつかのモードをサポートしている

コンポーネント

Prometheusのエコシステムは複数のコンポーネントから成り立つ

  • メインのPrometheusサーバは時系列データを取得して保存する
  • 計測するアプリケーションコードのためのクライアントライブラリ
  • 一時的なジョブをサポートするためのプッシュゲートウェイ
  • HAProxy, StatsD, Graphite, などのようなサービスのための特別な目的のエクスポーターズ
  • アラートを扱うためのアラートマネージャ
  • 多くのPrometheusコンポーネントはgolangで書かれている

Micrometerとは

以前書いた Micrometerでメトリクスを収集してAmazon Cloud Watchで可視化する にまとめてあるので省略。

アプリケーション作成

メトリクス収集対象のアプリケーションを作ります。今回はSpring Bootで作ります。

まず、build.gradleの依存関係です。PrometheusがActuatorのエンドポイントを叩いてメトリクス情報を収集します。

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
}
view raw build.gradle hosted with ❤ by GitHub

次に、アプリケーションの実装です。

@RestController
@RequestMapping("/")
public class IndexController {
@GetMapping
public IndexResponse index() {
return new IndexResponse("Hello World!!");
}
}
view raw IndexController.java hosted with ❤ by GitHub

アプリケーションを起動して、GET http://localhost:8080を叩くと次のようなレスポンスが返ってきます。
{
"message": "Hello World!!"
}
view raw index.json hosted with ❤ by GitHub

次に、Actuatorの GET /actuator/prometheus エンドポイントを有効にします。Prometheusがこのエンドポイントを叩いてメトリクス情報を収集します。

management:
endpoints:
web:
exposure:
include: prometheus
view raw application.yml hosted with ❤ by GitHub

GET http://localhost/actuator/prometheusを叩くと、Prometheusのフォーマットでメトリクス情報が返ってきます。

Dockerコンテナで起動

docker-compose.ymlを用意して、先に実装したアプリケーションとPrometheusをDockerコンテナ上で起動するようにします。

version: '3'
services:
prometheus:
image: prom/prometheus
container_name: prometheus
volumes:
- ./prometheus:/etc/prometheus
command: "--config.file=/etc/prometheus/prometheus.yml"
ports:
- 9090:9090
restart: always
micrometer-prometheus-api:
image: micrometer-prometheus-api
container_name: micrometer-prometheus-api
ports:
- 18080:8080
view raw docker-compose.yml hosted with ❤ by GitHub

次に、Prometheusの設定ファイルを用意します。 ほぼ、Spring Bootのドキュメントにあるサンプル通りです。

global:
scrape_interval: 10s
scrape_timeout: 10s
evaluation_interval: 10s
scrape_configs:
- job_name: 'micrometer-prometheus'
metrics_path: '/actuator/prometheus'
static_configs:
- targets:
- micrometer-prometheus-api:8080
view raw prometheus.yml hosted with ❤ by GitHub

次に、jibのGradleプラグインを使ってアプリケーションのDockerイメージを作成します。8080番ポートで起動するようにしています。

plugins {
id 'com.google.cloud.tools.jib' version '3.0.0'
}
jib {
container {
ports ['8080']
jvmFlags = ['--enable-preview']
}
from {
image = 'openjdk:15-alpine'
}
to {
image = 'micrometer-prometheus-api'
tags = ['latest']
}
}
view raw build.gradle hosted with ❤ by GitHub

./gradlew jibDockerBuildでDockerイメージを作成します。

それでは、コンテナを起動してみましょう。

$ docker-compose up
prometheus | level=info ts=2021-05-14T04:11:02.765Z caller=main.go:388 msg="No time or size retention was set so using the default time retention" duration=15d
prometheus | level=info ts=2021-05-14T04:11:02.765Z caller=main.go:426 msg="Starting Prometheus" version="(version=2.27.0, branch=HEAD, revision=24c9b61221f7006e87cd62b9fe2901d43e19ed53)"
prometheus | level=info ts=2021-05-14T04:11:02.765Z caller=main.go:431 build_context="(go=go1.16.4, user=root@f27daa3b3fec, date=20210512-18:04:51)"
prometheus | level=info ts=2021-05-14T04:11:02.765Z caller=main.go:432 host_details="(Linux 5.10.25-linuxkit #1 SMP Tue Mar 23 09:27:39 UTC 2021 x86_64 29b273b8d0c7 (none))"
prometheus | level=info ts=2021-05-14T04:11:02.765Z caller=main.go:433 fd_limits="(soft=1048576, hard=1048576)"
prometheus | level=info ts=2021-05-14T04:11:02.765Z caller=main.go:434 vm_limits="(soft=unlimited, hard=unlimited)"
prometheus | level=info ts=2021-05-14T04:11:02.778Z caller=web.go:540 component=web msg="Start listening for connections" address=0.0.0.0:9090
prometheus | level=info ts=2021-05-14T04:11:02.780Z caller=main.go:803 msg="Starting TSDB ..."
prometheus | level=info ts=2021-05-14T04:11:02.788Z caller=tls_config.go:191 component=web msg="TLS is disabled." http2=false
prometheus | level=info ts=2021-05-14T04:11:02.790Z caller=head.go:741 component=tsdb msg="Replaying on-disk memory mappable chunks if any"
prometheus | level=info ts=2021-05-14T04:11:02.794Z caller=head.go:755 component=tsdb msg="On-disk memory mappable chunks replay completed" duration=6.319µs
prometheus | level=info ts=2021-05-14T04:11:02.794Z caller=head.go:761 component=tsdb msg="Replaying WAL, this may take a while"
prometheus | level=info ts=2021-05-14T04:11:02.795Z caller=head.go:813 component=tsdb msg="WAL segment loaded" segment=0 maxSegment=0
prometheus | level=info ts=2021-05-14T04:11:02.795Z caller=head.go:818 component=tsdb msg="WAL replay completed" checkpoint_replay_duration=42.188µs wal_replay_duration=1.023386ms total_replay_duration=1.236444ms
prometheus | level=info ts=2021-05-14T04:11:02.799Z caller=main.go:828 fs_type=EXT4_SUPER_MAGIC
prometheus | level=info ts=2021-05-14T04:11:02.799Z caller=main.go:831 msg="TSDB started"
prometheus | level=info ts=2021-05-14T04:11:02.799Z caller=main.go:957 msg="Loading configuration file" filename=/etc/prometheus/prometheus.yml
prometheus | level=info ts=2021-05-14T04:11:02.805Z caller=main.go:988 msg="Completed loading of configuration file" filename=/etc/prometheus/prometheus.yml totalDuration=6.051413ms remote_storage=2.506µs web_handler=635ns query_engine=1.369µs scrape=2.644871ms scrape_sd=85.53µs notify=1.254µs notify_sd=2.059µs rules=1.15µs
prometheus | level=info ts=2021-05-14T04:11:02.805Z caller=main.go:775 msg="Server is ready to receive web requests."
micrometer-prometheus-api |
micrometer-prometheus-api | . ____ _ __ _ _
micrometer-prometheus-api | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
micrometer-prometheus-api | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
micrometer-prometheus-api | \\/ ___)| |_)| | | | | || (_| | ) ) ) )
micrometer-prometheus-api | ' |____| .__|_| |_|_| |_\__, | / / / /
micrometer-prometheus-api | =========|_|==============|___/=/_/_/_/
micrometer-prometheus-api | :: Spring Boot :: (v2.4.5)
micrometer-prometheus-api |
micrometer-prometheus-api | 2021-05-14 05:25:22.680 INFO 1 --- [ main] c.b.micrometerprometheus.Application : Starting Application using Java 15-ea on aad30f1b5aec with PID 1 (/app/classes started by root in /)
micrometer-prometheus-api | 2021-05-14 05:25:22.684 INFO 1 --- [ main] c.b.micrometerprometheus.Application : No active profile set, falling back to default profiles: default
micrometer-prometheus-api | 2021-05-14 05:25:23.854 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
micrometer-prometheus-api | 2021-05-14 05:25:23.866 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
micrometer-prometheus-api | 2021-05-14 05:25:23.867 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.45]
micrometer-prometheus-api | 2021-05-14 05:25:23.928 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
micrometer-prometheus-api | 2021-05-14 05:25:23.929 INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1182 ms
micrometer-prometheus-api | 2021-05-14 05:25:24.458 INFO 1 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
micrometer-prometheus-api | 2021-05-14 05:25:24.640 INFO 1 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path '/actuator'
micrometer-prometheus-api | 2021-05-14 05:25:24.688 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
micrometer-prometheus-api | 2021-05-14 05:25:24.705 INFO 1 --- [ main] c.b.micrometerprometheus.Application : Started Application in 2.464 seconds (JVM running for 2.963)
micrometer-prometheus-api | 2021-05-14 05:25:26.655 INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
micrometer-prometheus-api | 2021-05-14 05:25:26.655 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
micrometer-prometheus-api | 2021-05-14 05:25:26.657 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms
view raw docker-compose.log hosted with ❤ by GitHub

リクエストログをみてみると、10秒おきにエンドポイントが叩かれてるのがわかります。

2021-05-14 06:05:39.806 DEBUG 1 --- [nio-8080-exec-7] o.s.w.f.CommonsRequestLoggingFilter : Before request [GET /actuator/prometheus]
2021-05-14 06:05:39.816 DEBUG 1 --- [nio-8080-exec-7] o.s.w.f.CommonsRequestLoggingFilter : Request data : GET /actuator/prometheus]
2021-05-14 06:05:49.784 DEBUG 1 --- [nio-8080-exec-9] o.s.w.f.CommonsRequestLoggingFilter : Before request [GET /actuator/prometheus]
2021-05-14 06:05:49.789 DEBUG 1 --- [nio-8080-exec-9] o.s.w.f.CommonsRequestLoggingFilter : Request data : GET /actuator/prometheus]
2021-05-14 06:05:59.785 DEBUG 1 --- [nio-8080-exec-8] o.s.w.f.CommonsRequestLoggingFilter : Before request [GET /actuator/prometheus]
2021-05-14 06:05:59.792 DEBUG 1 --- [nio-8080-exec-8] o.s.w.f.CommonsRequestLoggingFilter : Request data : GET /actuator/prometheus]
2021-05-14 06:06:09.788 DEBUG 1 --- [io-8080-exec-10] o.s.w.f.CommonsRequestLoggingFilter : Before request [GET /actuator/prometheus]
2021-05-14 06:06:09.796 DEBUG 1 --- [io-8080-exec-10] o.s.w.f.CommonsRequestLoggingFilter : Request data : GET /actuator/prometheus]
view raw request-log.log hosted with ❤ by GitHub

PrometheusのUIを確認

ブラウザで、Prometheusにアクセスすると、UIを見ることできます。 「Expression」にPromQLを入力して「Execute」ボタンを押下すると表示されます。

● Table

prometheus_table

● Graph

prometheus_graph

やってみた記事なので、一旦ここまで。

Links