spring-boot-admin-docs/src/site/docs/09-samples/40-sample-consul.md
The Consul sample demonstrates Spring Boot Admin Server integration with HashiCorp Consul for service discovery. This sample shows how to leverage Consul's powerful service registry and health checking capabilities to automatically discover and monitor Spring Boot applications.
Location: spring-boot-admin-samples/spring-boot-admin-sample-consul/
Features:
brew install consul
wget https://releases.hashicorp.com/consul/1.17.0/consul_1.17.0_linux_amd64.zip
unzip consul_1.17.0_linux_amd64.zip
sudo mv consul /usr/local/bin/
Download from: https://www.consul.io/downloads
docker run -d -p 8500:8500 -p 8600:8600/udp --name=consul consul agent -server -ui -bootstrap-expect=1 -client=0.0.0.0
consul version
# Development mode (single node)
consul agent -dev
Verify Consul is running: http://localhost:8500/ui
cd spring-boot-admin-samples/spring-boot-admin-sample-consul
mvn spring-boot:run
Access Admin UI at: http://localhost:8080
mvn spring-boot:run -Dspring-boot.run.arguments=\
--spring.cloud.consul.host=consul-server
mvn spring-boot:run -Dspring-boot.run.profiles=insecure
<dependencies>
<!-- Admin Server -->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<!-- Consul Discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- Web (Servlet) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<!-- Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
@SpringBootApplication
@EnableDiscoveryClient // Enable Consul discovery
@EnableAdminServer // Enable Admin Server
public class SpringBootAdminConsulApplication {
static void main(String[] args) {
SpringApplication.run(SpringBootAdminConsulApplication.class, args);
}
}
spring:
application:
name: consul-example
cloud:
config:
enabled: false # Disable config client
consul:
host: localhost
port: 8500
discovery:
metadata:
# IMPORTANT: Use dashes, not dots in metadata keys!
management-context-path: /foo
health-path: /ping
user-name: user
user-password: password
profiles:
active:
- secure
boot:
admin:
discovery:
ignored-services: consul # Don't monitor Consul itself
management:
endpoints:
web:
exposure:
include: "*"
base-path: /foo # Custom actuator base path
path-mapping:
health: /ping # Custom health endpoint path
endpoint:
health:
show-details: ALWAYS
:::warning Metadata Key Restriction CRITICAL: Consul metadata keys cannot contain dots. Use dashes instead:
management-context-pathmanagement.context-pathThis is a Consul limitation, not a Spring Boot Admin limitation. :::
For applications to be monitored:
spring:
application:
name: my-service
cloud:
consul:
host: localhost
port: 8500
discovery:
metadata:
management-context-path: /actuator # Use dashes!
health-path: /actuator/health
# For secured actuators
user-name: ${actuator.username}
user-password: ${actuator.password}
management:
endpoints:
web:
exposure:
include: "*"
@Profile("insecure")
@Configuration
public static class SecurityPermitAllConfig {
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http)
throws Exception {
http.authorizeHttpRequests((authorizeRequests) ->
authorizeRequests.anyRequest().permitAll())
.csrf((csrf) -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers(
adminContextPath + "/instances",
adminContextPath + "/instances/*",
adminContextPath + "/actuator/**"
));
return http.build();
}
}
@Profile("secure")
@Configuration
public static class SecuritySecureConfig {
@Bean
protected SecurityFilterChain filterChain(HttpSecurity http)
throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler =
new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(adminContextPath + "/");
http.authorizeHttpRequests((authorizeRequests) ->
authorizeRequests
.requestMatchers(adminContextPath + "/assets/**")
.permitAll()
.requestMatchers(adminContextPath + "/login")
.permitAll()
.anyRequest()
.authenticated())
.formLogin((formLogin) -> formLogin
.loginPage(adminContextPath + "/login")
.successHandler(successHandler))
.logout((logout) -> logout
.logoutUrl(adminContextPath + "/logout"))
.httpBasic(Customizer.withDefaults())
.csrf((csrf) -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers(
adminContextPath + "/instances",
adminContextPath + "/instances/*",
adminContextPath + "/actuator/**"
));
return http.build();
}
}
Application Registration:
Health Checking:
Admin Discovery:
Deregistration:
Admin Server reads specific metadata keys from Consul:
spring:
cloud:
consul:
discovery:
metadata:
# Required for endpoint detection
management-context-path: /actuator # Dashes only!
management-port: 8081 # If different
# Optional - for secured actuators
user-name: admin
user-password: ${ACTUATOR_PASSWORD}
# Custom metadata
environment: production
version: 1.0.0
team: platform
Key Mappings:
management-context-path → Where to find actuator endpointsmanagement-port → Management port if different from service porthealth-path → Custom health endpoint pathuser-name / user-password → Actuator credentialsThis sample demonstrates custom actuator paths:
management:
endpoints:
web:
base-path: /foo # Actuator at /foo instead of /actuator
path-mapping:
health: /ping # Health at /foo/ping instead of /foo/health
Admin Server discovers these via metadata:
spring:
cloud:
consul:
discovery:
metadata:
management-context-path: /foo
health-path: /ping
http://localhost:8500/uiconsul-example (Admin Server)In Consul UI, services should show:
http://localhost:8080Register a new service:
# Register via Consul API
curl -X PUT -d '{
"Name": "test-service",
"Address": "127.0.0.1",
"Port": 8081,
"Meta": {
"management-context-path": "/actuator"
},
"Check": {
"HTTP": "http://127.0.0.1:8081/actuator/health",
"Interval": "10s"
}
}' http://localhost:8500/v1/agent/service/register
Service appears in Admin UI within seconds.
Consul supports multiple health check types:
spring:
cloud:
consul:
discovery:
health-check-path: /actuator/health
health-check-interval: 10s
health-check-timeout: 5s
spring:
cloud:
consul:
discovery:
health-check-ttl: 30s
Application must send heartbeat to Consul every 30 seconds.
Add tags for filtering:
spring:
cloud:
consul:
discovery:
tags:
- production
- backend
- v1.0.0
Filter services monitored by Admin:
spring:
boot:
admin:
discovery:
ignored-services:
- consul # Don't monitor Consul
- config-server # Don't monitor Config Server
services: # Only monitor these (if specified)
- my-service
- another-service
Secure Consul with ACL tokens:
spring:
cloud:
consul:
token: ${CONSUL_TOKEN}
discovery:
acl-token: ${CONSUL_ACL_TOKEN}
Connect to Consul over TLS:
spring:
cloud:
consul:
scheme: https
tls:
enabled: true
key-store-path: classpath:consul-keystore.p12
key-store-password: ${KEYSTORE_PASSWORD}
Register in specific datacenter:
spring:
cloud:
consul:
discovery:
datacenter: dc1
Use IP instead of hostname:
spring:
cloud:
consul:
discovery:
prefer-ip-address: true
ip-address: 192.168.1.100
| Feature | Consul | Eureka |
|---|---|---|
| Health Checks | Built-in (HTTP, TCP, TTL, Script) | Via Spring Boot actuator only |
| Key-Value Store | Yes | No |
| ACL | Yes | Basic |
| Multi-DC | Native support | Requires setup |
| DNS Interface | Yes | No |
| Metadata Keys | No dots allowed | Dots allowed |
| Complexity | Higher | Lower |
| Ecosystem | HashiCorp ecosystem | Netflix stack |
Symptom: Admin Server can't find actuator endpoints
Cause: Used dots in metadata keys
Solution: Use dashes instead:
# Wrong
metadata:
management.context-path: /actuator
# Correct
metadata:
management-context-path: /actuator
Check Consul connectivity:
# Test Consul API
curl http://localhost:8500/v1/catalog/services
# Check health
curl http://localhost:8500/v1/health/state/passing
Verify Admin logs:
tail -f logs/spring-boot-admin.log | grep -i consul
Services show as "failing" in Consul:
Verify health endpoint is accessible:
curl http://localhost:8080/actuator/health
Check health check interval:
spring:
cloud:
consul:
discovery:
health-check-interval: 30s # Increase if needed
Review Consul logs:
consul monitor
Increase timeout values:
spring:
cloud:
consul:
discovery:
health-check-timeout: 10s # Increase from default
Run Consul in cluster mode (3 or 5 nodes):
# Server node 1
consul agent -server -bootstrap-expect=3 -data-dir=/consul/data \
-bind=192.168.1.10
# Server node 2
consul agent -server -data-dir=/consul/data \
-bind=192.168.1.11 -join=192.168.1.10
# Server node 3
consul agent -server -data-dir=/consul/data \
-bind=192.168.1.12 -join=192.168.1.10
spring:
cloud:
consul:
token: ${CONSUL_MANAGEMENT_TOKEN}
discovery:
acl-token: ${CONSUL_SERVICE_TOKEN}
Register Admin Server to monitor itself:
spring:
boot:
admin:
discovery:
ignored-services: [] # Don't ignore any services
This sample demonstrates:
✅ Consul Integration
✅ Metadata Handling
✅ Production Features
✅ Flexibility