

# 자습서: 사용자 지정 런타임 빌드
<a name="runtimes-walkthrough"></a>

이 자습서에서는 사용자 지정 런타임이 있는 Lambda 함수를 생성합니다. 먼저 함수의 배포 패키지에 런타임을 포함시킵니다. 그런 다음, 이 런타임을 함수와는 별도로 관리하는 계층으로 마이그레이션합니다. 마지막으로 리소스 기반 권한 정책을 업데이트하여 런타임 계층을 다른 모든 사용자와 공유합니다.

## 사전 조건
<a name="runtimes-walkthrough-prereqs"></a>

이 자습서에서는 사용자가 기본 Lambda 작업과 Lambda 콘솔에 대해 어느 정도 알고 있다고 가정합니다. 그렇지 않은 경우 [콘솔로 Lambda 함수 생성](getting-started.md#getting-started-create-function)의 지침에 따라 첫 Lambda 함수를 생성합니다.

다음 단계를 완료하려면 [AWS CLI 버전 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)가 필요합니다. 명령과 예상 결과는 별도의 블록에 나열됩니다.

```
aws --version
```

다음 결과가 표시됩니다.

```
aws-cli/2.13.27 Python/3.11.6 Linux/4.14.328-248.540.amzn2.x86_64 exe/x86_64.amzn.2
```

긴 명령의 경우 이스케이프 문자(`\`)를 사용하여 명령을 여러 행으로 분할합니다.

Linux 및 macOS는 선호 셸과 패키지 관리자를 사용합니다.

**참고**  
Windows에서는 Lambda와 함께 일반적으로 사용하는 일부 Bash CLI 명령(예:`zip`)은 운영 체제의 기본 제공 터미널에서 지원되지 않습니다. Ubuntu와 Bash의 Windows 통합 버전을 가져오려면 [Linux용 Windows Subsystem을 설치](https://docs.microsoft.com/en-us/windows/wsl/install-win10)합니다. 이 안내서의 예제 CLI 명령은 Linux 형식을 사용합니다. Windows CLI를 사용하는 경우 인라인 JSON 문서를 포함하는 명령의 형식을 다시 지정해야 합니다.

Lambda 함수를 생성하려면 IAM 역할이 필요합니다. 이 역할에는 로그를 CloudWatch Logs로 전송하는 권한과 함수에서 사용하는 AWS 서비스에 액세스하는 권한이 필요합니다. 함수 개발을 위한 역할이 없는 경우 이 역할을 하나 생성합니다.

**실행 역할을 만들려면**

1. IAM 콘솔에서 [역할 페이지](https://console.aws.amazon.com/iam/home#/roles)를 엽니다.

1. **역할 생성**을 선택합니다.

1. 다음 속성을 사용하여 역할을 만듭니다.
   + **신뢰할 수 있는 엔터티** – **Lambda**.
   + **권한** – **AWSLambdaBasicExecutionRole**.
   + **역할 이름** – **lambda-role**.

   **AWSLambdaBasicExecutionRole** 정책은 함수가 CloudWatch Logs에 로그를 쓰는 데 필요한 권한을 가집니다.

## 함수 생성
<a name="runtimes-walkthrough-function"></a>

사용자 지정 런타임이 있는 Lambda 함수를 생성합니다. 이 예제는 두 개의 파일 즉, 런타임 `bootstrap` 파일과 함수 핸들러를 포함합니다. 두 파일은 모두 Bash에서 구현됩니다.

1. 프로젝트에 대한 디렉터리를 생성하고 해당 디렉터리로 전환합니다.

   ```
   mkdir runtime-tutorial
   cd runtime-tutorial
   ```

1. `bootstrap`라는 파일을 새로 생성합니다. 사용자 지정 런타임입니다.  
**Example 부트스트랩**  

   ```
   #!/bin/sh
   
   set -euo pipefail
   
   # Initialization - load function handler
   source $LAMBDA_TASK_ROOT/"$(echo $_HANDLER | cut -d. -f1).sh"
   
   # Processing
   while true
   do
     HEADERS="$(mktemp)"
     # Get an event. The HTTP request will block until one is received
     EVENT_DATA=$(curl -sS -LD "$HEADERS" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
   
     # Extract request ID by scraping response headers received above
     REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2)
   
     # Run the handler function from the script
     RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA")
   
     # Send the response
     curl "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response"  -d "$RESPONSE"
   done
   ```

   런타임은 배포 패키지에서 함수 스크립트를 로드합니다. 런타임은 두 변수를 사용하여 스크립트를 찾습니다. `LAMBDA_TASK_ROOT`는 패키지가 추출된 위치를 알려주며 `_HANDLER`에는 스크립트의 이름이 포함됩니다.

   런타임은 함수 스크립트를 로딩한 후 런타임 API를 사용하여 Lambda에서 간접 호출 이벤트를 검색하고 이벤트를 핸들러로 전달하며 응답을 Lambda에 다시 게시합니다. 요청 ID를 가져오기 위해 런타임은 API 응답의 헤더를 임시 파일에 저장하고 이 파일에서 `Lambda-Runtime-Aws-Request-Id` 헤더를 읽습니다.
**참고**  
런타임은 오류 처리를 포함한 추가적인 책임이 있으며, 핸들러에 컨텍스트 정보를 제공합니다. 세부 정보는 [요구 사항](runtimes-custom.md#runtimes-custom-build)을 참조하세요.

1. 함수에 대해 스크립트를 생성합니다. 다음 스크립트 예는 이벤트 데이터를 취하여 이를 `stderr`에 기록한 후 반환하는 핸들러 함수를 정의합니다.  
**Example function.sh**  

   ```
   function handler () {
     EVENT_DATA=$1
     echo "$EVENT_DATA" 1>&2;
     RESPONSE="Echoing request: '$EVENT_DATA'"
   
     echo $RESPONSE
   }
   ```

   `runtime-tutorial` 디렉터리는 이제 다음과 같아야 합니다.

   ```
   runtime-tutorial
   ├ bootstrap
   └ function.sh
   ```

1. 실행 파일들을 생성하여 이를 .zip 파일 아카이브에 추가합니다. 이것이 배포 패키지입니다.

   ```
   chmod 755 function.sh bootstrap
   zip function.zip function.sh bootstrap
   ```

1. `bash-runtime`이라는 이름의 함수를 생성합니다. `--role`에 Lambda [실행 역할](lambda-intro-execution-role.md)의 ARN을 입력합니다.

   ```
   aws lambda create-function --function-name bash-runtime \
   --zip-file fileb://function.zip --handler function.handler --runtime provided.al2023 \
   --role arn:aws:iam::123456789012:role/lambda-role
   ```

1. 함수를 간접 호출합니다.

   ```
   aws lambda invoke --function-name bash-runtime --payload '{"text":"Hello"}' response.txt --cli-binary-format raw-in-base64-out
   ```

   **cli-binary-format** 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 `aws configure set cli-binary-format raw-in-base64-out`을(를) 실행하세요. 자세한 내용은 [AWS CLI 지원되는 글로벌 명령줄 옵션](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)을 AWS Command Line Interface 사용 설명서 버전 2에서 참조하세요.

   다음과 같은 응답이 표시되어야 합니다.

   ```
   {
       "StatusCode": 200,
       "ExecutedVersion": "$LATEST"
   }
   ```

1. 응답을 확인합니다.

   ```
   cat response.txt
   ```

   다음과 같은 응답이 표시되어야 합니다.

   ```
   Echoing request: '{"text":"Hello"}'
   ```

## 계층 생성
<a name="runtimes-walkthrough-layer"></a>

함수 코드에서 런타임 코드를 분리하려면 런타임만 포함하는 계층을 생성하세요. 계층을 사용하면 함수의 종속 항목들을 독립적으로 개발할 수 있으며, 여러 함수가 있는 동일한 계층을 사용할 때 스토리지 사용량을 줄일 수 있습니다. 자세한 내용은 [계층으로 Lambda 종속성 관리](chapter-layers.md) 단원을 참조하십시오.

1. `bootstrap` 파일을 포함하는 .zip 파일을 생성합니다.

   ```
   zip runtime.zip bootstrap
   ```

1. [publish-layer-version](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/publish-layer-version.html?highlight=nodejs16%20x) 명령을 사용하여 계층을 생성합니다.

   ```
   aws lambda publish-layer-version --layer-name bash-runtime --zip-file fileb://runtime.zip
   ```

   그러면 해당 계층의 첫 번째 버전이 생성됩니다.

## 함수 업데이트
<a name="runtimes-walkthrough-update"></a>

함수에 런타임 계층을 사용하려면 이 계층을 사용하도록 함수를 구성하고 함수에서 런타임 코드를 제거하세요.

1. 계층을 가져 오도록 함수 구성을 업데이트하세요.

   ```
   aws lambda update-function-configuration --function-name bash-runtime \
   --layers arn:aws:lambda:us-east-1:123456789012:layer:bash-runtime:1
   ```

   이 작업으로 `/opt` 디렉터리의 함수에 런타임이 추가됩니다. Lambda가 계층의 런타임을 사용하도록 하려면 다음 두 단계에 표시된 것처럼 함수의 배포 패키지에서 `boostrap`을 제거해야 합니다.

1. 함수 코드를 포함하는 .zip 파일을 생성합니다.

   ```
   zip function-only.zip function.sh
   ```

1. 핸들러 스크립트만 포함하도록 함수 코드를 업데이트하세요.

   ```
   aws lambda update-function-code --function-name bash-runtime --zip-file fileb://function-only.zip
   ```

1. 함수를 간접 호출하여 런타임 계층에서 작동하는지 확인합니다.

   ```
   aws lambda invoke --function-name bash-runtime --payload '{"text":"Hello"}' response.txt --cli-binary-format raw-in-base64-out
   ```

   **cli-binary-format** 옵션은 AWS CLI 버전 2를 사용할 때 필요합니다. 이 설정을 기본 설정으로 지정하려면 `aws configure set cli-binary-format raw-in-base64-out`을(를) 실행하세요. 자세한 내용은 [AWS CLI 지원되는 글로벌 명령줄 옵션](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)을 AWS Command Line Interface 사용 설명서 버전 2에서 참조하세요.

   다음과 같은 응답이 표시되어야 합니다.

   ```
   {
       "StatusCode": 200,
       "ExecutedVersion": "$LATEST"
   }
   ```

1. 응답을 확인합니다.

   ```
   cat response.txt
   ```

   다음과 같은 응답이 표시되어야 합니다.

   ```
   Echoing request: '{"text":"Hello"}'
   ```

## 런타임 업데이트
<a name="runtimes-walkthrough-runtime"></a>

1. 실행 환경에 관한 정보를 기록하려면 환경 변수를 출력하도록 런타임 스크립트를 업데이트하세요.  
**Example 부트스트랩**  

   ```
   #!/bin/sh
   
   set -euo pipefail
   
   # Configure runtime to output environment variables
   echo "##  Environment variables:"
   env
   
   # Load function handler
   source $LAMBDA_TASK_ROOT/"$(echo $_HANDLER | cut -d. -f1).sh"
   
   # Processing
   while true
   do
     HEADERS="$(mktemp)"
     # Get an event. The HTTP request will block until one is received
     EVENT_DATA=$(curl -sS -LD "$HEADERS" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
   
     # Extract request ID by scraping response headers received above
     REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2)
   
     # Run the handler function from the script
     RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA")
   
     # Send the response
     curl "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response"  -d "$RESPONSE"
   done
   ```

1. `bootstrap` 파일의 새 버전을 포함하는 .zip 파일을 생성합니다.

   ```
   zip runtime.zip bootstrap
   ```

1. `bash-runtime` 계층의 새로운 버전을 생성합니다.

   ```
   aws lambda publish-layer-version --layer-name bash-runtime --zip-file fileb://runtime.zip
   ```

1. 새 버전의 계층을 사용하도록 함수를 구성합니다.

   ```
   aws lambda update-function-configuration --function-name bash-runtime \
   --layers arn:aws:lambda:us-east-1:123456789012:layer:bash-runtime:2
   ```

## 계층 공유
<a name="runtimes-walkthrough-share"></a>

계층을 다른 AWS 계정와 공유하려면 계층의 [리소스 기반 정책](access-control-resource-based.md)에 교차 계정 권한 문을 추가합니다. [add-layer-version-permission](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/add-layer-version-permission.html) 명령을 실행하고 계정 ID를 `principal`로 지정합니다. 각 문에서 단일 계정, 모든 계정 또는 [AWS Organizations](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_introduction.html)의 조직을 대상으로 권한을 부여할 수 있습니다.

다음 예시에서는 111122223333 계정에 `bash-runtime` 계층의 버전 2에 대한 액세스 권한을 부여합니다.

```
aws lambda add-layer-version-permission \
  --layer-name bash-runtime \
  --version-number 2 \  
  --statement-id xaccount \
  --action lambda:GetLayerVersion \
  --principal 111122223333 \
  --output text
```

다음과 유사한 출력 화면이 표시되어야 합니다.

```
{"Sid":"xaccount","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::111122223333:root"},"Action":"lambda:GetLayerVersion","Resource":"arn:aws:lambda:us-east-1:123456789012:layer:bash-runtime:2"}
```

권한은 하나의 계층 버전에만 적용됩니다. 새 계층 버전을 만들 때마다 해당 과정을 반복합니다.

## 정리
<a name="runtimes-walkthrough-cleanup"></a>

각 버전의 계층을 삭제합니다.

```
aws lambda delete-layer-version --layer-name bash-runtime --version-number 1
aws lambda delete-layer-version --layer-name bash-runtime --version-number 2
```

이 함수는 계층의 버전 2에 대한 참조가 있으므로 Lambda 내에 여전히 존재합니다. 함수는 계속 작동하며, 다만 삭제된 버전을 사용하도록 함수를 구성할 수는 없습니다. 함수의 계층 목록을 수정하려면 새 버전을 지정하거나 삭제된 계층을 생략해야 합니다.

[delete-function](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/delete-function.html) 명령으로 함수를 삭제합니다.

```
aws lambda delete-function --function-name bash-runtime
```