Spring Boot starter that auto-configures a client application to register with Spring Boot Admin server for centralized monitoring and management
—
Spring Boot Admin Client provides specialized support for cloud platforms, with automatic detection and configuration optimizations for Cloud Foundry and other cloud environments.
@ConfigurationProperties("spring.boot.admin.client.instance.metadata")
public class CloudFoundryApplicationProperties {
// Cloud Foundry specific configuration properties
// Automatically populated from VCAP_APPLICATION environment variable
}public class CloudFoundryApplicationFactory implements ApplicationFactory {
public CloudFoundryApplicationFactory(
InstanceProperties instance,
ManagementServerProperties management,
ServerProperties server,
PathMappedEndpoints pathMappedEndpoints,
WebEndpointProperties webEndpoint,
MetadataContributor metadataContributor,
CloudFoundryApplicationProperties cfApplicationProperties
);
@Override
public Application createApplication();
}public class CloudFoundryMetadataContributor implements MetadataContributor {
public CloudFoundryMetadataContributor(CloudFoundryApplicationProperties properties);
@Override
public Map<String, String> getMetadata();
}The client automatically detects cloud platform environments and adjusts behavior accordingly:
// CloudPlatform enum from Spring Boot
public enum CloudPlatform {
CLOUD_FOUNDRY,
HEROKU,
SAP,
KUBERNETES
}
// Auto-deregistration logic
public boolean isAutoDeregistration(Environment environment) {
return (this.autoDeregistration != null) ? this.autoDeregistration
: (CloudPlatform.getActive(environment) != null);
}When running on Cloud Foundry, the client automatically:
VCAP_APPLICATION environment variableThe Cloud Foundry integration automatically contributes metadata from the VCAP_APPLICATION environment variable:
{
"cf.application.id": "12345678-1234-1234-1234-123456789012",
"cf.application.name": "my-app",
"cf.space.id": "87654321-4321-4321-4321-210987654321",
"cf.space.name": "production",
"cf.organization.id": "11111111-1111-1111-1111-111111111111",
"cf.organization.name": "my-org",
"cf.instance.index": "0",
"cf.instance.port": "8080"
}# Cloud Foundry apps typically don't need explicit URL configuration
# The client auto-detects from CF environment variables
# But you can override if needed:
spring.boot.admin.client.instance.service-url=${vcap.application.uris[0]:http://localhost:8080}@Component
@ConditionalOnProperty(value = "spring.boot.admin.client.kubernetes.enabled", havingValue = "true")
public class KubernetesMetadataContributor implements MetadataContributor {
@Override
public Map<String, String> getMetadata() {
Map<String, String> metadata = new HashMap<>();
// Read from Kubernetes Downward API environment variables
addIfPresent(metadata, "k8s.namespace", "KUBERNETES_NAMESPACE");
addIfPresent(metadata, "k8s.pod.name", "HOSTNAME");
addIfPresent(metadata, "k8s.pod.ip", "POD_IP");
addIfPresent(metadata, "k8s.node.name", "NODE_NAME");
addIfPresent(metadata, "k8s.service.account", "SERVICE_ACCOUNT");
return metadata;
}
private void addIfPresent(Map<String, String> metadata, String key, String envVar) {
String value = System.getenv(envVar);
if (value != null && !value.isEmpty()) {
metadata.put(key, value);
}
}
}# Enable Kubernetes metadata
spring:
boot:
admin:
client:
kubernetes:
enabled: true
# In Kubernetes deployment, expose pod info via Downward API
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: my-app
env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName@Component
@ConditionalOnProperty(value = "spring.boot.admin.client.aws.enabled", havingValue = "true")
public class AwsMetadataContributor implements MetadataContributor {
private final RestTemplate restTemplate = new RestTemplate();
@Override
public Map<String, String> getMetadata() {
Map<String, String> metadata = new HashMap<>();
try {
// AWS Instance Metadata Service v2
String token = getImdsToken();
if (token != null) {
addAwsMetadata(metadata, token);
}
} catch (Exception e) {
// Running outside AWS or IMDS not available
logger.debug("Could not retrieve AWS metadata", e);
}
return metadata;
}
private String getImdsToken() {
HttpHeaders headers = new HttpHeaders();
headers.set("X-aws-ec2-metadata-token-ttl-seconds", "21600");
HttpEntity<String> entity = new HttpEntity<>("", headers);
ResponseEntity<String> response = restTemplate.exchange(
"http://169.254.169.254/latest/api/token",
HttpMethod.PUT, entity, String.class);
return response.getBody();
}
private void addAwsMetadata(Map<String, String> metadata, String token) {
HttpHeaders headers = new HttpHeaders();
headers.set("X-aws-ec2-metadata-token", token);
HttpEntity<String> entity = new HttpEntity<>("", headers);
// Instance metadata
metadata.put("aws.instance.id", getMetadata(entity, "instance-id"));
metadata.put("aws.instance.type", getMetadata(entity, "instance-type"));
metadata.put("aws.region", getMetadata(entity, "placement/region"));
metadata.put("aws.availability-zone", getMetadata(entity, "placement/availability-zone"));
}
private String getMetadata(HttpEntity<String> entity, String path) {
try {
ResponseEntity<String> response = restTemplate.exchange(
"http://169.254.169.254/latest/meta-data/" + path,
HttpMethod.GET, entity, String.class);
return response.getBody();
} catch (Exception e) {
return "unknown";
}
}
}@Component
@ConditionalOnProperty(value = "spring.boot.admin.client.docker.enabled", havingValue = "true")
public class DockerMetadataContributor implements MetadataContributor {
@Override
public Map<String, String> getMetadata() {
Map<String, String> metadata = new HashMap<>();
// Docker environment variables (if available)
addIfPresent(metadata, "docker.container.id", "HOSTNAME");
addIfPresent(metadata, "docker.image", "DOCKER_IMAGE");
addIfPresent(metadata, "docker.tag", "DOCKER_TAG");
// Try to detect if running in Docker
if (isRunningInDocker()) {
metadata.put("docker.container", "true");
}
return metadata;
}
private boolean isRunningInDocker() {
try {
return Files.exists(Paths.get("/.dockerenv")) ||
Files.lines(Paths.get("/proc/1/cgroup"))
.anyMatch(line -> line.contains("docker"));
} catch (Exception e) {
return false;
}
}
private void addIfPresent(Map<String, String> metadata, String key, String envVar) {
String value = System.getenv(envVar);
if (value != null && !value.isEmpty()) {
metadata.put(key, value);
}
}
}spring:
boot:
admin:
client:
# Enable cloud-specific features
kubernetes:
enabled: true
aws:
enabled: true
docker:
enabled: true
instance:
metadata:
# Static metadata
deployment-type: cloud
monitoring-level: enhanced# application-cloud.properties
spring.boot.admin.client.auto-deregistration=true
spring.boot.admin.client.period=30000
spring.boot.admin.client.instance.metadata.deployment=cloud
# application-local.properties
spring.boot.admin.client.auto-deregistration=false
spring.boot.admin.client.instance.metadata.deployment=localInstall with Tessl CLI
npx tessl i tessl/maven-de-codecentric--spring-boot-admin-starter-client