¿Cómo utilizo AWS SAM para crear un recurso personalizado respaldado por Lambda en Java para CloudFormation?

7 minutos de lectura
0

Quiero usar Java para crear un recurso personalizado respaldado por AWS Lambda para implementarlo en AWS CloudFormation.

Descripción breve

Crear un recurso personalizado basado en Java en Lambda para CloudFormation es un proceso complejo, sobre todo si lo realiza de forma manual. Para configurar el entorno de forma manual, debe configurar el kit de desarrollo de Java y el tiempo de ejecución antes de crear el recurso. A continuación, debe empaquetar y cargar el código en Amazon Simple Storage Service (Amazon S3) antes de crear finalmente la función Lambda.

Para simplificar este proceso, puede utilizar el AWS Serverless Application Model (AWS SAM). AWS SAM es un marco de código abierto que puede utilizar para crear aplicaciones sin servidor en AWS. Utilice este servicio para ayudar a crear el recurso personalizado de Java, cargar los códigos e implementar el recurso personalizado y la función Lambda.

Resolución

Crear una instancia para el desarrollo

1.    Cree una instancia de Amazon Elastic Compute Cloud (Amazon EC2) para desarrollar su recurso. Puede utilizar cualquier entorno para su instancia, pero se recomienda crear su instancia en Amazon Linux 2 para este caso de uso.

2.    Cree y asigne un par de claves SSH de Amazon EC2 a su instancia de EC2.

3.    Configure un perfil de instancia con permisos para implementar una pila y un recurso. Específicamente, conceda permisos para realizar las siguientes acciones:

  • Crear una función Lambda
  • Actualizar un código de función
  • Invocar una función
  • Crear un grupo de registros que almacene el registro de Lambda

4.    Tras lanzar su instancia, inicie sesión con SSH. Use esta instancia como entorno de desarrollo en la siguiente sección.

Configure su entorno de desarrollo

Importante: Antes de empezar, instale y configure la AWS Command Line Interface (AWS CLI). Si recibe errores al ejecutar los comandos de AWS CLI, asegúrese de que está utilizando la versión más reciente de AWS CLI.

Instalar java-corretto11

Para instalar corretto11, ejecute el siguiente comando:

sudo rpm --import https://yum.corretto.aws/corretto.key   
sudo curl -L -o /etc/yum.repos.d/corretto.repo https://yum.corretto.aws/corretto.repo  
sudo yum install -y java-11-amazon-corretto-devel

Compruebe la instalación con el siguiente comando:

java -version

Para obtener más información, consulte Instalar Amazon Corretto 11 en Linux basado en RPM.

Instalar AWS SAM

Para instalar AWS SAM, ejecute el siguiente comando:

wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip
unzip aws-sam-cli-linux-x86_64.zip -d sam-installation
sudo ./sam-installation/install
sam --version

Para obtener más información, consulte Instalar AWS SAM CLI.

Instalar Gradle

Para instalar Gradle, ejecute el siguiente comando:

wget https://services.gradle.org/distributions/gradle-7.6-bin.zip
sudo mkdir /opt/gradle
sudo unzip -d /opt/gradle gradle-7.6-bin.zip
export PATH=$PATH:/opt/gradle/gradle-7.6/bin
gradle -v

Para obtener más información, consulte Instalar con un administrador de paquetes en el sitio web de Gradle.

Nota: Puede que tenga que volver a exportar la RUTA después de reiniciar. Para evitar este paso, añada la siguiente línea al archivo ~/.bashrc:

export PATH=$PATH:/opt/gradle/gradle-7.6/bin

Crear el proyecto y los archivos

Para crear la carpeta raíz del proyecto SAM, ejecute el siguiente comando:

mkdir javaBasedCustomResource
cd javaBasedCustomResource/

Para crear las carpetas necesarias para su proyecto, ejecute el siguiente comando:

mkdir -p src/Function/src/main/java/

Crear los archivos del proyecto a través del editor de texto Vim. Para obtener más información, consulte el sitio web de Vim. Copie el siguiente contenido para ejecutarlo en Vim:

vim template.yaml
vim ./src/Function/build.gradle
vim ./src/Function/src/main/java/Handler.java

La estructura de su proyecto se parece al siguiente árbol estructural:

.
└── javaBasedCustomResource
    ├── src
    │   └── Function
    │       ├── build.gradle
    │       └── src
    │           └── main
    │               └── java
    │                   └── Handler.java
    └── template.yaml

Consulte las siguientes secciones para ver las plantillas de archivos y crear su proyecto.

template.yaml

Use la siguiente plantilla para la pila. Esto define la función Lambda, el grupo de registro y CustomResource:

Transform: AWS::Serverless-2016-10-31
Resources:
  CustomResourceJavaBased:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !Join ["", [ !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:", !Ref CustomResourceLambdaInJava]]
      DummyKey: DummyValue

  CustomResourceLambdaInJava:
    Type: AWS::Serverless::Function
    Properties:
      Description: !Sub
        - Stack ${AWS::StackName} Function ${ResourceName}
        - ResourceName: CustomResourceLambdaInJava
      CodeUri: src/Function
      Handler: Handler::handleRequest
      Runtime: java11
      MemorySize: 3008
      Timeout: 30
      Tracing: Active
  CustomResourceLambdaInJavaLogGroup:
    Type: AWS::Logs::LogGroup
    DeletionPolicy: Retain
    Properties:
      LogGroupName: !Sub /aws/lambda/${CustomResourceLambdaInJava}

build.gradle

Utilice la siguiente plantilla de archivo para facilitar la compilación de Java:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.amazonaws:aws-lambda-java-core:1.2.2'
    implementation 'com.amazonaws:aws-lambda-java-events:3.11.0'
    implementation 'com.google.code.gson:gson:2.10'

}

task buildZip(type: Zip) {
    from compileJava
    from processResources
    into('lib') {
        from configurations.compileClasspath
    }
}

build.dependsOn buildZip

Handler.java

Lambda ejecuta el siguiente código. Esto establece el evento de entrada en un mapa desde el que puede obtener la URL del punto de enlace necesario para enviar la respuesta. Coloque todos los parámetros necesarios en una cadena JSON y envíe una solicitud HTTP al punto de enlace:

import com.google.gson.Gson;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

import java.util.*;
import java.io.*;

public class Handler {
    public String handleRequest(Object event) {
    /* Customer workload */
    System.out.println("Dummy CustomResource Job");

    /* sending signal back to CFN stack */
    try {
        sendResponse(event);
    }
    catch (Exception e){
        System.out.println("Got Exception!!");
        e.printStackTrace(System.out);
    }

        return "JobFinished";
    }


    public void sendResponse(Object event) throws IOException, InterruptedException {
    System.out.println("start sending signal");

    Gson gson = new Gson();
    String eventJson = gson.toJson(event);
    Map map = gson.fromJson(eventJson, Map.class);

    System.out.println("Request event: " + eventJson);

    /* Generate response  parameters */
    String putEndpoint = (String)map.get("ResponseURL");

    String Status = "SUCCESS"; // "SUCCESS" or "FAILED"

    String Reason = "Dummy reason for Java based Custom Resource";

    String PhysicalResourceId = "CustomResourcePhysicalID";

    String StackId = (String)map.get("StackId");

    String RequestId = (String)map.get("RequestId");

    String LogicalResourceId = (String)map.get("LogicalResourceId");

    /* Building response */
        String responseJson = "{\"Status\":\"" + Status + "\",\"Reason\":\"" + Reason + "\",\"PhysicalResourceId\":\"" + PhysicalResourceId + "\",\"StackId\":\"" + StackId + "\",\"RequestId\":\"" + RequestId + "\",\"LogicalResourceId\":\"" + LogicalResourceId + "\",\"NoEcho\":false,\"Data\":{\"Key\":\"Value\"}}";

    System.out.println("Response event: " + responseJson);

    var request = HttpRequest.newBuilder()
            .uri(URI.create(putEndpoint))
            .header("Content-Type", "application/json")
            .PUT(HttpRequest.BodyPublishers.ofString(responseJson))
            .build();

        var client = HttpClient.newHttpClient();

    /* Sending Response */
    System.out.println("Sending Response to stack, response code: ");

        var response = client.send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println(response.statusCode());
        System.out.println(response.body());

    System.out.println("Finish sending signal");
    }
}

Despliegue el proyecto

1.    Después de crear su proyecto SAM de AWS, ejecute el siguiente comando en la carpeta raíz del proyecto javaBasedCustomResource:

sam build

2.    Para desplegar el proyecto, ejecute el siguiente comando. Esto inicia una guía en la que se le pide que especifique el nombre de la pila y la región de AWS en la que desea crear los recursos:

sam deploy --guided

Esto despliega una pila de CloudFormation en su cuenta con el nombre que especificó. La pila contiene una función Lambda que ejecuta el código de los pasos anteriores. CloudFormation también crea el tipo de recurso personalizado AWS::CloudFormation::CustomResource en la misma pila.

Cuando CloudFormation crea AWS::CloudFormation::CustomResource, CloudFormation también invoca la función Lambda anterior. En respuesta, la función Lambda envía una señal de ÉXITO a CloudFormation. Esta señal de ÉXITO envía el recurso a CreateComplete.

Cuando vea que el recurso personalizado de la pila se ha creado correctamente, significa que Lambda también se está ejecutando correctamente. Lambda devuelve la señal a la pila y el recurso personalizado basado en Java se inicia exitosamente.

Puede consultar los registros de Lambda para obtener más detalles sobre las métricas, como el evento de solicitud y el evento de respuesta. Puede modificar el código de la función para especificar sus propias tareas o crear sus propios recursos.

OFICIAL DE AWS
OFICIAL DE AWSActualizada hace un año