Implementar funciones de Lambda Java con archivos de archivo .zip o JAR - AWS Lambda

Implementar funciones de Lambda Java con archivos de archivo .zip o JAR

El código de la función AWS Lambda se compone de scripts o programas compilados y sus dependencias. Utiliza un paquete de implementación para implementar su código de función en Lambda. Lambda admite dos tipos de paquetes de implementación: imágenes de contenedor y archivos .zip.

Esta página describe cómo crear un archivo.zip o archivo Jar en su paquete de implementación y luego usar el archivo para implementar el código de función a AWS Lambda con el AWS Command Line Interface (AWS CLI).

Requisitos previos

La AWS CLI es una herramienta de código abierto que lo habitlita para interactuar con los servicios de AWS mediante el uso de comandos en el shell de la línea de comandos. Para completar los pasos de esta sección, debe disponer de lo siguiente:

Herramientas y bibliotecas

Lambda proporciona las siguientes bibliotecas de funciones de Java:

Estas bibliotecas están disponibles en el repositorio central de Maven. Agréguelas a la definición de la compilación de la siguiente manera:

Gradle
dependencies { implementation 'com.amazonaws:aws-lambda-java-core:1.2.2' implementation 'com.amazonaws:aws-lambda-java-events:3.11.1' runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.5.1' }
Maven
<dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-core</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-events</artifactId> <version>3.11.1</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-log4j2</artifactId> <version>1.5.1</version> </dependency> </dependencies>

Para crear un paquete de implementación, compile el código de función y las dependencias en un único archivo .zip o Java Archive (JAR). En el caso de Gradle, use el tipo de compilación Zip. En el caso de Apache Maven, use el complemento Maven Shade. Cargue el paquete de despliegue a través de la consola de Lambda, la API de Lambda o AWS Serverless Application Model (AWS SAM).

nota

Para que el tamaño del paquete de implementación sea reducido, empaquete las dependencias de la función en capas. Las capas le permiten administrar las dependencias de forma independiente, pueden utilizarlas varias funciones y pueden compartirse con otras cuentas. Para obtener más información, consulte Administración de las dependencias de Lambda con capas.

Compilación de un paquete de implementación con Gradle

Utilice el tipo de compilación Zip para crear un paquete de despliegue con el código de función y las dependencias de Gradle. Este es un ejemplo de un archivo build.gradle de muestra completo:

ejemplo build.gradle: tarea de compilación
task buildZip(type: Zip) { into('lib') { from(jar) from(configurations.runtimeClasspath) } }

Esta configuración de compilación produce un paquete de implementación en el directorio build/distributions. Dentro de la instrucción into('lib'), la tarea jar crea un archivo JAR que contiene las clases principales en una carpeta denominada lib. A continuación, la tarea configurations.runtimeClassPath copia las bibliotecas de dependencias de la ruta de clases de la compilación en el mismo archivo lib.

ejemplo build.gradle: dependencias
dependencies { ... implementation 'com.amazonaws:aws-lambda-java-core:1.2.2' implementation 'com.amazonaws:aws-lambda-java-events:3.11.1' implementation 'org.apache.logging.log4j:log4j-api:2.17.1' implementation 'org.apache.logging.log4j:log4j-core:2.17.1' runtimeOnly 'org.apache.logging.log4j:log4j-slf4j18-impl:2.17.1' runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.5.1' ... }

Lambda carga los archivos JAR en orden alfabético Unicode. Si hay varios archivos JAR en el directorio lib que contienen la misma clase, se utiliza el primero. Puede utilizar el siguiente script de shell para identificar las clases duplicadas.

ejemplo test-zip.sh
mkdir -p expanded unzip path/to/my/function.zip -d expanded find ./expanded/lib -name '*.jar' | xargs -n1 zipinfo -1 | grep '.*.class' | sort | uniq -c | sort

Creación de una capa de Java para las dependencias

nota

El uso de capas con funciones en un lenguaje compilado, como Java, puede no ofrecer las mismas ventajas que con un lenguaje interpretado, como Python. Como Java es un lenguaje compilado, las funciones aún tienen que cargar de forma manual los ensamblajes compartidos en la memoria durante la fase de inicio, lo que puede aumentar los tiempos de arranque en frío. En su lugar, se recomienda incluir cualquier código compartido en el momento de la compilación para aprovechar las optimizaciones del compilador integradas.

En las instrucciones de esta sección, se muestra cómo incluir las dependencias en una capa. Para obtener instrucciones sobre cómo incluir las dependencias en el paquete de implementación, consulte Compilación de un paquete de implementación con Gradle o Compilación de un paquete de implementación con Maven.

Cuando agrega una capa a una función, Lambda carga el contenido de la capa en el directorio /opt de ese entorno de ejecución. Para cada tiempo de ejecución de Lambda, la variable PATH ya incluye rutas de carpeta específicas en el directorio /opt. Para garantizar que la variable PATH recoja el contenido de la capa, el archivo.zip de la capa, debe tener sus dependencias en las siguientes rutas de carpeta:

  • java/lib (CLASSPATH)

Por ejemplo, la estructura del archivo .zip de la capa podría tener el siguiente aspecto:

jackson.zip └ java/lib/jackson-core-2.2.3.jar

Además, Lambda detecta de forma automática cualquier biblioteca en el directorio /opt/lib y todos los archivos binarios en el directorio /opt/bin. Para asegurarse de que Lambda encuentre el contenido de la capa de forma correcta, también puede crear una capa con la siguiente estructura:

custom-layer.zip └ lib | lib_1 | lib_2 └ bin | bin_1 | bin_2

Después de empaquetar la capa, consulte Creación y eliminación de capas en Lambda y Adición de capas a las funciones para completar la configuración de la capa.

Compilación de un paquete de implementación con Maven

Para crear un paquete de implementación con Maven, use el complemento Maven Shade. El complemento crea un archivo JAR que contiene el código compilado de la función y todas sus dependencias.

ejemplo pom.xml: configuración del complemento
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.2</version> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin>

Para crear el paquete de implementación, utilice el comando mvn package.

[INFO] Scanning for projects... [INFO] -----------------------< com.example:java-maven >----------------------- [INFO] Building java-maven-function 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- ... [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ java-maven --- [INFO] Building jar: target/java-maven-1.0-SNAPSHOT.jar [INFO] [INFO] --- maven-shade-plugin:3.2.2:shade (default) @ java-maven --- [INFO] Including com.amazonaws:aws-lambda-java-core:jar:1.2.2 in the shaded jar. [INFO] Including com.amazonaws:aws-lambda-java-events:jar:3.11.1 in the shaded jar. [INFO] Including joda-time:joda-time:jar:2.6 in the shaded jar. [INFO] Including com.google.code.gson:gson:jar:2.8.6 in the shaded jar. [INFO] Replacing original artifact with shaded artifact. [INFO] Replacing target/java-maven-1.0-SNAPSHOT.jar with target/java-maven-1.0-SNAPSHOT-shaded.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 8.321 s [INFO] Finished at: 2020-03-03T09:07:19Z [INFO] ------------------------------------------------------------------------

Este comando genera un archivo JAR en el directorio target.

nota

Si trabaja con un JAR de varias versiones (MRJAR), debe incluir el MRJAR (es decir, el JAR sombreado producido por el complemento Maven Shade) en el directorio lib y comprimirlo antes de subir el paquete de despliegue a Lambda. De lo contrario, es posible que Lambda no descomprima correctamente el archivo JAR, lo que hará que se ignore el archivo MANIFEST.MF.

Si utiliza la biblioteca de appender (aws-lambda-java-log4j2), también debe configurar un transformador para el complemento Maven Shade. La biblioteca de transformadores combina versiones de un archivo de caché que aparecen tanto en la biblioteca de appender como en Log4j.

ejemplo pom.xml: configuración del complemento con el appender Log4j 2
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.2</version> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="com.github.edwgiz.maven_shade_plugin.log4j2_cache_transformer.PluginsCacheFileTransformer"> </transformer> </transformers> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>com.github.edwgiz</groupId> <artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId> <version>2.13.0</version> </dependency> </dependencies> </plugin>

Carga de un paquete de despliegue con la consola de Lambda

Para crear una nueva función, primero debe crearla en la consola y, a continuación, cargar el archivo .zip o JAR. Para actualizar una función existente, abra la página de la función y, a continuación, siga el mismo procedimiento para agregar el archivo .zip o JAR actualizado.

Si el archivo del paquete de despliegue tiene un tamaño inferior a los 50 MB, puede cargarlo directamente desde su equipo local. Para los archivos .zip o JAR de un tamaño mayor que 50 MB, es preciso cargar el paquete en un bucket de Amazon S3. Para obtener instrucciones sobre cómo cargar un archivo en un bucket de Amazon S3 con la AWS Management Console, consulte Introducción a Amazon S3. Para cargar archivos mediante la AWS CLI, consulte Mover objetos en la Guía del usuario de la AWS CLI.

nota

No puede cambiar el tipo de paquete de implementación (.zip o imagen de contenedor) de una función existente. Por ejemplo, no se puede convertir una función de imagen de contenedor para utilizar un archivo .zip. Debe crear una nueva función.

Para crear una nueva función (consola)
  1. Abra la página Funciones de la consola de Lambda y elija Crear función.

  2. Elija Crear desde cero.

  3. En Información básica, haga lo siguiente:

    1. En Nombre de la función, escriba el nombre de la función.

    2. En Tiempo de ejecución, seleccione el tiempo de ejecución que desea utilizar.

    3. (Opcional) Para Arquitectura, elija la arquitectura del conjunto de instrucciones para su función. La arquitectura predeterminada es x86_64. Asegúrese de que el paquete de despliegue .zip para su función sea compatible con la arquitectura del conjunto de instrucciones que seleccione.

  4. (Opcional) En Permisos, expanda Cambiar función de ejecución predeterminada. Puede crear un nuevo Rol de ejecución o utilizar uno existente.

  5. Elija Crear función. Lambda crea una función básica “Hola, mundo” mediante el tiempo de ejecución elegido.

Para cargar un archivo .zip o JAR desde su equipo local (consola)
  1. En la página Funciones de la consola de Lambda, elija la función para la que desea cargar el archivo .zip o JAR.

  2. Seleccione la pestaña Código.

  3. En el panel Código fuente, elija Cargar desde.

  4. Elija archivo .zip o .jar.

  5. Para cargar un archivo .zip o JAR, haga lo siguiente:

    1. Seleccione Cargar y, a continuación, seleccione su archivo .zip o JAR en el selector de archivos.

    2. Elija Abrir.

    3. Seleccione Guardar.

Para cargar un archivo .zip o JAR desde un bucket de Amazon S3 (consola)
  1. En la página Funciones de la consola de Lambda, elija la función para la que desea cargar un nuevo archivo .zip o JAR.

  2. Seleccione la pestaña Código.

  3. En el panel Código fuente, elija Cargar desde.

  4. Elija la ubicación de Amazon S3.

  5. Pegue la URL del enlace de Amazon S3 de su archivo .zip y seleccione Guardar.

Carga de un paquete de despliegue con la AWS CLI

Puede utilizar la AWS CLI para crear una nueva función o actualizar una existente mediante un archivo .zip o JAR. Utilice los comandos create-function y update-function-code para implementar el paquete .zip o JAR. Si el archivo tiene un tamaño inferior a los 50 MB, puede cargarlo desde su equipo de compilación local. Para archivos más grandes, es preciso cargar el paquete .zip o JAR desde un bucket de Amazon S3. Para obtener instrucciones sobre cómo cargar un archivo en un bucket de Amazon S3 con la AWS CLI, consulte Mover objetos en la Guía del usuario de la AWS CLI.

nota

Si carga su archivo .zip o JAR desde un bucket de Amazon S3 con la AWS CLI, el bucket debe estar ubicado en la misma Región de AWS que su función.

Para crear una nueva función mediante un archivo .zip o JAR con la AWS CLI, debe especificar lo siguiente:

  • El nombre de la función (--function-name).

  • El tiempo de ejecución de la función (--runtime).

  • El nombre de recurso de Amazon (ARN) del rol de ejecución de la función (--role).

  • El nombre del método de controlador en el código de la función (--handler).

También debe especificar la ubicación del archivo .zip o JAR. Si el archivo .zip o JAR se encuentra en una carpeta de su equipo de compilación local, utilice la opción --zip-file para especificar la ruta del archivo, tal como se muestra en el siguiente comando de ejemplo.

aws lambda create-function --function-name myFunction \ --runtime java21 --handler example.handler \ --role arn:aws:iam::123456789012:role/service-role/my-lambda-role \ --zip-file fileb://myFunction.zip

Para especificar la ubicación del archivo .zip en un bucket de Amazon S3, utilice la opción --code, como se muestra en el siguiente comando de ejemplo. Solo necesita utilizar el parámetro S3ObjectVersion para los objetos con versiones.

aws lambda create-function --function-name myFunction \ --runtime java21 --handler example.handler \ --role arn:aws:iam::123456789012:role/service-role/my-lambda-role \ --code S3Bucket=DOC-EXAMPLE-BUCKET,S3Key=myFileName.zip,S3ObjectVersion=myObjectVersion

Para actualizar una función existente mediante la CLI, especifique el nombre de la función mediante el parámetro --function-name. También debe especificar la ubicación del archivo .zip que desea utilizar para actualizar el código de la función. Si el archivo .zip se encuentra en una carpeta de su equipo de compilación local, utilice la opción --zip-file para especificar la ruta del archivo, como se muestra en el siguiente comando de ejemplo.

aws lambda update-function-code --function-name myFunction \ --zip-file fileb://myFunction.zip

Para especificar la ubicación del archivo .zip en un bucket de Amazon S3, utilice las opciones --s3-bucket--s3-key tal como se muestra en el siguiente comando de ejemplo. Solo necesita usar el parámetro --s3-object-version para los objetos con versiones.

aws lambda update-function-code --function-name myFunction \ --s3-bucket DOC-EXAMPLE-BUCKET --s3-key myFileName.zip --s3-object-version myObject Version

Carga de un paquete de implementación con AWS SAM

Puede usar el AWS SAM para automatizar las implementaciones del código de función, la configuración y las dependencias. AWS SAM es una extensión de AWS CloudFormation que proporciona una sintaxis simplificada para definir aplicaciones sin servidor. En la siguiente plantilla de ejemplo, se define una función con un paquete de implementación en el directorio build/distributions que usa Gradle:

ejemplo template.yml
AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: An AWS Lambda application that calls the Lambda API. Resources: function: Type: AWS::Serverless::Function Properties: CodeUri: build/distributions/java-basic.zip Handler: example.Handler Runtime: java21 Description: Java function MemorySize: 512 Timeout: 10 # Function's execution role Policies: - AWSLambdaBasicExecutionRole - AWSLambda_ReadOnlyAccess - AWSXrayWriteOnlyAccess - AWSLambdaVPCAccessExecutionRole Tracing: Active

Para crear la función, utilice los comandos package y deploy. Estos comandos son personalizaciones de la CLI de AWS CLI. Contienen otros comandos que van a cargar el paquete de implementación en Amazon S3, reescribir la plantilla con el URI del objeto y actualizar el código de la función.

El siguiente script de ejemplo ejecuta una compilación de Gradle y carga el paquete de implementación que crea. Crea una pila de AWS CloudFormation la primera vez que la ejecuta. Si la pila ya existe, el script la actualiza.

ejemplo deploy.sh
#!/bin/bash set -eo pipefail aws cloudformation package --template-file template.yml --s3-bucket MY_BUCKET --output-template-file out.yml aws cloudformation deploy --template-file out.yml --stack-name java-basic --capabilities CAPABILITY_NAMED_IAM

Para ver un ejemplo completo, consulte las siguientes aplicaciones:

Aplicaciones de Lambda de ejemplo en Java
  • java17-examples: una función de Java que demuestra cómo utilizar un registro de Java para representar un objeto de datos de eventos de entrada.

  • java-basic: una colección de funciones de Java mínimas con pruebas unitarias y configuración de registro variable.

  • java-events: una colección de funciones Java que contiene un código básico sobre cómo gestionar los eventos de varios servicios, como Amazon API Gateway, Amazon SQS y Amazon Kinesis. Estas funciones utilizan la última versión de la biblioteca aws-lambda-java-events (3.0.0 y más recientes). Estos ejemplos no requieren utilizar AWS SDK como una dependencia.

  • s3-java: una función de Java que procesa los eventos de notificación de Amazon S3 y utiliza Java Class Library (JCL) para crear miniaturas de los archivos de imagen cargados.

  • Uso de API Gateway para invocar una función de Lambda: una función Java que escanea una tabla de Amazon DynamoDB que contiene información sobre los empleados. Luego, utiliza Amazon Simple Notification Service para enviar un mensaje de texto a los empleados que celebran sus aniversarios laborales. En este ejemplo, se utiliza API Gateway para invocar la función.