diff --git a/Dockerfile b/Dockerfile index 042438a..34da7a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,16 +6,16 @@ RUN yum -y update \ zlib-devel glibc-static libcxx libcxx-devel llvm-toolset-7 zlib-static \ && rm -rf /var/cache/yum -ENV JDK_FOLDERNAME jdk-17 -ENV JDK_FILENAME openjdk-17_linux-x64_bin.tar.gz -RUN curl -4 -L https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/${JDK_FILENAME} | tar -xvz -RUN mv $JDK_FOLDERNAME /usr/lib/jdk17 +ENV JDK_FOLDERNAME jdk-21 +ENV JDK_FILENAME openjdk-21_linux-x64_bin.tar.gz +RUN curl -4 -L https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz | tar -xvz +RUN mv $JDK_FOLDERNAME /usr/lib/jdk21 RUN yum install -y binutils RUN rm -rf $JDK_FOLDERNAME -ENV PATH="/usr/lib/jdk17/bin:$PATH" -RUN jlink --add-modules "$(java --list-modules | cut -f1 -d'@' | tr '\n' ',')" --compress 0 --no-man-pages --no-header-files --strip-debug --output /opt/jre17-slim -RUN find /opt/jre17-slim/lib -name *.so -exec strip -p --strip-unneeded {} \; +ENV PATH="/usr/lib/jdk21/bin:$PATH" +RUN jlink --add-modules "$(java --list-modules | cut -f1 -d'@' | tr '\n' ',')" --compress 0 --no-man-pages --no-header-files --strip-debug --output /opt/jre21-slim +RUN find /opt/jre21-slim/lib -name *.so -exec strip -p --strip-unneeded {} \; RUN java -Xshare:dump -version -RUN rm /opt/jre17-slim/lib/classlist -RUN cp /usr/lib/jdk17/lib/server/classes.jsa /opt/jre17-slim/lib/server/classes.jsa -RUN cd /opt/ && zip -r jre-17-slim.zip jre17-slim \ No newline at end of file +RUN rm /opt/jre21-slim/lib/classlist +RUN cp /usr/lib/jdk21/lib/server/classes.jsa /opt/jre21-slim/lib/server/classes.jsa +RUN cd /opt/ && zip -r jre-21-slim.zip jre21-slim diff --git a/README.md b/README.md index 6bc5167..b00ea56 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,35 @@ -# AWS Lambda Java 17 Custom Runtime (DEPRECATED) +# AWS Lambda Java 21 Custom Runtime -This project is no longer required, as [AWS Lambda now supports Java 17](https://aws.amazon.com/blogs/compute/java-17-runtime-now-available-on-aws-lambda/). I've left it here because others might find it's approach useful for other experimentation. +An AWS Lambda layer to enable Java 21 support. +## Usage -An AWS Lambda layer to enable Java 17 support +### In AWS Console -## Usage +- Download [java21layer.zip](https://github.com/aleph0io/lambda-java21-layer/releases/download/v21.0.0-alpha.0/java21layer.zip) +- Upload to S3 (required to create a layer from a ZIP file greater than 50MB in size) +- In Lambda console, create a layer using this ZIP file using the `x86_64` architecture and the `Custom runtime on Amazon Linux 2` runtime +- In Lambda console, create a function with `Provide your own bootstrap on Amazon Linux 2` and architecture `x86_64` +- In Lambda function console, add the layer you created, and upload your [Java deployment package](https://docs.aws.amazon.com/lambda/latest/dg/java-package.html) +- Run +- (Hopefully) celebrate! 🥳 ### with CDK -- Download [java17layer.zip](https://github.com/msailes/lambda-java17-layer/releases/download/v0.0.1-alpha/java17layer.zip) -- Create a Lambda layer using Code.fromAsset `java17layer.zip` +- Download [java21layer.zip](https://github.com/aleph0io/lambda-java21-layer/releases/download/v21.0.0-alpha.0/java21layer.zip) +- Create a Lambda layer using Code.fromAsset `java21layer.zip` - Note you might need to adjust the path for your own project structure ```java -LayerVersion java17layer = new LayerVersion(this, "Java17Layer", LayerVersionProps.builder() - .layerVersionName("Java17Layer") - .description("Java 17") +LayerVersion java21layer = new LayerVersion(this, "Java21Layer", LayerVersionProps.builder() + .layerVersionName("Java21Layer") + .description("Java 21") .compatibleRuntimes(Arrays.asList(Runtime.PROVIDED_AL2)) - .code(Code.fromAsset("java17layer.zip")) + .code(Code.fromAsset("java21layer.zip")) .build()); ``` -- Create a function using the PROVIDED_AL2 runtime. +- Create a function using the `PROVIDED_AL2` runtime. - Add this layer to your function. ```java @@ -34,18 +41,28 @@ Function exampleWithLayer = new Function(this, "ExampleWithLayer", FunctionProps .code(Code.fromAsset("../software/ExampleFunction/target/example.jar")) .memorySize(512) .logRetention(RetentionDays.ONE_WEEK) - .layers(singletonList(java17layer)) + .layers(singletonList(java21layer)) .build()); ``` ## Layer Details -### Java 17 +### Java 21 A custom JRE is created to reduce final file size. Lambda has a 250MB unzipped file size limit. [Dockerfile](Dockerfile) describes how the JRE is built. +## Known Issues + +Obviously, it's early days, and this is a preliminary release. There are a couple of known issues: + +1. The layer fails [CDS](https://docs.oracle.com/javase/8/docs/technotes/guides/vm/class-data-sharing.html) (Class Data Sharing) during initialization. This creates some log traffic, and may adversely affect performance. +2. It is only (lightly) tested +3. Only x86_64 is supported + +I'll be working on these as I have time. PRs welcome! + ### JVM Settings The following JVM settings are added by default. @@ -53,7 +70,7 @@ The following JVM settings are added by default. ``` --add-opens java.base/java.util=ALL-UNNAMED -XX:+TieredCompilation -XX:TieredStopAtLevel=1 --Xshare:on +-Xshare:auto ``` Further suggestions welcomed @@ -61,9 +78,9 @@ Further suggestions welcomed ### Java Class Path ``` -aws-lambda-java-runtime-interface-client-1.1.0.jar -aws-lambda-java-core-1.2.1.jar -aws-lambda-java-serialization-1.0.0.jar +aws-lambda-java-core-1.2.3.jar +aws-lambda-java-serialization-1.1.2.jar +aws-lambda-java-runtime-interface-client-2.4.1.jar $LAMBDA_TASK_ROOT $LAMBDA_TASK_ROOT/* $LAMBDA_TASK_ROOT/lib/* @@ -77,6 +94,10 @@ $LAMBDA_TASK_ROOT/lib/* ### Steps -- Run `build-jre.sh` to build the minimal Java 17 runtime +- Run `build-jre.sh` to build the minimal Java 21 runtime - Run `make-layer.sh` to package the runtime, dependencies and bootstrap as a zip +## Acknowledgements + +Much credit to [@msailes](https://github.com/msailes), who created the original repo from which this project is forked! + diff --git a/bootstrap b/bootstrap index 102cd38..ee6b53b 100755 --- a/bootstrap +++ b/bootstrap @@ -1,3 +1,5 @@ #!/bin/sh -/opt/jre17-slim/bin/java --add-opens java.base/java.util=ALL-UNNAMED -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xshare:on -cp "/opt/aws-lambda-java-runtime-interface-client-1.1.0.jar:/opt/aws-lambda-java-core-1.2.1.jar:/opt/aws-lambda-java-serialization-1.0.0.jar:$LAMBDA_TASK_ROOT:$LAMBDA_TASK_ROOT/*:$LAMBDA_TASK_ROOT/lib/*" com.amazonaws.services.lambda.runtime.api.client.AWSLambda "$_HANDLER" +# Should we use -Xshare:on? @msailes did originally... +# -Xlog:cds is important for solving the CDS problem. +/opt/jre21-slim/bin/java --add-opens java.base/java.util=ALL-UNNAMED -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xshare:auto -cp "/opt/aws-lambda-java-runtime-interface-client-2.4.1.jar:/opt/aws-lambda-java-core-1.2.3.jar:/opt/aws-lambda-java-serialization-1.1.2.jar:$LAMBDA_TASK_ROOT:$LAMBDA_TASK_ROOT/*:$LAMBDA_TASK_ROOT/lib/*" com.amazonaws.services.lambda.runtime.api.client.AWSLambda "$_HANDLER" diff --git a/build-jre.sh b/build-jre.sh index 4903f31..1d1f87b 100644 --- a/build-jre.sh +++ b/build-jre.sh @@ -1,2 +1,2 @@ -docker build --progress=plain -t jre17-al2-slim . -docker run -v $(pwd)/layer:/tmp -it jre17-al2-slim sh -c "cp /opt/jre-17-slim.zip /tmp" \ No newline at end of file +docker build -t jre21-al2-slim . +docker run -v $(pwd)/layer:/tmp -it jre21-al2-slim sh -c "cp /opt/jre-21-slim.zip /tmp" diff --git a/make-layer.sh b/make-layer.sh index 920d81f..99460c9 100755 --- a/make-layer.sh +++ b/make-layer.sh @@ -3,8 +3,20 @@ # -4 IPv4 only # -L follow redirect if the server responds with a redirect mkdir layer -curl -4 -L https://repo.maven.apache.org/maven2/com/amazonaws/aws-lambda-java-runtime-interface-client/1.1.0/aws-lambda-java-runtime-interface-client-1.1.0.jar -o layer/aws-lambda-java-runtime-interface-client-1.1.0.jar -curl -4 -L https://repo.maven.apache.org/maven2/com/amazonaws/aws-lambda-java-core/1.2.1/aws-lambda-java-core-1.2.1.jar -o layer/aws-lambda-java-core-1.2.1.jar -curl -4 -L https://repo.maven.apache.org/maven2/com/amazonaws/aws-lambda-java-serialization/1.0.0/aws-lambda-java-serialization-1.0.0.jar -o layer/aws-lambda-java-serialization-1.0.0.jar +curl -4 -L https://repo.maven.apache.org/maven2/com/amazonaws/aws-lambda-java-runtime-interface-client/2.4.1/aws-lambda-java-runtime-interface-client-2.4.1.jar -o layer/aws-lambda-java-runtime-interface-client-2.4.1.jar +curl -4 -L https://repo.maven.apache.org/maven2/com/amazonaws/aws-lambda-java-core/1.2.3/aws-lambda-java-core-1.2.3.jar -o layer/aws-lambda-java-core-1.2.3.jar +curl -4 -L https://repo.maven.apache.org/maven2/com/amazonaws/aws-lambda-java-serialization/1.1.2/aws-lambda-java-serialization-1.1.2.jar -o layer/aws-lambda-java-serialization-1.1.2.jar -chmod 755 bootstrap && zip -r java17layer.zip jre17-slim bootstrap layer/aws-lambda-java-runtime-interface-client-1.1.0.jar layer/aws-lambda-java-core-1.2.1.jar layer/aws-lambda-java-serialization-1.0.0.jar \ No newline at end of file +chmod 755 bootstrap + +cp bootstrap layer + +pushd layer + +rm -rf jre21-slim +unzip jre-21-slim.zip + +rm -f ../java21layer.zip +zip -r ../java21layer.zip bootstrap jre21-slim aws-lambda-java-runtime-interface-client-2.4.1.jar aws-lambda-java-core-1.2.3.jar aws-lambda-java-serialization-1.1.2.jar + +popd