diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..48d0ded --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,28 @@ +// see https://github.com/microsoft/vscode-remote-try-java for detailed example on vscode remote java project +{ + "name": "dev-container-with-graalvm", + // java images can be found here: https://mcr.microsoft.com/en-us/artifact/mar/devcontainers/java/about + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/devcontainers/features/java:1": { + // version is installed via sdkman + // see https://sdkman.io/jdks#graalce and https://www.graalvm.org/downloads/ for version + "version": "21-graalce", + "installMaven": "true", + "mavenVersion": "3.8.6", + "installGradle": "false" + } + }, + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + "settings": {}, + "extensions": [ + "streetsidesoftware.code-spell-checker" + ] + } + } + // Use 'postCreateCommand' to run commands after the container is created. +, "postCreateCommand": "java -version" +} diff --git a/.github/workflows/build_push_to_ecr.yaml b/.github/workflows/build_push_to_ecr.yaml index 722a3eb..5945235 100644 --- a/.github/workflows/build_push_to_ecr.yaml +++ b/.github/workflows/build_push_to_ecr.yaml @@ -1,16 +1,14 @@ name: build release and push to ECR -on: +on: release: types: [prereleased, released] jobs: build_and_push: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Login to Public ECR uses: docker/login-action@v1 with: @@ -19,32 +17,23 @@ jobs: password: ${{ secrets.AWS_PROD_ECR_VIADEE_SECRET_ACCESS_KEY }} env: AWS_REGION: us-east-1 - + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - - name: Set up JDK 1.11 - uses: actions/setup-java@v3 - with: - distribution: 'adopt' # See 'Supported distributions' for available options - java-version: '11' - - - name: Cache local Maven repository - uses: actions/cache@v2 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- + java-version: "21" + distribution: "adopt" # See 'Supported distributions' for available options + cache: 'maven' - name: Maven package - run: mvn package -B + run: mvn -B package - - - - name: Docker meta + - name: Docker meta id: meta - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v5 with: images: public.ecr.aws/m4k8r3n4/k8s-demo-app tags: | @@ -54,11 +43,10 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Build and push Docker images - uses: docker/build-push-action@v2.10.0 + uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64 push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 7018ca4..212a166 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,26 +1,27 @@ # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven name: Java CI with Maven on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] jobs: build: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'adopt' - cache: maven - - name: Build with Maven - run: mvn -B package --file pom.xml + - name: Checkout + uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "liberica" # See 'Supported distributions' for available options + cache: 'maven' + + - name: Maven package + run: mvn -B package diff --git a/.github/workflows/native_build.yaml b/.github/workflows/native_build.yaml new file mode 100644 index 0000000..9d67e37 --- /dev/null +++ b/.github/workflows/native_build.yaml @@ -0,0 +1,33 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven + +name: Java CI Native Build with Maven + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "graalvm" # See 'Supported distributions' for available options + cache: 'maven' + + - name: Maven native build + run: mvn package -Pnative native:compile + - name: 'Upload Artifact' + uses: actions/upload-artifact@v4 + with: + name: native-build + path: target/k8s-demo-app + retention-days: 5 diff --git a/.github/workflows/native_build_push_to_ecr.yaml b/.github/workflows/native_build_push_to_ecr.yaml new file mode 100644 index 0000000..9b69201 --- /dev/null +++ b/.github/workflows/native_build_push_to_ecr.yaml @@ -0,0 +1,52 @@ +name: build release and push to ECR +on: + release: + types: [prereleased, released] +jobs: + build_and_push: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Login to Public ECR + uses: docker/login-action@v1 + with: + registry: public.ecr.aws + username: ${{ secrets.AWS_PROD_ECR_VIADEE_ACCESS_KEY_ID }} + password: ${{ secrets.AWS_PROD_ECR_VIADEE_SECRET_ACCESS_KEY }} + env: + AWS_REGION: us-east-1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "graalvm" # See 'Supported distributions' for available options + cache: 'maven' + + - name: Maven native build + run: mvn package -Pnative native:compile + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: public.ecr.aws/m4k8r3n4/k8s-demo-app-native + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Build and push Docker images + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index 8ba7d49..590606b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:11-slim +FROM openjdk:17-slim COPY target/k8s-demo-app.jar app.jar RUN groupadd -g 1000 appuser && \ useradd -u 1000 -g 1000 appuser diff --git a/Dockerfile.Multistage b/Dockerfile.Multistage index 3ef8f11..5d77d09 100644 --- a/Dockerfile.Multistage +++ b/Dockerfile.Multistage @@ -1,4 +1,4 @@ -FROM maven:3.6-jdk-11-slim as build_container +FROM maven:3.8-openjdk-17-slim as build_container WORKDIR /build COPY pom.xml . @@ -8,7 +8,7 @@ COPY . /usr/src/build WORKDIR /usr/src/build RUN mvn package -B -FROM openjdk:11-slim +FROM openjdk:17-slim COPY --from=build_container /usr/src/build/target/k8s-demo-app.jar app.jar RUN groupadd -g 1000 appuser && \ useradd -u 1000 -g 1000 appuser diff --git a/README.md b/README.md index ee804f9..08c291a 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,32 @@ This demo app uses spring boot and a h2-database as technologies. Then browse to `http://localhost:8080` +Or build and run with maven locally: + + ```shell + mvn spring-boot:run + ``` + ## Building This is a simple maven project. Just run `maven package`. Or just do a local docker build: `docker build -t imagename .` Then you can run the container locally. + + +## Native Build in github Codespaces + + ```shell +mvn clean +# 'package' contains step 'process-aot' which is needed for native:compile +mvn package -Pnative +mvn native:compile +# If "[1/8] Initializing..." fails, it might be due to a lag of resources. Try increasing the VM resources. + ``` + +### start native build +```shell +./target/k8s-demo-app +./target/k8s-demo-app --spring.profiles.active=red +``` diff --git a/pom.xml b/pom.xml index c835419..28f2025 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ de.viadee.k8s.testapp k8s-demo-app - 0.2.0-SNAPSHOT + 0.2.2-SNAPSHOT jar k8s-demo-app @@ -14,14 +14,15 @@ org.springframework.boot spring-boot-starter-parent - 3.0.4 + 3.3.5 UTF-8 UTF-8 - 11 + 21 + @@ -46,11 +47,6 @@ h2 runtime - - org.springframework.cloud - spring-cloud-starter-kubernetes-client-config - 2.1.3 - org.springframework.boot spring-boot-starter-test @@ -59,16 +55,24 @@ org.webjars bootstrap - 5.2.3 + + 5.3.3 ${project.artifactId} + + org.graalvm.buildtools + native-maven-plugin + org.springframework.boot spring-boot-maven-plugin + + + diff --git a/src/main/java/de/viadee/k8s/testapp/config/NativeReflectionRuntimeHintConfig.java b/src/main/java/de/viadee/k8s/testapp/config/NativeReflectionRuntimeHintConfig.java new file mode 100644 index 0000000..41be192 --- /dev/null +++ b/src/main/java/de/viadee/k8s/testapp/config/NativeReflectionRuntimeHintConfig.java @@ -0,0 +1,37 @@ +package de.viadee.k8s.testapp.config; + +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.aot.hint.annotation.RegisterReflectionForBinding; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportRuntimeHints; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import java.util.HashMap; +import java.util.Map; + + +@Configuration +@RegisterReflectionForBinding(classes = {HashMap.class}) +@ImportRuntimeHints(NativeReflectionRuntimeHintConfig.NativeRuntimeHints.class) +@EnableWebMvc +public class NativeReflectionRuntimeHintConfig { + + static class NativeRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + + // especially for rendering k8s_env.html + hints.reflection().registerType(Map.Entry.class, MemberCategory.values()); + // hints.reflection().registerType(HashMap.class, MemberCategory.values()); + // Innere Klassen + hints.reflection().registerTypeIfPresent(classLoader, "java.util.HashMap$Node" + , MemberCategory.values()); + + hints.resources().registerPattern("META-INF/resources/webjars/bootstrap/5.3.3/css/bootstrap.min.css"); + hints.resources().registerPattern("META-INF/resources/webjars/bootstrap/5.3.3/js/bootstrap.min.js"); + } + } +} diff --git a/src/main/java/de/viadee/k8s/testapp/config/WebConfig.java b/src/main/java/de/viadee/k8s/testapp/config/WebConfig.java new file mode 100644 index 0000000..c23dbd0 --- /dev/null +++ b/src/main/java/de/viadee/k8s/testapp/config/WebConfig.java @@ -0,0 +1,18 @@ +package de.viadee.k8s.testapp.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + + +@Configuration +@EnableWebMvc +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + } + +} \ No newline at end of file diff --git a/src/main/java/de/viadee/k8s/testapp/counter/CounterEntity.java b/src/main/java/de/viadee/k8s/testapp/counter/CounterEntity.java index 50ed559..b1a7086 100644 --- a/src/main/java/de/viadee/k8s/testapp/counter/CounterEntity.java +++ b/src/main/java/de/viadee/k8s/testapp/counter/CounterEntity.java @@ -1,9 +1,9 @@ package de.viadee.k8s.testapp.counter; -import java.sql.Timestamp; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; -import javax.persistence.Entity; -import javax.persistence.Id; +import java.sql.Timestamp; @Entity public class CounterEntity { diff --git a/src/main/java/de/viadee/k8s/testapp/counter/CounterRepository.java b/src/main/java/de/viadee/k8s/testapp/counter/CounterRepository.java index 8c02d5f..86d3f16 100644 --- a/src/main/java/de/viadee/k8s/testapp/counter/CounterRepository.java +++ b/src/main/java/de/viadee/k8s/testapp/counter/CounterRepository.java @@ -1,9 +1,9 @@ package de.viadee.k8s.testapp.counter; -import java.util.Optional; - import org.springframework.data.repository.CrudRepository; +import java.util.Optional; + public interface CounterRepository extends CrudRepository { Optional findById(String id); diff --git a/src/main/java/de/viadee/k8s/testapp/counter/CounterService.java b/src/main/java/de/viadee/k8s/testapp/counter/CounterService.java index b94d750..8cb26f4 100644 --- a/src/main/java/de/viadee/k8s/testapp/counter/CounterService.java +++ b/src/main/java/de/viadee/k8s/testapp/counter/CounterService.java @@ -1,16 +1,19 @@ package de.viadee.k8s.testapp.counter; +import com.zaxxer.hikari.HikariDataSource; + import java.sql.Timestamp; import java.util.Optional; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.zaxxer.hikari.HikariDataSource; +import java.sql.Timestamp; +import java.util.Optional; @Component public class CounterService { diff --git a/src/main/java/de/viadee/k8s/testapp/exception/ExceptionRestController.java b/src/main/java/de/viadee/k8s/testapp/exception/ExceptionRestController.java index 450eebd..d98c3ac 100644 --- a/src/main/java/de/viadee/k8s/testapp/exception/ExceptionRestController.java +++ b/src/main/java/de/viadee/k8s/testapp/exception/ExceptionRestController.java @@ -16,5 +16,4 @@ public String throwException() { LOG.error("log exception on error level", runtimeException); throw runtimeException; } - } diff --git a/src/main/java/de/viadee/k8s/testapp/health/DbHealthCheck.java b/src/main/java/de/viadee/k8s/testapp/health/DbHealthCheck.java index ca72ddf..0faeffa 100644 --- a/src/main/java/de/viadee/k8s/testapp/health/DbHealthCheck.java +++ b/src/main/java/de/viadee/k8s/testapp/health/DbHealthCheck.java @@ -1,5 +1,6 @@ package de.viadee.k8s.testapp.health; +import de.viadee.k8s.testapp.counter.CounterService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -7,8 +8,6 @@ import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.stereotype.Component; -import de.viadee.k8s.testapp.counter.CounterService; - @Component public class DbHealthCheck implements HealthIndicator { diff --git a/src/main/java/de/viadee/k8s/testapp/health/FakedHealthCheck.java b/src/main/java/de/viadee/k8s/testapp/health/FakedHealthCheck.java index a4fffdd..b21ff17 100644 --- a/src/main/java/de/viadee/k8s/testapp/health/FakedHealthCheck.java +++ b/src/main/java/de/viadee/k8s/testapp/health/FakedHealthCheck.java @@ -1,7 +1,5 @@ package de.viadee.k8s.testapp.health; -import java.util.concurrent.atomic.AtomicInteger; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -9,6 +7,8 @@ import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.stereotype.Component; +import java.util.concurrent.atomic.AtomicInteger; + @Component public class FakedHealthCheck implements HealthIndicator { diff --git a/src/main/java/de/viadee/k8s/testapp/readiness/ReadinessController.java b/src/main/java/de/viadee/k8s/testapp/readiness/ReadinessController.java index f57f070..918cbfd 100644 --- a/src/main/java/de/viadee/k8s/testapp/readiness/ReadinessController.java +++ b/src/main/java/de/viadee/k8s/testapp/readiness/ReadinessController.java @@ -32,5 +32,4 @@ public ResponseEntity checkReadiness(@RequestParam(required = false, nam return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).build(); } } - } diff --git a/src/main/java/de/viadee/k8s/testapp/webapp/WebController.java b/src/main/java/de/viadee/k8s/testapp/webapp/WebController.java index 82a1a04..47d3b13 100644 --- a/src/main/java/de/viadee/k8s/testapp/webapp/WebController.java +++ b/src/main/java/de/viadee/k8s/testapp/webapp/WebController.java @@ -1,8 +1,8 @@ package de.viadee.k8s.testapp.webapp; -import java.util.Map; -import java.util.TreeMap; - +import com.zaxxer.hikari.HikariDataSource; +import de.viadee.k8s.testapp.counter.CounterEntity; +import de.viadee.k8s.testapp.counter.CounterService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -13,10 +13,8 @@ import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; -import com.zaxxer.hikari.HikariDataSource; - -import de.viadee.k8s.testapp.counter.CounterEntity; -import de.viadee.k8s.testapp.counter.CounterService; +import java.util.HashMap; +import java.util.Map; @Controller public class WebController { @@ -72,7 +70,7 @@ public String k8s_index(Model model) { @GetMapping("/env") public String k8s_env(Model model) { initBgColor(model); - Map env = new TreeMap<>(System.getenv()); + Map env = new HashMap<>(System.getenv()); model.addAttribute("env", env); diff --git a/src/main/resources/templates/fragments/footer.html b/src/main/resources/templates/fragments/footer.html index 7b441be..1453e4e 100644 --- a/src/main/resources/templates/fragments/footer.html +++ b/src/main/resources/templates/fragments/footer.html @@ -9,7 +9,7 @@
+ src="webjars/bootstrap/5.3.3/js/bootstrap.min.js">
diff --git a/src/main/resources/templates/fragments/header.html b/src/main/resources/templates/fragments/header.html index 2444632..f4e3d38 100644 --- a/src/main/resources/templates/fragments/header.html +++ b/src/main/resources/templates/fragments/header.html @@ -3,7 +3,7 @@
+ href="webjars/bootstrap/5.3.3/css/bootstrap.min.css" /> K8s Test App
diff --git a/src/main/resources/templates/k8s_env.html b/src/main/resources/templates/k8s_env.html index 2c4eaca..c423eab 100644 --- a/src/main/resources/templates/k8s_env.html +++ b/src/main/resources/templates/k8s_env.html @@ -1,12 +1,12 @@ -
+
K8s Test App -
+
@@ -22,8 +22,8 @@

Environment Variables

- key - val + key + val @@ -32,7 +32,7 @@

Environment Variables

-
+
\ No newline at end of file diff --git a/src/main/resources/templates/k8s_index.html b/src/main/resources/templates/k8s_index.html index f945367..e973db8 100644 --- a/src/main/resources/templates/k8s_index.html +++ b/src/main/resources/templates/k8s_index.html @@ -1,12 +1,12 @@ -
+
K8s Test App -
+
@@ -29,7 +29,7 @@

welcome_text +
\ No newline at end of file diff --git a/src/test/java/de/viadee/k8s/testapp/testapp/TestappApplicationTests.java b/src/test/java/de/viadee/k8s/testapp/testapp/TestappApplicationTests.java index 0c01667..a4d4d5f 100644 --- a/src/test/java/de/viadee/k8s/testapp/testapp/TestappApplicationTests.java +++ b/src/test/java/de/viadee/k8s/testapp/testapp/TestappApplicationTests.java @@ -2,7 +2,6 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; @SpringBootTest public class TestappApplicationTests {