diff --git a/.gitignore b/.gitignore index 215f3bd6..7e87c217 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .gradle/* build/* .idea/* +.vscode/* .ideaDataSources/ data-test/* bin/* diff --git a/Dockerfile b/Dockerfile index 17de11c0..67068ec8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,26 @@ -FROM eclipse-temurin:21 +# Stage 1: Build the application using Gradle and JDK 21 (Temurin) +FROM gradle:8.7-jdk21-alpine AS build +WORKDIR /app + +# Copy configuration files to cache dependencies +COPY build.gradle.kts settings.gradle.kts ./ -ARG JAR_FILE=build/libs/*.jar +# Copy source code and build the application +# Using the 'gradle' command directly since it's pre-installed +COPY src ./src +RUN gradle clean bootJar --no-daemon +# Stage 2: Minimal runtime image using Eclipse Temurin 21 JRE +FROM eclipse-temurin:21-jre-alpine WORKDIR /app +# Copy the built JAR from the previous stage +COPY --from=build /app/build/libs/*.jar app.jar +COPY --from=build /app/src/main/resources /app/resources + ENV JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" ENV SPRING_PROFILES_ACTIVE=docker -COPY ${JAR_FILE} /app/app.jar -COPY src/main/resources /app/resources - +# Application configuration EXPOSE 8080 5005 - -CMD ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"] \ No newline at end of file +ENTRYPOINT exec java $JAVA_OPTS -jar app.jar \ No newline at end of file diff --git a/README.md b/README.md index b80f47c5..761f51b0 100644 --- a/README.md +++ b/README.md @@ -146,9 +146,7 @@ docker --version ### Setup PostgreSQL database -PostgreSQL runs in Docker. The image (postgres:15) is downloaded from Docker Hub when running -the docker compose -f docker/docker-compose.yml up --build as explained -in [Run Locally](#run-locally) section. +PostgreSQL runs in Docker. The image (postgres:15) is downloaded from Docker Hub when running the `./scripts/docker-up.sh` as explained in [Run Locally](#run-locally) section. Setup Data source in the IntelliJ. @@ -178,8 +176,7 @@ execute * Build containers ```shell -./gradlew clean bootJar -docker compose -f docker/docker-compose.yml up --build +./scripts/docker-up.sh ``` Now you have the application running connected to the postgres database. @@ -235,7 +232,7 @@ You can generate a Postman collection from the application’s OpenAPI specifica 1. Start the application (e.g. via Docker Compose): ```shell - docker compose -f docker/docker-compose.yml up --build + ./scripts/docker-up.sh ``` 2. In the root directory of the repository, there is a folder called `postman-collection` which diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 0af1e58b..3183a3c2 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -28,6 +28,14 @@ services: SPRING_DATASOURCE_USERNAME: postgres SPRING_DATASOURCE_PASSWORD: MFpFnhhICniFNPA SPRING_APP_BASE_URL: http://localhost:8080 + healthcheck: + # http://localhost:8080/actuator/health is always DOWN because of the + # lack of mail service authentication + test: ["CMD-SHELL", "wget -qO- http://localhost:8080/actuator/health/ping | grep UP || exit 1"] + interval: 10s + timeout: 1s + retries: 5 + start_period: 5s networks: - app-network diff --git a/scripts/docker-down.sh b/scripts/docker-down.sh new file mode 100755 index 00000000..bc0a0cbd --- /dev/null +++ b/scripts/docker-down.sh @@ -0,0 +1,14 @@ +#!/bin/bash -xe + +# Script that kills the test environment and cleanup volumes + +dir="$(dirname -- "$(which -- "$0" 2>/dev/null || realpath -- "./$0")")" +docker compose --ansi never \ + --file "$dir/../docker/docker-compose.yml" \ + kill +if [ "$(docker ps -a -q)" ]; then + docker rm -f $(docker ps -a -q) +fi +if [ "$(docker volume ls -q)" ]; then + docker volume rm $(docker volume ls -q) +fi diff --git a/scripts/docker-up.sh b/scripts/docker-up.sh new file mode 100755 index 00000000..5daf0ecc --- /dev/null +++ b/scripts/docker-up.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Script that creates the test environment (bringuing it down before) by +# building the springboot-app (--build), and +# starting in detached mode (-d), and waiting for it to be healthy (--wait) +# +# Also checks how much time the application needed to be healthy in the end + +# Bring it down +dir="$(dirname -- "$(which -- "$0" 2>/dev/null || realpath -- "./$0")")" +$dir/docker-down.sh + +# Put it up with --build and --wait +docker compose --ansi never \ + --file "$dir/../docker/docker-compose.yml" \ + up --build -d --wait + +# Checks how long it took, from "Now" in the container to the StartedAt time +# we don't use the local clock to avoid issues with different timezones +APP=springboot-app +NOW_TIME=$(docker exec $APP date "+%H:%M:%S") +NOW_SECONDS=$(date -d "$NOW_TIME" +%s 2>/dev/null || date -j -f "%H:%M:%S" "${NOW_TIME%.*}" +%s) +echo "Now on $APP is: $NOW_TIME ($NOW_SECONDS)" +START_TIME=$(docker inspect --format='{{.State.StartedAt}}' $APP) +START_SECONDS=$(date -d "$START_TIME" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%S" "${START_TIME%.*}" +%s) +echo "Started $APP at: $START_TIME ($START_SECONDS)" +echo "Time to be healthy (in seconds): $((NOW_SECONDS - START_SECONDS))" \ No newline at end of file diff --git a/src/main/resources/application-docker.yml b/src/main/resources/application-docker.yml index 0ff14fad..59d39aba 100644 --- a/src/main/resources/application-docker.yml +++ b/src/main/resources/application-docker.yml @@ -2,6 +2,14 @@ spring: config: activate: on-profile: docker + mail: + properties: + mail: + smtp: + enable: false + auth: false + starttls: + enable: false file: storage: