Skip to content

Instantly share code, notes, and snippets.

@practicalli-johnny
Created October 31, 2022 14:42
Show Gist options
  • Save practicalli-johnny/84c8900d95fe3729c5ccd17ef3b26bb4 to your computer and use it in GitHub Desktop.
Save practicalli-johnny/84c8900d95fe3729c5ccd17ef3b26bb4 to your computer and use it in GitHub Desktop.
Dockerfile that builds a Java Run-time Enironment (JRE) and a Clojure service and deploys them on an Alpine image
# ---------------------------------------- #
# Multi-stage Dockerfile optomised for size
# - build JRE
# - build Clojure service
# - run Clojure Service on JRE
# ---------------------------------------- #
# Example of custom Java runtime using jlink in a multi-stage container build
FROM eclipse-temurin:17-alpine as jre-build
# Resource usage
# eclipse-temurin:17-alpine
# 196.75 Mb compressed size
# alpine:latest
# 5Mb
## ------ JRE Build stage ------ ##
# Create a custom Java runtime
RUN $JAVA_HOME/bin/jlink \
--add-modules java.base \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /javaruntime
## ------ Clojure Build stage ------ ##
FROM clojure:temurin-17-alpine AS builder
# Create directory for project code (working directory)
RUN mkdir -p /build
# Set Docker working directory
WORKDIR /build
# Cache and install Clojure dependencies
# Add before copying code to cache the layer even if code changes
COPY deps.edn /build/
RUN clojure -P -X:env/test:package/uberjar
# Copy project to working directory
COPY ./ /build
RUN clojure -X:package/uberjar
## ------ Run-time stage ------ ##
# Use Apline Linux as a base image
# https://hub.docker.com/_/alpine/
FROM alpine:3.16
# ------------------------
# Metadata
LABEL org.opencontainers.image.authors="noreply@practical.li"
LABEL io.practicalli.service="Gameboard API Service"
LABEL io.practicalli.team="Practicalli Engineering Team"
LABEL version="1.0"
LABEL description="Gameboard API service to share your gaming victories"
# ------------------------
# ------------------------
# Add Curl and jq binaries for manual running of system integration scripts
RUN apk add --no-cache \
curl~=7.83.1 \
jq~=1.6
# ------------------------
# ------------------------
# Setup Java Run-time Environment (JRE)
ENV JAVA_HOME=/opt/java/openjdk
ENV PATH "${JAVA_HOME}/bin:${PATH}"
COPY --from=jre-build /javaruntime $JAVA_HOME
# ------------------------
# ------------------------
# Create Non-root group and user to run service securely
RUN addgroup -S practicalli && adduser -S practicalli -G practicalli
# Create directory to contain service archive, owned by non-root user
RUN mkdir -p /service && chown -R practicalli. /service
# Tell docker that all future commands should run as the appuser user
USER practicalli
# ------------------------
# ------------------------
# Copy service archive file from Builder image
WORKDIR /service
COPY --from=builder /build/practicalli-gameboard-service.jar /service/practicalli-gameboard-service.jar
# Add System Integration testing scripts
RUN mkdir -p /service/test-scripts
COPY --from=builder /build/test-data/test-scripts/curl--* /service/test-scripts/
# ------------------------
# ------------------------
# Set Service Environment variables
# optional over-rides for Integrant configuration
# ENV HTTP_SERVER_PORT=
# ENV MYSQL_DATABASE=
ENV BILLIE_FRAUD_API_SERVICE_PROFILE=prod
# Expose port of HTTP Server
EXPOSE 8080
# ------------------------
# Run service
# JDK_JAVA_OPTIONS environment variable for setting JVM options
# Use JVM options that optomise running in a container
# For very low latency, use the Z Garbage collector
# "-XX:+UnlockExperimentalVMOptions -XX:+UseZGC"
ENV JDK_JAVA_OPTIONS "-XshowSettings:system -XX:+UseContainerSupport -XX:MaxRAMPercentage=90"
# Start service (override default `jshell` entrypoint command of image)
ENTRYPOINT ["java", "-jar", "/service/practicalli-gameboard-service.jar"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment