Spring Boot Actuatorは、本番環境でアプリケーションを監視・運用するための強力な機能セットを提供します。本記事では、Actuatorエンドポイントの有効化から、カスタムヘルスインジケータの実装、Prometheus形式でのメトリクスエクスポート、Grafanaダッシュボードとの連携までを実践的に解説します。
実行環境と前提条件#
本記事の内容を実践するにあたり、以下の環境を前提としています。
| 項目 |
バージョン・要件 |
| Java |
17以上 |
| Spring Boot |
3.4.x |
| ビルドツール |
Maven または Gradle |
| IDE |
VS Code または IntelliJ IDEA |
事前に以下の準備を完了してください。
- Spring Bootプロジェクトが作成済みであること
- 基本的なREST APIの実装経験があること
Spring Boot Actuatorとは#
Spring Boot Actuatorは、アプリケーションの健全性監視、メトリクス収集、環境情報の取得などを行うための本番環境向け機能です。主な特徴は以下のとおりです。
- ヘルスチェックエンドポイント: アプリケーションやデータベースの死活監視
- メトリクスエンドポイント: JVM、HTTP、データベースなどのメトリクス収集
- 情報エンドポイント: アプリケーションのバージョン、Git情報の表示
- 環境エンドポイント: プロパティや環境変数の確認
Actuatorの依存関係を追加する#
Mavenの場合#
pom.xmlに以下の依存関係を追加します。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<dependencies>
<!-- Spring Boot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Prometheus形式でのメトリクスエクスポート用 -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
</dependencies>
|
Gradleの場合#
build.gradleに以下を追加します。
1
2
3
4
|
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-registry-prometheus'
}
|
Actuatorエンドポイントの有効化と公開設定#
依存関係を追加しただけでは、すべてのエンドポイントが公開されるわけではありません。application.ymlで適切に設定する必要があります。
基本設定#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# application.yml
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
base-path: /actuator
endpoint:
health:
show-details: when_authorized
show-components: when_authorized
prometheus:
enabled: true
info:
env:
enabled: true
|
設定項目の解説#
| 設定項目 |
説明 |
management.endpoints.web.exposure.include |
HTTP経由で公開するエンドポイントを指定 |
management.endpoints.web.base-path |
Actuatorエンドポイントのベースパス(デフォルト: /actuator) |
management.endpoint.health.show-details |
ヘルスチェックの詳細表示条件 |
management.endpoint.prometheus.enabled |
Prometheusエンドポイントの有効化 |
show-detailsの設定値#
| 値 |
説明 |
never |
詳細を表示しない(デフォルト) |
when_authorized |
認証済みユーザーにのみ詳細を表示 |
always |
常に詳細を表示 |
すべてのエンドポイントを公開する場合#
開発環境では、すべてのエンドポイントを公開することで詳細な情報を確認できます。
1
2
3
4
5
|
management:
endpoints:
web:
exposure:
include: "*"
|
本番環境では必要最小限のエンドポイントのみを公開することを推奨します。
主要なActuatorエンドポイント#
以下は頻繁に使用されるActuatorエンドポイントの一覧です。
| エンドポイント |
パス |
説明 |
| health |
/actuator/health |
アプリケーションの健全性を確認 |
| info |
/actuator/info |
アプリケーション情報を表示 |
| metrics |
/actuator/metrics |
利用可能なメトリクス一覧を表示 |
| prometheus |
/actuator/prometheus |
Prometheus形式でメトリクスをエクスポート |
| env |
/actuator/env |
環境プロパティを表示 |
| loggers |
/actuator/loggers |
ログレベルの表示・変更 |
| beans |
/actuator/beans |
登録されているBeanの一覧 |
ヘルスチェックエンドポイントの詳細#
基本的なヘルスチェック#
アプリケーションを起動して/actuator/healthにアクセスすると、以下のようなレスポンスが返されます。
詳細表示を有効にした場合#
show-details: alwaysを設定すると、詳細な情報が表示されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": {
"database": "PostgreSQL",
"validationQuery": "isValid()"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 499963174912,
"free": 250000000000,
"threshold": 10485760,
"path": "/",
"exists": true
}
},
"ping": {
"status": "UP"
}
}
}
|
自動構成されるヘルスインジケータ#
Spring Boot Actuatorは、依存関係に基づいて以下のヘルスインジケータを自動で構成します。
| インジケータ |
条件 |
| DataSourceHealthIndicator |
DataSourceが存在する場合 |
| DiskSpaceHealthIndicator |
常に有効 |
| RedisHealthIndicator |
Redis接続が設定されている場合 |
| MongoHealthIndicator |
MongoDB接続が設定されている場合 |
| ElasticsearchRestClientHealthIndicator |
Elasticsearch接続が設定されている場合 |
| RabbitHealthIndicator |
RabbitMQ接続が設定されている場合 |
カスタムヘルスインジケータの実装#
外部APIやカスタムリソースの健全性を監視するために、独自のヘルスインジケータを実装できます。
基本的なカスタムヘルスインジケータ#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package com.example.demo.health;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
@Component
public class ExternalApiHealthIndicator implements HealthIndicator {
private final ExternalApiClient externalApiClient;
public ExternalApiHealthIndicator(ExternalApiClient externalApiClient) {
this.externalApiClient = externalApiClient;
}
@Override
public Health health() {
try {
boolean isHealthy = externalApiClient.checkHealth();
if (isHealthy) {
return Health.up()
.withDetail("service", "External API")
.withDetail("status", "Available")
.build();
} else {
return Health.down()
.withDetail("service", "External API")
.withDetail("status", "Unavailable")
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("service", "External API")
.withDetail("error", e.getMessage())
.build();
}
}
}
|
外部APIクライアントの例#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package com.example.demo.health;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component
public class ExternalApiClient {
private final RestTemplate restTemplate;
private static final String HEALTH_CHECK_URL = "https://api.example.com/health";
public ExternalApiClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public boolean checkHealth() {
try {
restTemplate.getForEntity(HEALTH_CHECK_URL, String.class);
return true;
} catch (Exception e) {
return false;
}
}
}
|
データベース接続のカスタムヘルスインジケータ#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package com.example.demo.health;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
private final DataSource dataSource;
public DatabaseHealthIndicator(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public Health health() {
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT 1");
ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
return Health.up()
.withDetail("database", "Connected")
.withDetail("validationQuery", "SELECT 1")
.build();
}
return Health.down()
.withDetail("database", "Query failed")
.build();
} catch (Exception e) {
return Health.down()
.withDetail("database", "Connection failed")
.withDetail("error", e.getMessage())
.build();
}
}
}
|
ヘルスグループの設定#
複数のヘルスインジケータをグループ化して、用途別に異なるエンドポイントで公開できます。
1
2
3
4
5
6
7
8
9
10
11
|
management:
endpoint:
health:
group:
liveness:
include: ping
readiness:
include: db,externalApi
custom:
include: externalApi
show-details: always
|
この設定により、以下のエンドポイントが利用可能になります。
/actuator/health/liveness: Kubernetes Liveness Probe用
/actuator/health/readiness: Kubernetes Readiness Probe用
/actuator/health/custom: カスタムグループ
Prometheusメトリクス形式でのエクスポート#
Prometheusエンドポイントの確認#
micrometer-registry-prometheusを追加すると、/actuator/prometheusエンドポイントが有効になります。
1
|
curl http://localhost:8080/actuator/prometheus
|
以下のような形式でメトリクスが出力されます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="G1 Eden Space",} 4.2991616E7
jvm_memory_used_bytes{area="heap",id="G1 Old Gen",} 1.6777216E7
jvm_memory_used_bytes{area="heap",id="G1 Survivor Space",} 8388608.0
jvm_memory_used_bytes{area="nonheap",id="CodeCache",} 1.4680064E7
# HELP http_server_requests_seconds Duration of HTTP server request handling
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{method="GET",outcome="SUCCESS",status="200",uri="/api/users",} 150.0
http_server_requests_seconds_sum{method="GET",outcome="SUCCESS",status="200",uri="/api/users",} 2.5
# HELP process_cpu_usage The "recent cpu usage" for the Java Virtual Machine process
# TYPE process_cpu_usage gauge
process_cpu_usage 0.0025
|
主要なメトリクス#
| メトリクス名 |
説明 |
jvm_memory_used_bytes |
JVMのメモリ使用量 |
jvm_gc_pause_seconds |
GCの停止時間 |
http_server_requests_seconds |
HTTPリクエストの処理時間 |
process_cpu_usage |
CPU使用率 |
hikaricp_connections_active |
アクティブなDB接続数 |
tomcat_threads_current |
現在のTomcatスレッド数 |
カスタムメトリクスの追加#
Micrometerを使用して、独自のメトリクスを追加できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package com.example.demo.service;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
private final Counter orderCounter;
private final Timer orderProcessingTimer;
public OrderService(MeterRegistry meterRegistry) {
this.orderCounter = Counter.builder("orders.created.total")
.description("Total number of orders created")
.tag("type", "all")
.register(meterRegistry);
this.orderProcessingTimer = Timer.builder("orders.processing.time")
.description("Time taken to process orders")
.register(meterRegistry);
}
public Order createOrder(OrderRequest request) {
return orderProcessingTimer.record(() -> {
// 注文処理ロジック
Order order = processOrder(request);
orderCounter.increment();
return order;
});
}
private Order processOrder(OrderRequest request) {
// 実際の処理
return new Order();
}
}
|
アノテーションを使用したメトリクス収集#
@Timedアノテーションを使用すると、より簡潔にメトリクスを収集できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.example.demo.controller;
import io.micrometer.core.annotation.Timed;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
@Timed(value = "users.list.time", description = "Time taken to list users")
public List<User> getUsers() {
return userService.findAll();
}
}
|
@Timedを有効にするには、TimedAspectをBean登録する必要があります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package com.example.demo.config;
import io.micrometer.core.aop.TimedAspect;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MetricsConfig {
@Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
|
Prometheus + Grafana連携#
Prometheusの設定#
prometheus.ymlに以下のスクレイプ設定を追加します。
1
2
3
4
5
6
7
8
9
10
11
12
|
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'spring-boot-app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['host.docker.internal:8080']
labels:
application: 'demo-api'
environment: 'development'
|
Docker Composeでの構成例#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
networks:
- monitoring
prometheus:
image: prom/prometheus:v2.48.0
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
networks:
- monitoring
grafana:
image: grafana/grafana:10.2.0
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
networks:
- monitoring
depends_on:
- prometheus
networks:
monitoring:
driver: bridge
volumes:
prometheus-data:
grafana-data:
|
監視構成のアーキテクチャ#
以下はSpring Boot ActuatorとPrometheus、Grafanaの連携アーキテクチャです。
flowchart LR
subgraph Application
SB[Spring Boot App]
AC[Actuator]
MR[Micrometer Registry]
end
subgraph Monitoring
PM[Prometheus]
GF[Grafana]
end
SB --> AC
AC --> MR
MR -->|/actuator/prometheus| PM
PM -->|データソース| GF
GF -->|ダッシュボード| User((運用者))Grafanaダッシュボードの設定#
- Grafanaにログイン(初期認証: admin/admin)
- Configuration > Data Sources > Add data source
- Prometheusを選択し、URL に
http://prometheus:9090 を設定
- Dashboards > Import からダッシュボードをインポート
推奨のダッシュボードID(Grafana公式ギャラリーから):
| ダッシュボードID |
名称 |
用途 |
| 4701 |
JVM (Micrometer) |
JVMメトリクス監視 |
| 11378 |
Spring Boot Statistics |
Spring Boot統計情報 |
| 12900 |
Spring Boot APM Dashboard |
アプリケーションパフォーマンス監視 |
Kubernetes環境でのヘルスチェック設定#
KubernetesのLiveness ProbeとReadiness Probeに対応した設定例です。
application.ymlの設定#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
management:
endpoint:
health:
probes:
enabled: true
group:
liveness:
include: livenessState
readiness:
include: readinessState,db
health:
livenessstate:
enabled: true
readinessstate:
enabled: true
|
Kubernetesマニフェストの例#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-api
spec:
replicas: 3
selector:
matchLabels:
app: demo-api
template:
metadata:
labels:
app: demo-api
spec:
containers:
- name: demo-api
image: demo-api:latest
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
|
セキュリティ設定#
本番環境ではActuatorエンドポイントを適切に保護する必要があります。
Spring Securityを使用した設定#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
package com.example.demo.config;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
// health と prometheus は認証なしでアクセス可能
.requestMatchers(EndpointRequest.to("health", "prometheus")).permitAll()
// その他のActuatorエンドポイントは管理者のみ
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN")
// APIエンドポイントは認証必須
.requestMatchers("/api/**").authenticated()
.anyRequest().permitAll()
)
.httpBasic(httpBasic -> {});
return http.build();
}
}
|
別ポートでActuatorを公開#
Actuatorエンドポイントをアプリケーションとは別のポートで公開することで、内部ネットワークからのみアクセス可能にできます。
1
2
3
4
|
management:
server:
port: 8081
address: 127.0.0.1
|
期待される結果#
本記事の設定を完了すると、以下の結果が期待できます。
ヘルスチェック確認#
1
2
3
4
5
|
# 基本的なヘルスチェック
curl http://localhost:8080/actuator/health
# 期待されるレスポンス
{"status":"UP"}
|
Prometheusメトリクス確認#
1
2
3
4
5
6
|
curl http://localhost:8080/actuator/prometheus | head -20
# 期待されるレスポンス(一部)
# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="G1 Eden Space",} 4.2991616E7
|
利用可能なエンドポイント一覧#
1
2
3
4
5
6
7
8
9
10
11
12
|
curl http://localhost:8080/actuator
# 期待されるレスポンス
{
"_links": {
"self": {"href": "http://localhost:8080/actuator"},
"health": {"href": "http://localhost:8080/actuator/health"},
"prometheus": {"href": "http://localhost:8080/actuator/prometheus"},
"metrics": {"href": "http://localhost:8080/actuator/metrics"},
"info": {"href": "http://localhost:8080/actuator/info"}
}
}
|
まとめ#
本記事では、Spring Boot Actuatorを使用したREST APIの監視について解説しました。
- Actuatorエンドポイントの有効化: 依存関係の追加と
application.ymlでの公開設定
- カスタムヘルスインジケータ: 外部APIやデータベースの健全性監視を独自実装
- Prometheusメトリクス: Micrometer経由でのメトリクスエクスポートとカスタムメトリクス追加
- Grafana連携: ダッシュボードによる可視化と監視
- Kubernetes対応: LivenessとReadinessプローブの設定
- セキュリティ: Spring Securityによるエンドポイント保護
Actuatorを適切に設定することで、本番環境での問題検知と迅速な対応が可能になります。運用チームと連携し、アプリケーションの健全性を継続的に監視できる体制を構築してください。
参考リンク#