Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .claude-volumes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build
src/main/resources
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gradlew text eol=lf
gradlew.bat text eol=crlf
16 changes: 6 additions & 10 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,11 @@ jobs:
- name: Checkout
uses: actions/checkout@v3

- uses: octokit/request-action@v2.x
id: get_latest_release
with:
route: GET /repos/codecentric/spring-boot-admin/releases/latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- run: "echo latest release: ${{ steps.get_latest_release.outputs }}"
- name: Read Spring Boot Admin version
id: sba_version
run: |
version=$(grep -E '^springBootAdmin\s*=' gradle/libs.versions.toml | sed -E 's/.*"([^"]+)".*/\1/')
echo "version=$version" >> "$GITHUB_OUTPUT"

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
Expand All @@ -49,7 +46,7 @@ jobs:
with:
context: .
push: true
tags: '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ fromJson(steps.get_latest_release.outputs.data).tag_name }}'
tags: '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest,${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.sba_version.outputs.version }}'
platforms: linux/amd64,linux/arm64
labels: |
org.opencontainers.image.licenses=Apache-2.0
Expand All @@ -58,4 +55,3 @@ jobs:
org.opencontainers.image.url=https://github.com/cloudflightio/spring-boot-admin-docker
org.opencontainers.image.source=https://github.com/cloudflightio/spring-boot-admin-docker
org.opencontainers.image.version=nightly
build-args: SPRING_BOOT_ADMIN_VERSION=${{ fromJson(steps.get_latest_release.outputs.data).tag_name }}
4 changes: 1 addition & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
FROM docker.io/library/eclipse-temurin:17-jdk AS builder

ARG SPRING_BOOT_ADMIN_VERSION=2.7.3

WORKDIR /src
COPY . /src
RUN /src/gradlew build -PspringBootAdminVersion=$SPRING_BOOT_ADMIN_VERSION
RUN /src/gradlew build

FROM docker.io/library/eclipse-temurin:17-jre

Expand Down
94 changes: 94 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,97 @@ To configure settings for your instance, either use environment variables as
documentation](https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/html/boot-features-external-config.html)
or mount a file called `application.yaml` to `/deployments/application.yaml`
when running the container.

### Security

The admin UI, its API, and the client registration endpoints are locked down by
`SecurityConfig` and require an authenticated user. Only the static assets and
the login page are reachable anonymously. Authentication is delegated to an
OAuth2 / OpenID Connect provider, so you must configure an OAuth2 client before
the application will start serving the UI.

The client registration and provider **must** be named `openid`. The provider's
`issuer-uri` is mandatory: it is used both for login and for building the
provider's logout URL on sign-out. The logout URL is constructed as
`<issuer-uri>/protocol/openid-connect/logout`, which matches
[Keycloak](https://www.keycloak.org/); other providers that do not expose that
path are not supported without code changes.

```yaml
spring:
security:
oauth2:
client:
registration:
openid:
client-id: <your-client-id>
client-secret: <your-client-secret>
scope:
- openid
- profile
- email
authorization-grant-type: authorization_code
provider:
openid:
issuer-uri: <issuer-uri-with-realm>
user-name-attribute: preferred_username
```

### Service discovery

Monitored applications are located through Spring Cloud discovery. Two options
are available.

#### Kubernetes discovery

The [Kubernetes discovery
client](https://docs.spring.io/spring-cloud-kubernetes/reference/index.html) is
on the classpath. When the application runs inside a cluster it discovers other
pods/services automatically; no additional configuration is required beyond the
usual RBAC allowing the pod to list services and endpoints.

#### Simple (static) discovery

To register targets explicitly — for local testing or for instances outside the
cluster — use the simple discovery client. Each entry needs the target's base
`uri` and the `management.context-path` metadata so SBA knows where the actuator
endpoints live:

```yaml
spring:
cloud:
discovery:
client:
simple:
instances:
my-application:
- uri: http://localhost:18080
metadata:
management.context-path: /actuator
```

##### Discovering more than one client

The key under `instances` is the application name, and its value is a **list**,
so you can register several instances of the same application and add further
applications as additional keys:

```yaml
spring:
cloud:
discovery:
client:
simple:
instances:
my-application:
- uri: http://my-application-1:18080
metadata:
management.context-path: /actuator
- uri: http://my-application-2:18080
metadata:
management.context-path: /actuator
another-application:
- uri: http://another-application:8080
metadata:
management.context-path: /actuator
```
32 changes: 0 additions & 32 deletions build.gradle

This file was deleted.

58 changes: 58 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.spring)
alias(libs.plugins.spring.boot)
}

group = "io.cloudflight"
version = libs.versions.springBootAdmin.get()

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

kotlin {
compilerOptions {
freeCompilerArgs.addAll("-Xjsr305=strict")
jvmTarget = JvmTarget.JVM_17
}
}

repositories {
mavenCentral()
}

dependencies {
implementation(platform(libs.spring.boot.bom))
implementation(platform(libs.spring.boot.admin.bom))
implementation(platform(libs.spring.cloud.bom))
implementation(libs.spring.boot.admin.starter.server)
implementation(libs.spring.boot.starter.web)
implementation(libs.spring.boot.starter.actuator)
implementation(libs.spring.boot.starter.security)
implementation(libs.spring.boot.starter.oauth2.client)
implementation(libs.jackson.module.kotlin)
implementation(libs.kotlin.reflect)
implementation(libs.spring.cloud.starter.kubernetes.client.all)

testImplementation(libs.spring.boot.starter.test)
}

tasks.withType<Test> {
useJUnitPlatform()
}

tasks.test {
filter {
includeTestsMatching("*Test")
isFailOnNoMatchingTests = false
}
}

tasks.named("jar") {
enabled = false
}
4 changes: 3 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
springBootAdminVersion=2.7.3
org.gradle.caching=true
org.gradle.parallel=true
kotlin.code.style=official
33 changes: 33 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[versions]
kotlin = "2.1.21"
springBoot = "3.5.4"
# Spring Boot Admin is versioned independently of Spring Boot (they happen to align today).
springBootAdmin = "3.5.4"
springCloud = "2025.0.3"

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-spring = { id = "org.jetbrains.kotlin.plugin.spring", version.ref = "kotlin" }
spring-boot = { id = "org.springframework.boot", version.ref = "springBoot" }

[libraries]
spring-boot-bom = { module = "org.springframework.boot:spring-boot-dependencies", version.ref = "springBoot" }
spring-boot-admin-bom = { module = "de.codecentric:spring-boot-admin-dependencies", version.ref = "springBootAdmin" }
spring-cloud-bom = { module = "org.springframework.cloud:spring-cloud-dependencies", version.ref = "springCloud" }

# Dependencies managed by Spring Boot BOM
spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web" }
spring-boot-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator" }
spring-boot-starter-security = { module = "org.springframework.boot:spring-boot-starter-security" }
spring-boot-starter-oauth2-client = { module = "org.springframework.boot:spring-boot-starter-oauth2-client" }
jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect" }

# Spring Boot Admin server UI + registration endpoint (version managed by the SBA BOM).
spring-boot-admin-starter-server = { module = "de.codecentric:spring-boot-admin-starter-server" }

# Discover Spring Boot Applications running in Kubernetes (version managed by the Spring Cloud BOM).
spring-cloud-starter-kubernetes-client-all = { module = "org.springframework.cloud:spring-cloud-starter-kubernetes-client-all" }

# Test dependencies (managed by Spring Boot BOM)
spring-boot-starter-test = { module = "org.springframework.boot:spring-boot-starter-test" }
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading