Skip to content
This repository was archived by the owner on Jul 27, 2023. It is now read-only.

Update Spring Boot on Liberty Stack to base on Open Liberty stack. #760

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions experimental/java-spring-boot2-liberty/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ The Spring Boot 2 stack supports the development of [Spring Boot 2](https://spri

The Spring Boot 2 stack uses a parent Maven project object model (POM) to manage dependency versions and provide required capabilities and plugins. Specifically, this stack enables [Spring Boot Actuator](https://github.com/spring-projects/spring-boot/tree/master/spring-boot-project/spring-boot-actuator), the Prometheus Micrometer reporter, and OpenTracing support for Spring using a Jaeger tracer.

This stack is based on OpenJDK with container-optimizations in OpenJ9 and `Open Liberty v20.0.0.3`. It provides live reloading during development by utilizing the "dev mode" capability in the liberty-maven-plugin. To see dev mode in action (though not in Appsody) check out this [shorter demo](https://openliberty.io/blog/2019/10/22/liberty-dev-mode.html) and this [a bit longer demo](https://blog.sebastian-daschner.com/entries/openliberty-plugin-dev-mode).

**Note:** Maven is provided by the Appsody stack container, allowing you to build, test, and debug your Java application without installing Maven locally. We recommend installing Maven locally for the best IDE experience.

## Templates
Expand Down Expand Up @@ -39,6 +41,28 @@ The default template provides a `pom.xml` file that references the parent POM de
- Metrics endpoint: http://localhost:9080/actuator/metrics
- Prometheus endpoint: http://localhost:9080/actuator/prometheus

## Appsody local development operations: (run/debug/test )

### RUN
If you launch via `appsody run` then the liberty-maven-plugin will launch dev mode in "hot test" mode, where unit tests and integration tests get automatically re-executed after each detected change.

You can alternatively launch the container with `appsody run --interactive`, in which case the tests will only execute after you input `<Enter>` from the terminal, allowing you to make a set of application and/or test changes, and only execute the tests by pressing `<Enter>` when ready.
### DEBUG
The `appsody debug` launches the Open Liberty server in debug mode, listening for the debugger on port 7777 (but not waiting, suspended). Otherwise it allows you to perform the same iteractive, interactive testing as the `appsody run` command.

### TEST
The command `appsody test` launches the Open Liberty server, runs integration tests, and then exits with a "success" or "failure" return code (and message). If you want to run tests interactively, then just use `appsody run`, since dev mode will run allow you to iteratively test and develop interactively.

## Notes to Windows 10 Users

### Shared Drive and Permission Setup
* See the instructions [here](https://appsody.dev/docs/docker-windows-aad/) for information on setting up "Shared Drives" and permissions to enable mounting the host filesystem from the appsody container.

### Changes from Windows 10 host side not detected within container
* Because of an issue in Docker for Windows 10, changes made from the host side to the application may not be detected by the liberty-maven-plugin dev mode watcher running inside the Appsody Docker container, and thus the normal expected compile, app update, test execution etc. may not run.
* At the time of the release of this java-openliberty stack, this problem seems to be getting the active attention of the Docker Desktop for Windows developement team, (e.g. see [this issue](https://github.com/docker/for-win/issues/5530)). Naturally, updating your Docker Desktop for Windows installation might help, however, we can not simply point to a recommended version that is known to work for all users.
* **Workaround**: This may be worked around by making the changes from the host, and then doing a `touch` of the corresponding files from within the container.

## Health checks, readiness and liveness

Kubernetes defines two integral mechanisms for checking the health of a container:
Expand Down
60 changes: 27 additions & 33 deletions experimental/java-spring-boot2-liberty/image/Dockerfile-stack
Original file line number Diff line number Diff line change
@@ -1,49 +1,43 @@
FROM adoptopenjdk/openjdk8-openj9
FROM kabanero/ubi8-maven:0.3.1
RUN groupadd --gid 1000 java_group \
&& useradd --uid 1000 --gid java_group --shell /bin/bash --create-home java_user \
&& mkdir -p /mvn/repository \
&& chown -R java_user:java_group /mvn \
&& mkdir -p /opt/ol \
&& chown -R java_user:java_group /opt

USER root
RUN apt-get -qq update \
&& apt-get -qq install -y curl maven wget unzip xmlstarlet \
&& DEBIAN_FRONTEND=noninteractive apt-get -qq upgrade -y \
&& apt-get -qq clean \
&& rm -rf /tmp/* /var/lib/apt/lists/*

COPY ./LICENSE /licenses/
COPY ./project /project
COPY ./config /config
COPY --chown=java_user:java_group ./project /project
COPY --chown=java_user:java_group ./config /config

WORKDIR /project
USER java_user

RUN /project/util/check_version build

WORKDIR /project/

RUN mkdir -p /mvn/repository
RUN mvn -e help:evaluate -Dexpression=maven.version -DforceStdout
RUN mvn -B -Dmaven.repo.local=/mvn/repository -N io.takari:maven:wrapper -Dmaven=$(mvn help:evaluate -Dexpression=maven.version -q -DforceStdout)
RUN mvn -B -Pstack-image-package -Dmaven.repo.local=/mvn/repository liberty:install-server install dependency:go-offline
RUN chmod -R 777 /opt/ol

# Build utility for version range processing
# Install parent pom
# Install maven wrapper in /project
RUN mkdir -p /mvn/repository \
&& /project/util/check_version build \
&& cd /project \
&& mvn -B -Dmaven.repo.local=/mvn/repository install dependency:go-offline -DskipTests \
&& mvn -B -N io.takari:maven:wrapper -Dmaven=$(mvn help:evaluate -Dexpression=maven.version -q -DforceStdout)

WORKDIR /project/user-app

ENV APPSODY_MOUNTS="~/.m2/repository:/mvn/repository;src:/project/user-app/src;pom.xml:/project/user-app/pom.xml"
ENV APPSODY_DEPS=
ENV APPSODY_MOUNTS="~/.m2/repository:/mvn/repository;.:/project/user-app"

ENV APPSODY_WATCH_DIR=/project/user-app
ENV APPSODY_WATCH_IGNORE_DIR=/project/user-app/target
ENV APPSODY_WATCH_REGEX="^.*(.xml|.java|.properties)$"
ENV APPSODY_USER_RUN_AS_LOCAL=true

ENV APPSODY_INSTALL="../validate.sh && mvn -B -Dmaven.repo.local=/mvn/repository install -DskipTests"
# Allow validate to distinguish build via APPSODY_DEV_MODE
ENV APPSODY_PREP="/project/run-stack.sh prep"

ENV APPSODY_RUN="mvn -B -Dmaven.repo.local=/mvn/repository liberty:run"
ENV APPSODY_RUN_ON_CHANGE="mvn -Dmaven.repo.local=/mvn/repository package -DskipTests"
ENV APPSODY_RUN_KILL=false
ENV APPSODY_RUN="/project/run-stack.sh run"

ENV APPSODY_DEBUG="mvn -B -Dmaven.repo.local=/mvn/repository liberty:debug"
ENV APPSODY_DEBUG_ON_CHANGE="mvn -Dmaven.repo.local=/mvn/repository package -DskipTests"
ENV APPSODY_DEBUG_KILL=false
ENV APPSODY_DEBUG="/project/run-stack.sh debug"

ENV APPSODY_TEST="mvn -B -Dmaven.repo.local=/mvn/repository verify"
ENV APPSODY_TEST_ON_CHANGE=""
ENV APPSODY_TEST_KILL=false
ENV APPSODY_TEST="/project/run-stack.sh test"

ENV PORT=9080

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ spec:
port: APPSODY_PORT
initialDelaySeconds: 5
periodSeconds: 2
timeoutSeconds: 1
livenessProbe:
failureThreshold: 12
httpGet:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ set JAVA_FOUND=0
where java >nul 2>nul
if %ERRORLEVEL% EQU 0 set JAVA_FOUND=1
if defined JAVA_HOME set JAVA_FOUND=1
if "%JAVA_FOUND%"==1 mvnw install -Denforcer.skip=true
if "%JAVA_FOUND%"=="1" mvnw install -Denforcer.skip=true
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
#!/bin/bash

if [ -n "$TERM" ] && [ "$TERM" != "dumb" ] && [ -x /usr/bin/tput ] && [[ `tput colors` != "0" ]]; then
color_prompt="yes"
else
color_prompt=
fi

if [[ "$color_prompt" == "yes" ]]; then
BLUE="\033[0;34m"
NO_COLOR="\033[0m"
else
BLUE=""
NO_COLOUR=""
fi

if [ ! -d ~/.m2/repository ]; then
echo -e "${BLUE}Creating local maven repository: ~/.m2/repository${NO_COLOR}"
mkdir -p ~/.m2/repository
fi

which java 2>&1 >/dev/null ; JAVA_KNOWN=$?
if [ ! -z "$JAVA_HOME" ] || [ $JAVA_KNOWN = "0" ]; then
./mvnw install -Denforcer.skip=true
fi
fi

# copy the maven wrapper from the stack to extracted application directory
cp -Rp mvnw* ..
cp -Rp .mvn ..
98 changes: 64 additions & 34 deletions experimental/java-spring-boot2-liberty/image/project/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,47 +1,77 @@
FROM {{.stack.image.namespace}}/{{.stack.id}}:{{.stack.semver.major}}.{{.stack.semver.minor}} as compile
# Step 1: Build the user's application
FROM kabanero/ubi8-maven:0.3.1 as compile

COPY . /project
RUN groupadd java_group \
&& useradd --gid java_group --shell /bin/bash --create-home java_user \
&& mkdir -p /mvn/repository \
&& chown -R java_user:java_group /mvn \
&& mkdir -p /config \
&& chown -R java_user:java_group /config \
# make a well known place for shared library jars seperate from the rest of the defaultServer contents (to help with caching)
&& mkdir /configlibdir \
&& chown -R java_user:java_group /configlibdir \
&& mkdir /shared \
&& chown -R java_user:java_group /shared

WORKDIR /project/user-app
USER java_user

# Ensure parent pom is used for compile
# Copy and build the dev.appsody:java-openliberty parent pom
COPY --chown=java_user:java_group ./pom.xml /project/pom.xml
RUN cd /project && mvn -B install dependency:go-offline -DskipTests

# Build version range check util for project/parent pom
RUN /project/util/check_version build
# Prime image
# a) Prime .m2/repository with common artifacts
# b) Create target/liberty/wlp/usr/servers/defaultServer dir
COPY --chown=java_user:java_group ./preload-m2-pom.xml /project/user-app/preload-m2-pom.xml
RUN cd /project/user-app && \
mvn -B -f /project/user-app/preload-m2-pom.xml liberty:install-server dependency:go-offline && \
rm /project/user-app/preload-m2-pom.xml

# Build project
RUN ../validate.sh && mvn -B install -DskipTests
# Copy and run a simple version check
COPY --chown=java_user:java_group ./util /project/util
RUN /project/util/check_version build

# Gather built resources to staging dirs
RUN cd target && \
unzip *.zip && \
mkdir -p /config && \
mv wlp/usr/servers/*/* /config/ && \
mv wlp/usr/shared/resources/lib.index.cache /lib.index.cache
# Copy the validate.sh script and application pom.xml
COPY --chown=java_user:java_group ./validate.sh /project/user-app/validate.sh
# -- This is the first app-specific piece --
COPY --chown=java_user:java_group ./user-app/pom.xml /project/user-app/pom.xml
# Validate
RUN cd /project/user-app && ./validate.sh build

FROM open-liberty:kernel-java8-openj9
# Copy the rest of the application source
COPY --chown=java_user:java_group ./user-app /project/user-app

# Ensure up to date / patched OS
USER root
RUN apt-get -qq update \
&& DEBIAN_FRONTEND=noninteractive apt-get -qq upgrade -y \
&& apt-get -qq clean \
&& rm -rf /tmp/* /var/lib/apt/lists/*
USER 1001
# Build (and run unit tests)
# also liberty:create copies config from src->target
# also remove quick-start-security.xml since it's convenient for local dev mode but should not be in the production image.
RUN cd /project/user-app && \
rm -f src/main/liberty/config/configDropins/defaults/quick-start-security.xml && \
mvn -Pappsody-build -B liberty:create package

# Bring in built artifacts from previous stage
COPY --chown=1001:0 --from=compile /config/ /config/
COPY --chown=1001:0 --from=compile /lib.index.cache/ /lib.index.cache/
# process any resources or shared libraries - if they are present in the dependencies block for this project (there may be none potentially)
# test to see if each is present and move to a well known location for later processing in the next stage
#
RUN cd /project/user-app/target/liberty/wlp/usr/servers && \
if [ -d ./defaultServer/lib ]; then mv ./defaultServer/lib /configlibdir; fi && \
if [ ! -d /configlibdir/lib ]; then mkdir /configlibdir/lib; fi && \
mv -f defaultServer/* /config/ && \
if [ -d ../shared ]; then mv ../shared/* /shared/; fi

# Step 2: Package Open Liberty image
FROM openliberty/open-liberty:{{.stack.libertyversion}}-kernel-java8-openj9-ubi

#2a) copy any resources
COPY --chown=1001:0 --from=compile /shared /opt/ol/wlp/usr/shared/

# Set metadata
ARG artifactId=appsody-spring-liberty
ARG version=1.0-SNAPSHOT
ENV JVM_ARGS=""
# 2b) next copy shared library
# but can't assume config/lib exists - copy from previous stage to a tmp holding place and test
COPY --chown=1001:0 --from=compile /configlibdir/ /config

# 2c) Server config, bootstrap.properties, and everything else
COPY --chown=1001:0 --from=compile /config/ /config/

LABEL org.opencontainers.image.version="${version}"
LABEL org.opencontainers.image.title="${artifactId}"
LABEL appsody.stack="{{.stack.image.namespace}}/{{.stack.id}}:{{.stack.semver.major}}.{{.stack.semver.minor}}.{{.stack.semver.patch}}"

EXPOSE 9080
EXPOSE 9443
# 2d) Changes to the application binary
COPY --chown=1001:0 --from=compile /project/user-app/target/*.[ew]ar /config/apps
RUN configure.sh && \
chmod 664 /opt/ol/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml
Loading