Comment utiliser AWS SAM pour créer une ressource personnalisée basée sur Lambda dans Java pour CloudFormation ?

Lecture de 7 minute(s)
0

Je souhaite utiliser Java pour créer une ressource personnalisée basée sur AWS Lambda à implémenter dans AWS CloudFormation.

Brève description

La création d'une ressource personnalisée basée sur Java dans Lambda pour CloudFormation est un processus complexe, surtout si vous le faites manuellement. Pour configurer l'environnement manuellement, vous devez configurer le kit de développement Java et le moteur d'exécution avant de créer la ressource. Vous devez ensuite empaqueter et charger le code sur Amazon Simple Storage Service (Amazon S3) avant de créer définitivement la fonction Lambda.

Pour simplifier ce processus, vous pouvez utiliser le modèle d'application sans serveur AWS (AWS SAM). AWS SAM est un framework open source que vous pouvez utiliser pour créer des applications sans serveur sur AWS. Utilisez ce service pour créer la ressource personnalisée Java, charger vos codes et déployer la ressource personnalisée ainsi que la fonction Lambda.

Résolution

Créez une instance pour le développement

1.Créez une instance Amazon Elastic Compute Cloud (Amazon EC2) pour développer votre ressource. Vous pouvez utiliser tout environnement pour votre instance, mais il est recommandé de créer votre instance dans Amazon Linux 2 pour ce cas d'utilisation.

2.Créez et attribuez une paire de clés SSH Amazon EC2 à votre instance EC2.

3.Configurez un profil d'instance avec des autorisations pour déployer une pile et une ressource. Concrètement, accordez les autorisations nécessaires pour effectuer les actions suivantes :

  • Créer une fonction Lambda
  • Mettre à jour le code de fonction
  • Invoquer une fonction
  • Créer un groupe de journaux qui stocke le journal du Lambda

4.Après avoir lancé votre instance, connectez-vous via SSH. Utilisez cette instance comme environnement de développement dans la section suivante.

Configurez votre environnement de développement

**Remarque :**Avant de commencer, installez et configurez l'interface de la ligne de commande AWS (AWS CLI). Si vous recevez des erreurs lors de l'exécution des commandes de l'interface de la ligne de commande AWS, assurez-vous que vous utilisez la version la plus récente de AWS CLI.

Installer java-corretto11

Pour installer corretto11, exécutez la commande suivante :

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

Vérifiez l'installation à l'aide de la commande suivante :

java -version

Pour plus d'informations, consultez Installer Amazon Corretto 11 sur un système Linux basé sur RPM.

Installer AWS SAM

Pour installer AWS SAM, exécutez la commande suivante :

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

Pour plus d'informations, consultez Installation de l'interface de la ligne de commande AWS SAM.

Installer Gradle

Pour installer Gradle, exécutez la commande suivante :

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

Pour plus d'informations, consultez Installation à l'aide d'un gestionnaire de packages sur le site Web de Gradle.

**Remarque :**Il n’est pas exclu que vous ayez à exporter à nouveau le PATH après le redémarrage. Pour éviter cette étape, ajoutez la ligne suivante au fichier ~/.bashrc :

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

Créer le projet et les fichiers

Pour créer le dossier racine du projet SAM, exécutez la commande suivante :

mkdir javaBasedCustomResource
cd javaBasedCustomResource/

Pour créer les dossiers nécessaires à votre projet, exécutez la commande suivante :

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

Créez les fichiers du projet via l'éditeur de texte Vim. Pour plus d'informations, consultez le site Web de Vim. Copiez le contenu suivant pour l'exécuter dans Vim :

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

La structure de votre projet ressemble à l'arbre structurel suivant :

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

Consultez les sections suivantes pour les modèles de fichiers permettant de créer votre projet.

template.yaml

Utilisez le modèle suivant pour la pile. Cela définit la fonction Lambda, le groupe de journaux et **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

Utilisez le modèle de fichier suivant pour faciliter votre compilation 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 exécute le code suivant. Cette action définit l'événement d'entrée comme une carte à partir de laquelle vous pouvez obtenir l'URL du point de terminaison nécessaire pour renvoyer la réponse. Mettez tous les paramètres nécessaires dans une chaîne JSON et envoyez une requête HTTP au point de terminaison :

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");
    }
}

Déployer le projet

1.Après avoir créé votre projet AWS SAM, exécutez la commande suivante dans le dossier racine du projet javaBasedCustomResource :

sam build

2.Pour déployer le projet, exécutez la commande suivante. L’action lance un guide qui vous invite à spécifier le nom de la pile et la Région AWS dans laquelle vous souhaitez que les ressources soient créées :

sam deploy --guided

Cela permet de déployer une pile CloudFormation dans votre compte avec le nom spécifié. La pile contient une fonction Lambda qui exécute le code des étapes précédentes. CloudFormation crée également le type de ressource personnalisé AWS::CloudFormation::CustomResource dans la même pile.

Lorsque CloudFormation crée AWS::CloudFormation::CustomResource, CloudFormation appelle également la fonction Lambda ci-dessus. En réponse, la fonction Lambda renvoie un signal SUCCÈS à CloudFormation. Ce signal SUCCÈSenvoie la ressource à CreateComplete.

Lorsque vous la ressource personnalisée de la pile a été créée avec succès, cela signifie que Lambda également fonctionne correctement. Lambda renvoie le signal à la pile et la ressource personnalisée basée sur Java démarre correctement.

Vous pouvez consulter les journaux Lambda pour plus de détails sur des métriques telles que l'événement de demande et l'événement de réponse. Vous pouvez modifier le code de fonction pour spécifier vos propres tâches ou créer vos propres ressources.

AWS OFFICIEL
AWS OFFICIELA mis à jour il y a un an