Skip to content

Commit 6215579

Browse files
author
Yuriy Bezsonov
committed
feat(apps): add Java 25 Docker optimization examples and deployment scripts
1 parent 2041cc6 commit 6215579

15 files changed

Lines changed: 905 additions & 46 deletions
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
FROM public.ecr.aws/docker/library/maven:3-amazoncorretto-25-al2023 AS builder
2+
3+
COPY ./pom.xml ./pom.xml
4+
COPY src ./src/
5+
6+
RUN mvn clean package -DskipTests -ntp && mv target/store-spring-1.0.0-exec.jar store-spring.jar
7+
8+
FROM public.ecr.aws/docker/library/amazoncorretto:25-al2023
9+
10+
RUN yum install -y shadow-utils
11+
12+
COPY --from=builder store-spring.jar store-spring.jar
13+
14+
RUN groupadd --system spring -g 1000
15+
RUN adduser spring -u 1000 -g 1000
16+
17+
USER 1000:1000
18+
EXPOSE 8080
19+
20+
ENTRYPOINT ["java", "-jar", "-Dserver.port=8080", "/store-spring.jar"]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
FROM public.ecr.aws/docker/library/maven:3-amazoncorretto-25-al2023 AS builder
2+
3+
RUN yum install -y tar gzip unzip
4+
5+
COPY ./pom.xml ./pom.xml
6+
COPY src ./src/
7+
8+
RUN mvn clean package -DskipTests -ntp && \
9+
mv target/store-spring-1.0.0-exec.jar target/store-spring.jar && \
10+
cd target && unzip store-spring.jar
11+
12+
# Analyze dependencies to determine required JDK modules
13+
RUN jdeps --ignore-missing-deps \
14+
--multi-release 25 --print-module-deps \
15+
--class-path="target/BOOT-INF/lib/*" \
16+
target/store-spring.jar > jre-deps.info
17+
18+
# Add jdk.crypto.ec for TLS 1.3 support
19+
RUN truncate --size -1 jre-deps.info && \
20+
echo ",jdk.crypto.ec" >> jre-deps.info && cat jre-deps.info
21+
22+
# Create custom JRE with only required modules
23+
RUN export JAVA_TOOL_OPTIONS="-Djdk.lang.Process.launchMechanism=vfork" && \
24+
jlink --verbose --compress zip-6 --strip-java-debug-attributes \
25+
--no-header-files --no-man-pages --output custom-jre \
26+
--add-modules $(cat jre-deps.info)
27+
28+
FROM public.ecr.aws/docker/library/amazoncorretto:25-al2023
29+
30+
RUN yum install -y shadow-utils
31+
32+
COPY --from=builder target/store-spring.jar store-spring.jar
33+
COPY --from=builder custom-jre custom-jre
34+
35+
RUN groupadd --system spring -g 1000
36+
RUN adduser spring -u 1000 -g 1000
37+
38+
USER 1000:1000
39+
EXPOSE 8080
40+
41+
ENTRYPOINT ["./custom-jre/bin/java", "-jar", "-Dserver.port=8080", "/store-spring.jar"]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
FROM public.ecr.aws/docker/library/maven:3-amazoncorretto-25-al2023 AS builder
2+
3+
COPY ./pom.xml ./pom.xml
4+
COPY src ./src/
5+
6+
RUN mvn clean package -DskipTests -ntp -Psoci && \
7+
mv target/store-spring-1.0.0.jar store-spring.jar && \
8+
java -Djarmode=layertools -jar store-spring.jar extract
9+
10+
FROM public.ecr.aws/docker/library/amazoncorretto:25-al2023
11+
12+
RUN yum install -y shadow-utils
13+
14+
# Layers ordered by change frequency for optimal caching
15+
COPY --from=builder dependencies/ ./
16+
COPY --from=builder spring-boot-loader/ ./
17+
COPY --from=builder snapshot-dependencies/ ./
18+
COPY --from=builder application/ ./
19+
20+
RUN groupadd --system spring -g 1000
21+
RUN adduser spring -u 1000 -g 1000
22+
23+
USER 1000:1000
24+
EXPOSE 8080
25+
26+
ENTRYPOINT ["java", "-Dserver.port=8080", "org.springframework.boot.loader.launch.JarLauncher"]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
FROM public.ecr.aws/docker/library/maven:3-amazoncorretto-25-al2023 AS builder
2+
3+
ARG SPRING_DATASOURCE_URL
4+
ENV SPRING_DATASOURCE_URL=$SPRING_DATASOURCE_URL
5+
ARG SPRING_DATASOURCE_USERNAME
6+
ENV SPRING_DATASOURCE_USERNAME=$SPRING_DATASOURCE_USERNAME
7+
ARG SPRING_DATASOURCE_PASSWORD
8+
ENV SPRING_DATASOURCE_PASSWORD=$SPRING_DATASOURCE_PASSWORD
9+
10+
COPY ./pom.xml ./pom.xml
11+
COPY src ./src/
12+
13+
RUN mvn clean package -DskipTests -ntp && mv target/store-spring-1.0.0-exec.jar store-spring.jar
14+
15+
# CDS training - dump class archive after Spring context initialization
16+
RUN java -XX:ArchiveClassesAtExit=/app.jsa \
17+
-Dspring.context.exit=onRefresh \
18+
-jar /store-spring.jar || true && \
19+
test -s /app.jsa
20+
21+
FROM public.ecr.aws/docker/library/amazoncorretto:25-al2023
22+
23+
RUN yum install -y shadow-utils
24+
25+
COPY --from=builder /store-spring.jar /store-spring.jar
26+
COPY --from=builder /app.jsa /app.jsa
27+
28+
RUN groupadd --system spring -g 1000 && \
29+
adduser spring -u 1000 -g 1000
30+
31+
USER 1000:1000
32+
EXPOSE 8080
33+
34+
ENTRYPOINT ["java", "-XX:SharedArchiveFile=/app.jsa", "-jar", "-Dserver.port=8080", "/store-spring.jar"]
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
FROM public.ecr.aws/docker/library/maven:3-amazoncorretto-25-al2023 AS builder
2+
3+
COPY ./pom.xml ./pom.xml
4+
COPY src ./src/
5+
6+
RUN mvn clean package -DskipTests -ntp \
7+
-Dspring-boot.aot.enabled=true && \
8+
mv target/store-spring-1.0.0-exec.jar app.jar
9+
10+
FROM public.ecr.aws/docker/library/amazoncorretto:25-al2023 AS trainer
11+
12+
COPY --from=builder app.jar app.jar
13+
14+
# Explode fat jar for AOT training
15+
RUN mkdir -p /ex && (cd /ex && jar -xf /app.jar) && \
16+
mkdir -p /opt/app/training /opt/app/lib && \
17+
(cd /ex/BOOT-INF/classes && jar -cf /opt/app/training/classes.jar .) && \
18+
cp -r /ex/BOOT-INF/lib/* /opt/app/lib/
19+
20+
# Create sorted classpath for deterministic ordering between training and runtime
21+
RUN ls /opt/app/lib/*.jar | sort | tr '\n' ':' | sed 's/:$//' > /opt/app/lib-cp.txt
22+
23+
ENV MAIN_CLASS="com.unicorn.store.StoreApplication"
24+
25+
# Optional: pass DB props for training to capture Hibernate/JDBC classes
26+
# docker build --build-arg TRAINING_JAVA_OPTS="-Dspring.datasource.url=... -Dspring.datasource.username=... -Dspring.datasource.password=..." ...
27+
ARG TRAINING_JAVA_OPTS=""
28+
ENV TRAINING_JAVA_OPTS=${TRAINING_JAVA_OPTS}
29+
ENV TRAINING_JAVA_OPTS_DEFAULT="-Dspring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration -Dspring.main.lazy-initialization=true"
30+
31+
# Record AOT configuration
32+
RUN set -e; \
33+
OPTS="${TRAINING_JAVA_OPTS}"; [ -z "${OPTS}" ] && OPTS="${TRAINING_JAVA_OPTS_DEFAULT}"; \
34+
java -XX:AOTMode=record -XX:AOTConfiguration=/app.aotconf \
35+
-cp "/opt/app/training/classes.jar:$(cat /opt/app/lib-cp.txt)" \
36+
-Dspring.context.exit=onRefresh ${OPTS} ${MAIN_CLASS} || true && \
37+
test -s /app.aotconf
38+
39+
# Create AOT cache
40+
RUN set -e; \
41+
OPTS="${TRAINING_JAVA_OPTS}"; [ -z "${OPTS}" ] && OPTS="${TRAINING_JAVA_OPTS_DEFAULT}"; \
42+
java -XX:AOTMode=create -XX:AOTConfiguration=/app.aotconf \
43+
-XX:AOTCache=/opt/app/app.aot \
44+
-cp "/opt/app/training/classes.jar:$(cat /opt/app/lib-cp.txt)" \
45+
${OPTS} ${MAIN_CLASS} || true && \
46+
test -s /opt/app/app.aot
47+
48+
FROM public.ecr.aws/docker/library/amazoncorretto:25-al2023
49+
50+
RUN yum install -y shadow-utils
51+
52+
COPY --from=trainer /opt/app/training/classes.jar /opt/app/training/classes.jar
53+
COPY --from=trainer /opt/app/lib/ /opt/app/lib/
54+
COPY --from=trainer /opt/app/app.aot /opt/app/app.aot
55+
COPY --from=trainer /opt/app/lib-cp.txt /opt/app/lib-cp.txt
56+
57+
RUN groupadd --system spring -g 1000
58+
RUN adduser spring -u 1000 -g 1000
59+
60+
USER 1000:1000
61+
EXPOSE 8080
62+
63+
ENTRYPOINT ["sh", "-c", "exec java -XX:AOTCache=/opt/app/app.aot -Dserver.port=8080 -cp /opt/app/training/classes.jar:$(cat /opt/app/lib-cp.txt) com.unicorn.store.StoreApplication"]
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
FROM quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-25 AS builder
2+
3+
USER root
4+
RUN microdnf install -y unzip zip
5+
6+
USER 1001
7+
RUN \
8+
curl -s "https://get.sdkman.io" | bash; \
9+
bash -c "source $HOME/.sdkman/bin/sdkman-init.sh; \
10+
sdk install maven;"
11+
12+
COPY ./pom.xml ./pom.xml
13+
COPY src ./src/
14+
15+
ENV MAVEN_OPTS='-Xmx8g'
16+
RUN bash -c "source $HOME/.sdkman/bin/sdkman-init.sh && mvn -DskipTests -ntp clean package -Pnative"
17+
18+
FROM public.ecr.aws/docker/library/amazoncorretto:25-al2023
19+
20+
RUN yum install -y shadow-utils
21+
22+
COPY --from=builder /project/target/store-spring /
23+
24+
RUN groupadd --system spring -g 1000
25+
RUN adduser spring -u 1000 -g 1000
26+
27+
USER 1000:1000
28+
EXPOSE 8080
29+
30+
ENTRYPOINT ["./store-spring", "-Dserver.port=8080"]
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
FROM azul/zulu-openjdk:25-jdk-crac-latest AS builder
2+
3+
RUN apt-get -qq update && apt-get -qq install -y curl maven
4+
5+
ARG SPRING_DATASOURCE_URL
6+
ENV SPRING_DATASOURCE_URL=$SPRING_DATASOURCE_URL
7+
ARG SPRING_DATASOURCE_USERNAME
8+
ENV SPRING_DATASOURCE_USERNAME=$SPRING_DATASOURCE_USERNAME
9+
ARG SPRING_DATASOURCE_PASSWORD
10+
ENV SPRING_DATASOURCE_PASSWORD=$SPRING_DATASOURCE_PASSWORD
11+
12+
COPY ./pom.xml ./pom.xml
13+
COPY src ./src/
14+
15+
RUN mvn clean package -DskipTests -ntp && mv target/store-spring-1.0.0-exec.jar store-spring.jar
16+
17+
# Take checkpoint using Warp engine (no CRIU, no extra privileges)
18+
RUN java -Dspring.context.checkpoint=onRefresh \
19+
-Djdk.crac.collect-fd-stacktraces=true \
20+
-XX:CRaCEngine=warp \
21+
-XX:CPUFeatures=generic \
22+
-XX:CRaCCheckpointTo=/opt/crac-files \
23+
-jar /store-spring.jar & PID=$! && wait ${PID} || true
24+
25+
FROM azul/zulu-openjdk:25-jdk-crac-latest
26+
27+
RUN apt-get -qq update && apt-get -qq install -y adduser \
28+
&& addgroup --system --gid 1000 spring \
29+
&& adduser --system --disabled-password --gecos "" --uid 1000 --gid 1000 spring
30+
31+
COPY --from=builder --chown=1000:1000 /opt/crac-files /opt/crac-files
32+
COPY --from=builder --chown=1000:1000 /store-spring.jar /store-spring.jar
33+
34+
USER 1000:1000
35+
EXPOSE 8080
36+
37+
ENTRYPOINT ["java", "-XX:CRaCEngine=warp", "-XX:CRaCRestoreFrom=/opt/crac-files", "-Dserver.port=8080"]

apps/unicorn-store-spring-java25/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,13 @@
275275
<activation>
276276
<activeByDefault>true</activeByDefault>
277277
</activation>
278+
<dependencies>
279+
<dependency>
280+
<groupId>org.crac</groupId>
281+
<artifactId>crac</artifactId>
282+
<version>1.5.0</version>
283+
</dependency>
284+
</dependencies>
278285
<build>
279286
<plugins>
280287
<plugin>

infra/cfn/java-ai-agents-stack.yaml

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,10 @@ Resources:
400400
- arn:aws:iam::*:role/aws-service-role/application-signals.cloudwatch.amazonaws.com/*
401401
- arn:aws:iam::*:role/aws-service-role/cloudtrail.amazonaws.com/*
402402
Sid: CreateServiceLinkedRole
403-
- Action: iam:GetRole
403+
- Action:
404+
- iam:GetRole
405+
- iam:ListRoles
406+
- iam:PassRole
404407
Effect: Allow
405408
Resource: "*"
406409
Sid: GetRole
@@ -772,6 +775,16 @@ Resources:
772775
Fn::GetAtt:
773776
- IdeInstanceLauncherFunction803C5A2A
774777
- Arn
778+
SecurityGroupIds:
779+
Fn::Join:
780+
- ""
781+
- - Fn::GetAtt:
782+
- IdeSecurityGroup73B02454
783+
- GroupId
784+
- ","
785+
- Fn::GetAtt:
786+
- IdeInternalSecurityGroupB0A5D76B
787+
- GroupId
775788
ImageId:
776789
Ref: SsmParameterValueawsserviceamiamazonlinuxlatestal2023amikernel61x8664C96584B6F00A464EAD1953AFF4B05118Parameter
777790
UserData:
@@ -923,16 +936,6 @@ Resources:
923936
- - Ref: VpcPublicSubnet1Subnet8E8DEDC0
924937
- ","
925938
- Ref: VpcPublicSubnet2SubnetA811849C
926-
SecurityGroupIds:
927-
Fn::Join:
928-
- ""
929-
- - Fn::GetAtt:
930-
- IdeSecurityGroup73B02454
931-
- GroupId
932-
- ","
933-
- Fn::GetAtt:
934-
- IdeInternalSecurityGroupB0A5D76B
935-
- GroupId
936939
UpdateReplacePolicy: Delete
937940
DeletionPolicy: Delete
938941
IdeEipAssociationDFF81215:

0 commit comments

Comments
 (0)