Merge branch 'feature/Dockerfile-multistage' into 'develop/0.2.0'

add kontor-javalin and change to multistage Dockerfile for Gradle projects

See merge request tpeetz/kontor!37
This commit was merged in pull request #81.
This commit is contained in:
2025-12-21 21:44:23 +01:00
16 changed files with 107 additions and 82 deletions
+22
View File
@@ -113,6 +113,28 @@ services:
depends_on:
postgres:
condition: service_healthy
kontor-javalin:
build:
context: ./kontor-javalin
dockerfile: Dockerfile
tags:
- kontor-javalin:0.2.0-SNAPSHOT
image: kontor-javalin:0.2.0-SNAPSHOT
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://kontor-javalin:8400/health"]
interval: 10s
timeout: 5s
retries: 3
networks:
- database
- integration
- frontend
ports:
- 8400:8400
depends_on:
postgres:
condition: service_healthy
networks:
integration:
+24 -4
View File
@@ -1,5 +1,25 @@
FROM alpine/java:21-jdk
# ----------------------------------------------------------------------- #
FROM gradle:9.2.1-jdk21 AS builder
WORKDIR /
ADD build/libs/kontor-spring-0.2.0-SNAPSHOT.jar app.jar
EXPOSE 8000
CMD ["java", "-jar", "-Dspring.profiles.active=prod", "-Dvaadin.productionMode=true", "app.jar"]
COPY ./src/main/ ./src/main/
COPY ./build.gradle ./
COPY ./gradle.properties ./
COPY ./settings.gradle ./
COPY ./gradle/libs.versions.toml ./gradle/
RUN gradle build --no-daemon
# ----------------------------------------------------------------------- #
FROM alpine/java:21-jre AS run
RUN apk --no-cache add curl
RUN adduser --system appuser
USER appuser
COPY --from=builder --chown=appuser:appuser /build/libs/kontor-javalin-0.2.0-SNAPSHOT.jar app.jar
EXPOSE 8400
USER appuser
CMD ["java", "-jar", "app.jar"]
-17
View File
@@ -1,17 +0,0 @@
plugins {
id 'application'
}
dependencies {
implementation project(":models") // We need this dependency for serializing persons to JSON
implementation project(":services") // We'll make use of the InMemoryPersonReader soon
implementation libs.javalin // Pulling in Javalin
implementation libs.jackson // For JSON serialization of persons
implementation libs.slf4j // To see some Javalin logging
}
application {
mainClass = "de.thpeetz.kontor.api.Main"
mainModule = "de.thpeetz.kontor.api"
}
@@ -1,10 +0,0 @@
module de.thpeetz.kontor.api {
requires io.javalin;
requires com.fasterxml.jackson.databind;
requires org.slf4j;
requires kotlin.stdlib;
requires de.thpeetz.kontor.services;
uses de.thpeetz.kontor.services.api.PersonReader;
}
+19 -5
View File
@@ -1,14 +1,28 @@
plugins {
id 'org.javamodularity.moduleplugin' version '2.0.0' apply false
id 'java'
}
subprojects {
repositories {
repositories {
mavenCentral()
}
apply plugin: "org.javamodularity.moduleplugin"
}
dependencies {
implementation libs.javalin // Pulling in Javalin
implementation libs.jackson // For JSON serialization of persons
implementation libs.slf4j // To see some Javalin logging
}
task fatJar(type: Jar) {
manifest {
attributes 'Main-Class': 'de.thpeetz.kontor.api.Main'
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
build.dependsOn fatJar
wrapper {
gradleVersion = "9.2.1"
}
-4
View File
@@ -1,4 +0,0 @@
plugins {
id 'java-library'
}
@@ -1,4 +0,0 @@
module de.thpeetz.kontor.models {
// We're exporting the only package we have in this subproject
exports de.thpeetz.kontor.models;
}
-7
View File
@@ -1,7 +0,0 @@
plugins {
id 'java-library'
}
dependencies {
implementation project(":models") // <-- add dependency to models subproject
}
@@ -1,11 +0,0 @@
import de.thpeetz.kontor.services.api.PersonReader;
import de.thpeetz.kontor.services.inmemory.InMemoryPersonReader;
module de.thpeetz.kontor.services {
exports de.thpeetz.kontor.services.api;
requires de.thpeetz.kontor.models;
// We're telling the ServiceLoader that the InMemoryPersonReader provides the implementation for the PersonReader interface
provides PersonReader with InMemoryPersonReader;
}
-5
View File
@@ -1,6 +1 @@
rootProject.name = 'kontor-javalin'
include ':models'
include ':services'
include ':api'
@@ -1,21 +1,20 @@
package de.thpeetz.kontor.api;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.thpeetz.kontor.services.inmemory.InMemoryPersonReader;
import io.javalin.Javalin;
import de.thpeetz.kontor.services.api.PersonReader;
import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ServiceLoader;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
private static Logger logger = LoggerFactory.getLogger(Main.class);
private static short port = 7312;
private static short port = 8400;
public static void main(String[] args) {
var personReader = ServiceLoader.load(PersonReader.class).findFirst().get(); // <-- Getting an implementation
// for the PersonReader interface
// from the ServiceLoader
var personReader = new InMemoryPersonReader();
var objMapper = new ObjectMapper();
var result = objMapper.valueToTree(personReader.getAll());
@@ -23,7 +22,15 @@ public class Main {
var app = Javalin.create().start(port);
app.get("/ping", ctx -> ctx.result("pong"));
app.get("/persons", ctx -> ctx.json(result));
app.get("/health", ctx -> {
HashMap<String, String> status = new HashMap<>();
status.put("status", "ok");
ctx.json(status);
});
app.get("/persons", ctx -> {
logger.info("persons called");
ctx.json(result);
});
logger.info("API's alive for real :-)))");
}
@@ -1,7 +1,6 @@
package de.thpeetz.kontor.services.api;
import de.thpeetz.kontor.models.Person;
import java.util.List;
public interface PersonReader {
@@ -6,6 +6,7 @@ import java.util.List;
import de.thpeetz.kontor.services.api.PersonReader;
public class InMemoryPersonReader implements PersonReader {
@Override
public List<Person> getAll() {
return List.of(
+23 -3
View File
@@ -1,5 +1,25 @@
FROM alpine/java:21-jdk
# ----------------------------------------------------------------------- #
FROM gradle:8.7-jdk AS builder
WORKDIR /
ADD build/libs/kontor-spring-0.2.0-SNAPSHOT.jar app.jar
EXPOSE 8000
COPY ./src/main/ ./src/main/
COPY ./frontend/ ./frontend/
COPY ./build.gradle ./
COPY ./gradle.properties ./
COPY ./settings.gradle ./
COPY ./gradle/libs.versions.toml ./gradle/
RUN gradle bootJar --no-daemon
# ----------------------------------------------------------------------- #
FROM alpine/java:21-jdk AS run
RUN mkdir -p /logs
RUN adduser --system appuser
COPY --from=builder --chown=appuser:appuser /build/libs/kontor-spring-0.2.0-SNAPSHOT.jar app.jar
RUN chown appuser:root /logs
EXPOSE 8100
USER appuser
CMD ["java", "-jar", "-Dspring.profiles.active=prod", "-Dvaadin.productionMode=true", "app.jar"]
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOGS" value="./logs" />
<property name="LOGS" value="logs" />
<appender name="Console"
class="ch.qos.logback.core.ConsoleAppender">