diff --git a/aws-lambda-java-runtime-interface-client/README.md b/aws-lambda-java-runtime-interface-client/README.md index 180d8eb9..65255294 100644 --- a/aws-lambda-java-runtime-interface-client/README.md +++ b/aws-lambda-java-runtime-interface-client/README.md @@ -2,12 +2,12 @@ We have open-sourced a set of software packages, Runtime Interface Clients (RIC), that implement the Lambda [Runtime API](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html), allowing you to seamlessly extend your preferred - base images to be Lambda compatible. + base images to be Lambda compatible or to implement your own custom Lambda runtime. The Lambda Runtime Interface Client is a lightweight interface that allows your runtime to receive requests from and send requests to the Lambda service. -You can include this package in your preferred base image to make that base image Lambda compatible. +## Usage 1: Deploy your Lambda as a Container Image without native compilation -## Usage +You can include this package in your preferred base image to make that base image Lambda compatible. ### Creating a Docker Image for Lambda with the Runtime Interface Client @@ -151,6 +151,222 @@ DOCKERHUB_PASSWORD= ``` Recommended way is to set the Docker Hub credentials in CodeBuild job by retrieving them from AWS Secrets Manager. +## Usage 2: Deploy your Lambda with Native Compilation + +You can include this package as a dependency to build your Custom Runtime or to run your Lambda as a Container without any Java Runtime. + +The idea here is to compile natively your java bytecode with [GraalVM](https://www.graalvm.org) [native-image](https://www.graalvm.org/reference-manual/native-image/) to a linux executable file. +In order to ease this native compilation of the Java Runtime Interface Client, the Java RIC jar artifact is now including special configuration files for GraalVM native-image. + +Note: In this example the docker image provided may be used +* For cross compiling only to linux x86-64 and extract the Custom Runtime zip to deploy +* For deploying your Lambda as a Container Image +* For local testing of your Container Image or your native executable. + +### Example: hello-lambda-native project + +Let's take the same Lambda as before: + +src/main/java/example/App.java +```java +package example; + +public class App { + public static String sayHello() { + return "Hello λ!"; + } +} +``` + +This is the needed configuration for native-image for finding the Lambda code: + +src/main/resources/META-INF/native-image/reflect-config.json +```json +[ +{ + "name":"example.App", + "allPublicMethods":true +} +] +``` + +When building a Custom Runtime you need a zip archive containing at root a file named bootstrap that will be the entry point for running your Lambda. In a Container, the same bootstrap file is used as ENTRYPOINT. And finally, it contains also the logic to identify the case of local testing: + +bootstrap +```bash +#!/bin/sh +if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then + exec /usr/bin/aws-lambda-rie ./func $1 +else + set -euo pipefail + exec ./func $_HANDLER +fi +``` + +The Dockerfile is slightly more complex to support the three use cases described above: + +Dockerfile +```dockerfile +FROM amazonlinux:2 as base + +FROM base as build +ENV LANG=en_US.UTF-8 +RUN yum update -y && yum install -y gcc gcc-c++ zlib-devel zip tar gzip && yum clean all +RUN curl -4 -L https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-20.3.0/graalvm-ce-java11-linux-amd64-20.3.0.tar.gz -o /tmp/graalvm.tar.gz \ + && tar -zxf /tmp/graalvm.tar.gz -C /tmp \ + && mv /tmp/graalvm-ce-java11-20.3.0 /usr/lib/graalvm \ + && rm -rf /tmp/* +RUN /usr/lib/graalvm/bin/gu install native-image +ENV PATH=/usr/lib/graalvm/bin:${PATH} +ENV JAVA_HOME=/usr/lib/graalvm +RUN yum install -y maven + +# compile the function +WORKDIR /home/app +ADD . . +RUN mvn package + +COPY bootstrap /home/app/ +# (Optional) Add Lambda Runtime Interface Emulator and use a script in the ENTRYPOINT for simpler local runs +ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /home/app/aws-lambda-rie +RUN native-image -jar target/hello-lambda-native-1.0-SNAPSHOT.jar -H:Name=func --no-fallback +RUN yum install -y zip && yum clean all +RUN chmod 755 aws-lambda-rie +RUN chmod 755 bootstrap +RUN chmod 755 func +RUN zip -j function.zip bootstrap func + +FROM base +WORKDIR /function +COPY --from=build /home/app/func /function/func +COPY --from=build /home/app/bootstrap /function/bootstrap +COPY --from=build /home/app/function.zip /function/function.zip +COPY --from=build /home/app/aws-lambda-rie /usr/bin/aws-lambda-rie +ENTRYPOINT [ "/function/bootstrap" ] +CMD [ "example.App::sayHello" ] +``` + +pom.xml +```xml + + 4.0.0 + example + hello-lambda-native + 1.0-SNAPSHOT + + + 11 + 11 + com.amazonaws.services.lambda.runtime.api.client.AWSLambda + + + + + com.amazonaws + aws-lambda-java-runtime-interface-client + 1.0.0 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.0 + + ${jdk.version} + ${release.version} + UTF-8 + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.1.2 + + + copy-dependencies + prepare-package + + copy-dependencies + + + + ${project.build.directory}/libs + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + true + libs/ + ${exec.mainClass} + + + + + + + + + + +``` + +### Custom Runtime + +just build the image with Docker: + +```bash +docker build -t hello-lambda-native:latest . +``` + +Then extract the Custom Runtime deployable zip bundle with this command: + +```bash +docker cp $(docker create hello-lambda-native:latest):/function/function.zip . +``` + +### Container with native compilation + +just build the image with Docker: + +```bash +docker build -t hello-lambda-native:latest . +``` + +This image can be deployed directly. + +### Local Testing + +just build the image with Docker: + +```bash +docker build -t hello-lambda-native:latest . +``` + +Then you can run the image locally: + +```bash +docker run -p 9000:8080 hello-lambda-native:latest +``` + +And test it from another Terminal/Console with: + +```bash +curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}' +``` + ## Security If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. diff --git a/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/jni-config.json b/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/jni-config.json new file mode 100644 index 00000000..e6c7da3c --- /dev/null +++ b/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/jni-config.json @@ -0,0 +1,11 @@ +[ +{ + "name":"com.amazonaws.services.lambda.runtime.api.client.runtimeapi.LambdaRuntimeClientException", + "methods":[{"name":"","parameterTypes":["java.lang.String","int"] }] +}, +{ + "name":"com.amazonaws.services.lambda.runtime.api.client.runtimeapi.InvocationRequest", + "fields":[{"name":"id"}, {"name":"invokedFunctionArn"}, {"name":"deadlineTimeInMs"}, {"name":"xrayTraceId"}, {"name":"clientContext"}, {"name":"cognitoIdentity"}, {"name":"content"}], + "allPublicMethods":true +} +] diff --git a/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/native-image.properties b/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/native-image.properties new file mode 100644 index 00000000..1ca4a3ca --- /dev/null +++ b/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/native-image.properties @@ -0,0 +1,4 @@ +Args = --initialize-at-build-time=jdk.xml.internal.SecuritySupport \ +-H:ReflectionConfigurationResources=${.}/reflect-config.json \ +-H:JNIConfigurationResources=${.}/jni-config.json \ +-H:ResourceConfigurationResources=${.}/resource-config.json diff --git a/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/reflect-config.json b/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/reflect-config.json new file mode 100644 index 00000000..630a721e --- /dev/null +++ b/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/reflect-config.json @@ -0,0 +1,34 @@ +[ +{ + "name":"com.amazonaws.lambda.thirdparty.com.fasterxml.jackson.databind.deser.Deserializers[]" +}, +{ + "name":"com.amazonaws.lambda.thirdparty.com.fasterxml.jackson.databind.ext.Java7SupportImpl", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"com.amazonaws.services.lambda.runtime.LambdaRuntime", + "fields":[{"name":"logger"}] +}, +{ + "name":"java.lang.Void", + "methods":[{"name":"","parameterTypes":[] }] +}, +{ + "name":"java.util.Collections$UnmodifiableMap", + "fields":[{"name":"m"}] +}, +{ + "name":"jdk.internal.module.IllegalAccessLogger", + "fields":[{"name":"logger"}] +}, +{ + "name":"sun.misc.Unsafe", + "fields":[{"name":"theUnsafe"}] +}, +{ + "name":"com.amazonaws.services.lambda.runtime.api.client.runtimeapi.InvocationRequest", + "fields":[{"name":"id"}, {"name":"invokedFunctionArn"}, {"name":"deadlineTimeInMs"}, {"name":"xrayTraceId"}, {"name":"clientContext"}, {"name":"cognitoIdentity"}, {"name":"content"}], + "allPublicMethods":true +} +] diff --git a/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/resource-config.json b/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/resource-config.json new file mode 100644 index 00000000..18f4ba9b --- /dev/null +++ b/aws-lambda-java-runtime-interface-client/src/main/resources/META-INF/native-image/com.amazonaws/aws-lambda-java-runtime-interface-client/resource-config.json @@ -0,0 +1,8 @@ +{ + "resources":{ + "includes":[ + {"pattern":"\\Qaws-lambda-runtime-interface-client.glibc.so\\E"}, + {"pattern":"\\Qaws-lambda-runtime-interface-client.musl.so\\E"} + ]}, + "bundles":[] +}