AWS re:Post을(를) 사용하면 다음에 동의하게 됩니다. AWS re:Post 이용 약관

AWS SAM을 사용하여 Java로 CloudFormation용 Lambda 지원 사용자 지정 리소스를 구축하려면 어떻게 해야 합니까?

5분 분량
0

Java를 사용하여 AWS CloudFormation에서 구현할 AWS Lambda 지원 사용자 지정 리소스를 구축하고 싶습니다.

간략한 설명

CloudFormation용 Lambda로 Java 기반 사용자 지정 리소스를 빌드하는 것은 복잡한 과정이며 수동으로 과정을 수행하는 경우 더욱 그렇습니다. 환경을 수동으로 설정하려면 리소스를 빌드하기 전에 Java 개발 키트와 런타임을 설정해야 합니다. 그런 다음 Lambda 함수를 최종적으로 생성하기 전에 코드를 패키징하여 Amazon Simple Storage Service(S3)에 업로드해야 합니다.

이 프로세스를 간소화하기 위해 AWS Serverless Application Model(AWS SAM)을 사용할 수 있습니다. AWS SAM은 AWS에서 서버리스 애플리케이션을 구축하는 데 사용할 수 있는 오픈 소스 프레임워크입니다. 이 서비스를 사용하여 Java 사용자 지정 리소스를 구축하고, 코드를 업로드하며, 사용자 지정 리소스 및 Lambda 함수를 배포할 수 있습니다.

해결 방법

개발용 인스턴스 생성

1.    Amazon Elastic Compute Cloud(Amazon EC2) 인스턴스를 생성하여 리소스를 개발합니다. 어떤 환경이든 인스턴스에 사용할 수 있지만, 이 사용 사례에는 Amazon Linux 2에서 인스턴스를 생성하는 것이 좋습니다.

2.    Amazon EC2 SSH 키 페어를 생성하고 EC2 인스턴스에 할당합니다.

3.    스택과 리소스를 배포할 권한이 있는 인스턴스 프로파일을 설정합니다. 구체적으로 다음 작업을 수행할 수 있는 권한을 부여합니다.

  • Lambda 함수 생성
  • 함수 코드 업데이트
  • 함수 호출
  • Lambda 로그를 저장하는 로그 그룹 생성

4.    인스턴스를 시작한 후 SSH로 로그인합니다. 다음 섹션에서 이 인스턴스를 개발 환경으로 사용합니다.

개발 환경 설정

중요: 시작하기 전에 AWS Command Line Interface(AWS CLI)를 설치하고 구성해야 합니다. AWS CLI 명령을 실행할 때 오류가 발생하면 최신 버전의 AWS CLI를 사용하고 있는지 확인하십시오.

java-corretto11 설치

다음 명령을 실행하여 corretto11을 설치합니다.

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

다음 명령을 사용하여 설치를 확인합니다.

java -version

자세한 내용은 RPM 기반 Linux에 Amazon Corretto 11 설치를 참조하십시오.

AWS SAM 설치

다음 명령을 실행하여 AWS SAM을 설치합니다.

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

자세한 내용은 AWS SAM CLI 설치를 참조하십시오.

Gradle 설치

다음 명령을 실행하여 Gradle을 설치합니다.

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

자세한 내용은 Gradle 웹사이트에서 패키지 관리자로 설치를 참조하십시오.

참고: 재부팅 후 PATH를 다시 내보내야 할 수 있습니다. 이 단계를 피하려면 ~/.bashrc 파일에 다음 줄을 추가합니다.

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

프로젝트 및 파일 생성

다음 명령을 실행하여 SAM 프로젝트의 루트 폴더를 생성합니다.

mkdir javaBasedCustomResource
cd javaBasedCustomResource/

다음 명령을 실행하여 프로젝트에 필요한 폴더를 생성합니다.

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

Vim 텍스트 편집기로 프로젝트 파일을 생성합니다. 자세한 내용은 Vim 웹사이트를 참조하십시오. 다음 내용을 복사하여 Vim에서 실행합니다.

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

프로젝트 구조는 다음 구조 트리와 비슷합니다.

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

프로젝트를 빌드하기 위한 파일 템플릿은 다음 섹션을 참조하십시오.

template.yaml

다음 템플릿을 스택에 사용합니다. 이는 Lambda 함수, 로그 그룹 및 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

다음 파일 템플릿을 사용하여 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가 다음 코드를 실행합니다. 이렇게 하면 입력 이벤트가 응답을 다시 보내는 데 필요한 엔드포인트 URL을 가져올 수 있는 맵으로 설정됩니다. 필요한 모든 파라미터를 JSON 문자열에 넣고 엔드포인트로 HTTP 요청을 보냅니다.

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

프로젝트 배포

1.    AWS SAM 프로젝트를 생성한 후 루트 프로젝트 폴더 javaBasedCustomResource에서 다음 명령을 실행합니다.

sam build

2.    다음 명령을 실행하여 프로젝트를 배포합니다. 그러면 리소스를 생성할 스택 이름과 AWS 리전을 지정하라는 안내가 시작됩니다.

sam deploy --guided

이렇게 하면 지정한 이름으로 계정에 CloudFormation 스택이 배포됩니다. 스택에는 이전 단계의 코드를 실행하는 Lambda 함수가 포함되어 있습니다. CloudFormation은 또한 같은 스택에 사용자 지정 리소스 유형 AWS::CloudFormation::CustomResource를 생성합니다.

CloudFormation은 AWS::CloudFormation::CustomResource를 생성할 때 위의 Lambda 함수도 호출합니다. Lambda 함수는 이에 대한 응답으로 SUCCESS 신호를 CloudFormation으로 다시 보냅니다. 이 SUCCESS 신호는 리소스를 CreateComplete로 보냅니다.

스택의 사용자 지정 리소스가 성공적으로 생성되면 Lambda도 성공적으로 실행되고 있음을 의미합니다. Lambda는 신호를 스택으로 반환하고 Java 기반 사용자 지정 리소스가 성공적으로 시작됩니다.

요청 이벤트 및 응답 이벤트와 같은 지표에 대한 자세한 내용은 Lambda 로그를 확인할 수 있습니다. 함수 코드를 수정하여 고유한 작업을 지정하거나 고유한 리소스를 생성할 수 있습니다.

AWS 공식
AWS 공식업데이트됨 2년 전