Spring Batch + Prometheus + Pushgateway + Grafana + Dockerでアプリケーション監視

概要
Prometheusは基本的に、メトリクス指標を提供するサーバーへ周期的にリクエスト(pull)してメトリクスを収集する。
しかし、Spring BatchのようにCLI形式で周期的に実行されるだけの場合がある。このような場合は個別のIPがないため、周期的なPolling方式ではなく、Prometheusへメトリクスを逆にPushできるようにする必要がある。メトリクスのPushを支援するのがPushgatewayである。
Pushgateway
Prometheusが提供するPushgatewayは、メトリクスをPushできるようにし、PushされたメトリクスをPrometheusがPullingして取得できるようにする仲介者の役割を果たす。この構造により、PushgatewayへPushされたメトリクスをPrometheusが取得できる。

Spring Batchプロジェクト作成
新規プロジェクト作成コマンド
次のようにcurlコマンドを使用してSpring Bootの新規プロジェクトを作成する。
curl https://start.spring.io/starter.tgz \
-d bootVersion=2.7.6 \
-d dependencies=batch,h2 \
-d baseDir=spring-batch-prometheus \
-d groupId=com.devkuma \
-d artifactId=spring-batch-prometheus \
-d packageName=com.devkuma.batch.prometheus \
-d applicationName=BatchPrometheusApplication \
-d javaVersion=11 \
-d packaging=jar \
-d type=gradle-project | tar -xzvf -
上記コマンドを実行するとSpring Batch、H2 Databaseが追加される。
Spring Batch設定
/src/main/java/com/devkuma/batch/prometheus/BatchPrometheusApplication.java
package com.devkuma.batch.prometheus;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
@SpringBootApplication
@EnableBatchProcessing
public class BatchPrometheusApplication {
public static void main(String[] args) {
SpringApplication.run(BatchPrometheusApplication.class, args);
}
}
@EnableBatchProcessingアノテーションを追加してバッチ機能を有効化し、@EnableSchedulingアノテーションも追加してスケジューラ機能を有効化した。
Prometheus関連ライブラリ追加
/build.gradle
// ... 省略 ...
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-batch'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.batch:spring-batch-test'
// Prometheus関連ライブラリ追加
implementation 'io.micrometer:micrometer-registry-prometheus'
implementation 'io.prometheus:simpleclient_pushgateway'
}
// ... 省略 ...
ファイル内の依存ライブラリを見ると、Spring Batch関連ライブラリとPrometheusおよびPushgatewayライブラリが追加されていることが分かる。
Tasklet処理方式のJob構成を実装
簡単なTasklet処理方式のJob構成ファイルを追加する。
/src/main/java/com/devkuma/batch/prometheus/batch/TaskletStepJobConfiguration.java
package com.devkuma.batch.prometheus.batch;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TaskletStepJobConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(TaskletStepJobConfiguration.class);
private Random random;
public TaskletStepJobConfiguration() {
this.random = new Random();
}
@Bean
public Job taskletStepJob(JobBuilderFactory jobBuilderFactory, Step taskletStep1, Step taskletStep2) {
return jobBuilderFactory.get("taskletStepJob")
.start(taskletStep1)
.next(taskletStep2)
.build();
}
}
itemReader、itemWriter処理方式のJob構成を実装
簡単なitemReader、itemWriter処理方式のJob構成ファイルを作成する。
/src/main/java/com/devkuma/batch/prometheus/batch/ItemStepJobConfiguration.java
package com.devkuma.batch.prometheus.batch;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ItemStepJobConfiguration {
// itemReader and itemWriter configuration
}
Jobスケジューラ作成
ここでは必ずしもスケジューラは必要ないが、グラフをより見やすくするため、周期的にデータを送るJobスケジューラを作成する。
/src/main/java/com/devkuma/batch/prometheus/batch/JobScheduler.java
package com.devkuma.batch.prometheus.batch;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class JobScheduler {
// Run taskletStepJob every 10 seconds and itemStepJob every 15 seconds
}
続いて、thread.pool.sizeも設定ファイルへ入れる。
/src/main/resources/application.properties
thread.pool.size=3
前で入れたthread.pool.sizeを使用してThreadPoolTaskScheduler設定ファイルを作成する。
Prometheus設定
次にPrometheus設定を行う。
/src/main/resources/application.properties
prometheus.push.rate=5000
prometheus.job.name=springbatch
prometheus.grouping.key=appname
prometheus.pushgateway.url=localhost:9091
Prometheusのpush周期、Job名、グループキーを入れる。そしてPushgateway URLを設定する。
設定したPrometheus設定値を設定オブジェクトへ反映する。
/src/main/java/com/devkuma/batch/prometheus/config/PrometheusConfiguration.java
package com.devkuma.batch.prometheus.config;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.prometheus.PrometheusConfig;
import io.micrometer.prometheus.PrometheusMeterRegistry;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.exporter.PushGateway;
@Configuration
public class PrometheusConfiguration {
// Configure PushGateway and periodically push metrics
}
Prometheus + Pushgateway + GrafanaサーバーをDockerで起動
次にDockerでPrometheus + Pushgateway + Grafanaサーバーを起動するため、docker-compose.ymlを作成し、Prometheus設定を行う。
docker-compose.yml設定ファイル
/src/prometheus/docker-compose.yml
version: '3.7'
services:
prometheus:
image: prom/prometheus
container_name: 'prometheus'
ports:
- '9090:9090'
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
pushgateway:
image: prom/pushgateway
container_name: 'pushgateway'
ports:
- '9091:9091'
grafana:
image: grafana/grafana
container_name: 'grafana'
ports:
- '3000:3000'
prometheus.yml設定ファイル
/src/docker/prometheus/prometheus.yml
global:
scrape_interval: 5s
evaluation_interval: 5s
scrape_configs:
- job_name: 'springbatch'
honor_labels: true
static_configs:
- targets: ['host.docker.internal:9091'] # pushgateway
テスト環境がmacOSのためPushgatewayのURLをhost.docker.internal:9091としているが、Linuxなどでは異なる場合がある。テスト環境に合わせてURLを入力する。
Docker起動
% cd src/prometheus
% docker-compose up -d
接続実行
-
Pushgateway
- http://localhost:9091
-
Prometheus
- http://localhost:9090
-
Grafana
- http://localhost:3000
- 基本アカウントID/PW: admin/admin
- http://localhost:3000
Pushgateway収集情報確認
Pushgateway(http://localhost:9091)にアクセスすると、spring-batchで収集された情報を確認できる。

Prometheus収集情報確認
Prometheus(http://localhost:9090)にアクセスすると、Pushgatewayを通じて受け取ったspring-batchで収集された情報を確認できる。

Grafana設定
では、spring-batchで収集された情報をGrafanaを通じてより視覚的に表示してみる。
Grafanaデータソース設定
まずデータソースを追加する。

データソースとしてPrometheusを選択する。

PrometheusのData Source追加画面が表示されたら、NameとURLを入力する。
ここでは実装環境がmacOSなのでURLにはhttp://host.docker.internal:9090を入力したが、Linux環境などでは異なる場合があるので注意してほしい。


Grafanaダッシュボード設定および確認
続いてダッシュボード設定をImportで追加する。

用意されたImport JSONファイル(spring-batch-dashboard.json)を選択する。

内容を確認し、Importをクリックする。

ダッシュボード画面へ移動すると、spring-batchメトリクス情報がグラフで見えることを確認できる。

参考
上記のサンプルコードはGitHubで確認できる。