diff --git a/server/Dockerfile b/server/Dockerfile index 68b8ee4b..43dd33fd 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -14,23 +14,42 @@ # # Atum Service docker file - -# build via (docker root = project root): -# docker build -t absaoss/atum-service:latest \ -# --build-arg BUILD_PROXY=http://my.cool.proxy.here:3128 \ -# --build-arg CONFIG=./path/to/my.awesome.local.reference.conf \ -# --build-arg SSL=true \ -# --build-arg SSL_DNAME="CN=*.my.domain.com, OU=project1, O=mycorp, L=Johannesburg, ST=Gauteng, C=za" . -# run via -# docker run -p 8080:8080 -p 8443:8443 absaoss/atum-service:latest - -# test via: -# http://localhost:8080/token/public-key -# https://localhost:8443/token/public-key +# +# Note: the JAR file is expected to be build prior the docker build process and will be eventually placed in this +# location inside the running container: `/opt/app/atum-service.jar` +# +# Note: you can specify application configuration dynamically during `docker run` command, see below. +# The application will primarily run with the configuration file provided in `/opt/config/resource.conf`, +# but if that file does not exist (i.e. wasn't supplied via `docker run` command, or its desination path was not +# `/opt/config/`, or the file you are mounting via `docker run` wasn't named as `resource.conf`), then the +# application will use # configuration that was provided during the build (i.e. the one in the JAR file). +# +# Build via (docker root = project root): +# +# docker build -t absaoss/atum-service:latest \ +# --build-arg BASE_IMAGE=amazoncorretto:11.0.22 \ +# --build-arg BUILD_PROXY=http://my.cool.proxy.here:3128 \ +# --build-arg SSL=true \ +# --build-arg LDAP_SSL_CERTS_PATH=certs/ \ +# --build-arg AS_PREFIX=. \ +# --build-arg SCALA_VERSION=2.13 \ +# --build-arg JAR_FILE=./target/jvm-2.13/*.jar \ +# --build-arg SSL_DNAME="CN=*.my.domain.com, OU=project1, O=mycorp, L=Johannesburg, ST=Gauteng, C=za" . +# +# Run [with custom config] via +# +# docker run -v /absolute/path/resource.conf:/opt/config/resource.conf \ +# -p 8080:8080 -p 8443:8443 absaoss/atum-service:latest +# +# Test via +# +# http://localhost:8080/token/public-key +# https://localhost:8443/token/public-key # Conditional Docker image creation idea: https://stackoverflow.com/a/60820156/1773349 # change to false to disable SSL ARG SSL + # Amazon correto base image ARG BASE_IMAGE=amazoncorretto:11.0.22 @@ -39,13 +58,15 @@ FROM $BASE_IMAGE as base # Provide your proxy if needed, e.g. http://my.proxy.examle.com:3128 ARG BUILD_PROXY -# Override of the example application config is possible -ARG CONFIG=./src/main/resources/resource.conf + # Provide path to the directory with LDAP certs in PEM format ARG LDAP_SSL_CERTS_PATH + # ARG SSL_DNAME is defined below in the SSL-enabled image + # In case you build the Dockerfile from another location than the default 'service' dir, provide a prefix to reach it ARG AS_PREFIX=. + # Version of scala that server was built against ARG SCALA_VERSION=2.13 @@ -54,8 +75,8 @@ LABEL org.opencontainers.image.authors="ABSA" # The application's jar file ARG JAR_FILE=${AS_PREFIX}/target/jvm-${SCALA_VERSION}/*.jar -# Add the application's jar to the container -ADD ${JAR_FILE} app.jar +# Add the application's jar to the container in location & with filename that is easily discoverable and usable +ADD ${JAR_FILE} /opt/app/atum-service.jar ENV http_proxy=$BUILD_PROXY ENV https_proxy=$BUILD_PROXY @@ -85,7 +106,6 @@ RUN keytool -genkeypair -keyalg RSA -alias selfsigned -keysize 2048 \ -validity 365 -storepass changeit -keystore /etc/ssl/certs/selfsigned.jks -storetype JKS EXPOSE 8080 8443 -ENTRYPOINT ["java","-jar","/app.jar"] # --- SSL=false image specifics --- FROM base AS base-ssl-false @@ -93,8 +113,12 @@ ENV SSL_ENABLED=false RUN echo "This stage sets SSL=$SSL_ENABLED" EXPOSE 8080 -ENTRYPOINT ["java","-jar","/app.jar"] # --- Final image assembly --- FROM base-ssl-${SSL} AS final + +COPY ./docker_entrypoint.sh /opt/app/docker_entrypoint.sh +RUN chmod +x /opt/app/docker_entrypoint.sh + RUN echo "Running final stage with SSL_ENABLED=$SSL_ENABLED." +ENTRYPOINT ["/opt/app/docker_entrypoint.sh"] diff --git a/server/README.md b/server/README.md index 4c10d385..0d265602 100644 --- a/server/README.md +++ b/server/README.md @@ -56,12 +56,15 @@ sbt clean assembly docker build -t absaoss/atum-service:latest --progress=plain --no-cache \ --build-arg BUILD_PROXY=http://zproxycloud.intra.absaafrica:80 \ ---build-arg CONFIG=./src/main/resources/reference.conf \ ---build-arg SSL=true \ +--build-arg SSL=false \ --build-arg LDAP_SSL_CERTS_PATH=./certs \ --build-arg SSL_DNAME="CN=*.my.domain.com, OU=project1, O=mycorp, L=Johannesburg, ST=Gauteng, C=za" ./ -docker run -p 8080:8080 -p 8443:8443 absaoss/atum-service:latest +# If you want to run it against AWS, you need to add AWS related credentials into the docker container, possibly via +# environment variables; but you can also run it against your a local Postgres DB (in host or another Docker container). +docker run -v /absolute/path/resource.conf:/opt/config/resource.conf \ + -e AWS_ACCESS_KEY_ID="abc" -e AWS_SECRET_ACCESS_KEY="def" -e AWS_SESSION_TOKEN="xyz" \ + -p 8080:8080 -p 8443:8443 absaoss/atum-service:latest # reference.conf file has to be configured as below when running with ssl enabled ssl { diff --git a/server/docker_entrypoint.sh b/server/docker_entrypoint.sh new file mode 100644 index 00000000..a857f317 --- /dev/null +++ b/server/docker_entrypoint.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# These two are locations known and used in the Dockerfile. +CUSTOM_CONFIG_LOCATION="/opt/config/resource.conf" +JAR_LOCATION="/opt/app/atum-service.jar" + +# Why `exec` - mostly for a correct termination signal handling & finishing the application. +# +# Explanation: The exec command replaces the shell process with the Java process, so the Java process (our application) +# becomes the main process (PID 1) in the container. Docker automatically sends termination signals +# (SIGTERM, SIGINT, etc.) to PID 1, so the Java process will directly receive the signals and can terminate cleanly. +# +# When you define ENTRYPOINT in a Dockerfile and it points to a shell script, as it is in our case, what actually +# happens is that the shell starts first, executes the script, and then runs whatever commands are inside that script. +# For example, without exec, the process flow looks like this: +# 1. Docker starts the container, and the shell process (/bin/sh) is launched. +# 2. The shell process begins executing this `docker_entrypoint.sh` script. +# 3. Inside the script, if you run java, the shell spawns a child process to run the java command, while the shell +# process remains the parent process (still PID 1). But what we want is our Java to have PID 1 to receive +# termination signals. +if [ -f "${CUSTOM_CONFIG_LOCATION}" ]; then + echo "Running with custom config" + exec java -Dconfig.file="${CUSTOM_CONFIG_LOCATION}" -jar "${JAR_LOCATION}" +else + echo "Running with default config" + exec java -jar "${JAR_LOCATION}" +fi