From 05cbbdc6d22472ce5e6d48d74061ff9947d1ae5f Mon Sep 17 00:00:00 2001 From: Raouf MAKHLOUF Date: Sat, 17 Feb 2024 10:56:44 +0100 Subject: [PATCH] ci(docker) build native docker image --- .github/workflows/build.yml | 32 +++--- Dockerfile | 103 ++++-------------- Dockerfile_default | 19 ---- jdeps/Dockerfile | 37 ------- pom.xml | 31 +++++- .../configuration/JpaConfiguration.java | 6 + ...ionArgumentResolverProxyHintRegistrar.java | 11 ++ 7 files changed, 82 insertions(+), 157 deletions(-) delete mode 100644 Dockerfile_default delete mode 100644 jdeps/Dockerfile create mode 100644 src/main/java/com/mak/springbootefficientsearchapi/configuration/ProjectSpecificationArgumentResolverProxyHintRegistrar.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f5db2c3..b053efd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,8 +1,10 @@ name: SonarCloud + on: push: branches: - main + - main_5 env: FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} @@ -14,7 +16,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + fetch-depth: 0 # Shallow clones should be disabled for better analysis relevancy - name: Set up JDK 21 uses: actions/setup-java@v4 with: @@ -39,30 +41,24 @@ jobs: run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=Raouf25_Spring-Boot-efficient-search-API docker: - # docker-repository: https://hub.docker.com/r/raouf25/spring-boot-efficient-search-api - name: Build & push in Docker Hub + name: Build & push to Docker Hub needs: build runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to Docker Hub + - name: Build Docker image + run: docker build -t raouf25/spring-boot-efficient-search-api . + - name: Push to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build and push - uses: docker/build-push-action@v5 - with: - context: . - push: true - tags: | - raouf25/spring-boot-efficient-search-api:1.0.0 - raouf25/spring-boot-efficient-search-api:latest + - name: Docker push + run: | + docker push raouf25/spring-boot-efficient-search-api:latest + docker tag raouf25/spring-boot-efficient-search-api registry.fly.io/spring-boot-efficient-search-api + docker images | grep "spring-boot-efficient" deploy: environment: @@ -74,4 +70,6 @@ jobs: steps: - uses: actions/checkout@v4 - uses: superfly/flyctl-actions/setup-flyctl@master - - run: flyctl deploy --remote-only + - run: | + flyctl deploy -i registry.fly.io/spring-boot-efficient-search-api + diff --git a/Dockerfile b/Dockerfile index e8bc025..05d3a58 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,83 +1,20 @@ -# -# Build stage -# -FROM maven:3.8.7-eclipse-temurin-19 AS MAVEN_BUILD -COPY pom.xml /build/ -COPY . /build/ -WORKDIR /build/ -#The option "--quiet" is used to limit the output to only warnings and errors (1) -RUN mvn clean package -DskipTests --quiet - -# -# Package stage -# -# base image to build a JRE -FROM amazoncorretto:19.0.2-alpine AS deps - -# Identify dependencies (2) -COPY --from=MAVEN_BUILD ./build/target/*-SNAPSHOT.jar /app/app.jar -RUN mkdir /app/unpacked && \ - cd /app/unpacked && \ - unzip ../app.jar && \ - cd .. && \ - $JAVA_HOME/bin/jdeps \ - --ignore-missing-deps \ - --print-module-deps \ - -q \ - --recursive \ - --multi-release 17 \ - --class-path="./unpacked/BOOT-INF/lib/*" \ - --module-path="./unpacked/BOOT-INF/lib/*" \ - ./app.jar > /deps.info && \ - rm -rf ./unpacked - -# base image to build a JRE -FROM amazoncorretto:19.0.2-alpine AS corretto-jdk - -# required for strip-debug to work -RUN apk add --no-cache binutils - -# copy module dependencies info -COPY --from=deps /deps.info /deps.info - -# Build small JRE image (3) -RUN $JAVA_HOME/bin/jlink \ - --verbose \ - --add-modules $(cat /deps.info) \ - --strip-debug \ - --no-man-pages \ - --no-header-files \ - --compress=2 \ - --output /customjre - -## run this command with this option to display dependencies -## docker build -t spring-boot-efficient-search-api-custom-5 . --progress plain -RUN file0="$(cat /deps.info)" && echo $file0 - -# main app image -FROM alpine:latest -ENV JAVA_HOME=/jre -ENV PATH="${JAVA_HOME}/bin:${PATH}" - -# copy JRE from the base image -COPY --from=corretto-jdk /customjre $JAVA_HOME - -# Add app user -ARG APPLICATION_USER=appuser -RUN adduser --no-create-home -u 1000 -D $APPLICATION_USER - -# Configure working directory -RUN mkdir /app && \ - chown -R $APPLICATION_USER /app - -# Set the working directory -WORKDIR /app - -# Copy the built JAR file from the build stage -COPY --chown=1000:1000 --from=MAVEN_BUILD /build/target/spring-boot-efficient-search-api-0.0.1-SNAPSHOT.jar /app/app.jar - -# Expose port 8080 -EXPOSE 8080 - -# Run the JAR file as the entrypoint -ENTRYPOINT [ "/jre/bin/java", "-jar", "/app/app.jar" ] +# Using Oracle GraalVM for JDK 21 +FROM container-registry.oracle.com/graalvm/native-image:21-ol8 AS builder + +# Set the working directory to /home/app +WORKDIR /build + +# Copy the source code into the image for building +COPY . /build + +# Build +RUN ./mvnw --no-transfer-progress native:compile -Pnative -DskipTests + +# The deployment Image +FROM container-registry.oracle.com/os/oraclelinux:8-slim + +EXPOSE 8080 + +# Copy the native executable into the containers +COPY --from=builder /build/target/spring-boot-efficient-search-api app +ENTRYPOINT ["/app"] diff --git a/Dockerfile_default b/Dockerfile_default deleted file mode 100644 index 43084f3..0000000 --- a/Dockerfile_default +++ /dev/null @@ -1,19 +0,0 @@ -# -# Build stage -# -FROM maven:3.8.7-eclipse-temurin-19 AS MAVEN_BUILD -COPY pom.xml /build/ -COPY . /build/ -WORKDIR /build/ -#The option "--quiet" is used to limit the output to only warnings and errors (1) -RUN mvn -f /build/pom.xml clean package --quiet - - - -# -# Package stage -# -FROM amazoncorretto:19.0.2-alpine -VOLUME /tmp -COPY --from=MAVEN_BUILD /build/target/spring-boot-efficient-search-api-0.0.1-SNAPSHOT.jar spring-boot-efficient-search-api.jar -ENTRYPOINT ["java","-jar","spring-boot-efficient-search-api.jar"] diff --git a/jdeps/Dockerfile b/jdeps/Dockerfile deleted file mode 100644 index ed284c8..0000000 --- a/jdeps/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -# -# Build stage -# -FROM maven:3.8.7-eclipse-temurin-19 AS MAVEN_BUILD -COPY pom.xml /build/ -COPY . /build/ -WORKDIR /build/ -#The option "--quiet" is used to limit the output to only warnings and errors (1) -RUN mvn -f /build/pom.xml clean package --quiet - -# -# Package stage -# -# base image to build a JRE -FROM amazoncorretto:19.0.2-alpine AS deps - -# Identify dependencies (2) -COPY --from=MAVEN_BUILD ./build/target/*-SNAPSHOT.jar /app/app.jar -RUN mkdir /app/unpacked && \ - cd /app/unpacked && \ - unzip ../app.jar && \ - cd .. && \ - $JAVA_HOME/bin/jdeps \ - --ignore-missing-deps \ - --print-module-deps \ - -q \ - --recursive \ - --multi-release 17 \ - --class-path="./unpacked/BOOT-INF/lib/*" \ - --module-path="./unpacked/BOOT-INF/lib/*" \ - ./app.jar > /deps.info && \ - rm -rf ./unpacked - - -## run this command with this option to display dependencies -## docker build -t discover-jdeps . --progress plain -f ./jdeps/Dockerfile -RUN jdeps_file="$(cat /deps.info)" && echo $jdeps_file diff --git a/pom.xml b/pom.xml index ae865af..67252b1 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ Demo project for Spring Boot efficient search api - 19 + 21 raouf25-github @@ -91,14 +91,43 @@ spring-boot-starter-cache + + io.github.classgraph + classgraph + 4.8.165 + + + + + org.graalvm.buildtools + native-maven-plugin + org.springframework.boot spring-boot-maven-plugin + + org.hibernate.orm.tooling + hibernate-enhance-maven-plugin + ${hibernate.version} + + + enhance + + enhance + + + true + true + true + + + + org.jacoco jacoco-maven-plugin diff --git a/src/main/java/com/mak/springbootefficientsearchapi/configuration/JpaConfiguration.java b/src/main/java/com/mak/springbootefficientsearchapi/configuration/JpaConfiguration.java index 544e63c..b7cdcb9 100644 --- a/src/main/java/com/mak/springbootefficientsearchapi/configuration/JpaConfiguration.java +++ b/src/main/java/com/mak/springbootefficientsearchapi/configuration/JpaConfiguration.java @@ -1,7 +1,9 @@ package com.mak.springbootefficientsearchapi.configuration; +import net.kaczmarzyk.spring.data.jpa.nativeimage.SpecificationArgumentResolverHintRegistrar; import net.kaczmarzyk.spring.data.jpa.web.SpecificationArgumentResolver; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportRuntimeHints; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -10,6 +12,10 @@ @Configuration @EnableTransactionManagement +// Doc: https://github.com/tkaczmarzyk/specification-arg-resolver/blob/master/README_native_image.md +@ImportRuntimeHints({SpecificationArgumentResolverHintRegistrar.class, + ProjectSpecificationArgumentResolverProxyHintRegistrar.class}) //support for reflection //support for dynamic proxy + public class JpaConfiguration implements WebMvcConfigurer { @Override diff --git a/src/main/java/com/mak/springbootefficientsearchapi/configuration/ProjectSpecificationArgumentResolverProxyHintRegistrar.java b/src/main/java/com/mak/springbootefficientsearchapi/configuration/ProjectSpecificationArgumentResolverProxyHintRegistrar.java new file mode 100644 index 0000000..092813d --- /dev/null +++ b/src/main/java/com/mak/springbootefficientsearchapi/configuration/ProjectSpecificationArgumentResolverProxyHintRegistrar.java @@ -0,0 +1,11 @@ +package com.mak.springbootefficientsearchapi.configuration; + +import net.kaczmarzyk.spring.data.jpa.nativeimage.SpecificationArgumentResolverProxyHintRegistrar; + +class ProjectSpecificationArgumentResolverProxyHintRegistrar extends SpecificationArgumentResolverProxyHintRegistrar { + protected ProjectSpecificationArgumentResolverProxyHintRegistrar() { + super( + "com.mak.springbootefficientsearchapi.controller" // the name of package containing the interfaces with specification definitions + ); + } +}