

# Ruby Lambda 함수를 위한 계층 작업
<a name="ruby-layers"></a>

[Lambda 계층](chapter-layers.md)을 사용하여 여러 함수에서 재사용하려는 코드와 종속성을 패키징합니다. 계층에는 일반적으로 라이브러리 종속 항목, [사용자 지정 런타임](runtimes-custom.md) 또는 구성 파일이 포함됩니다. 계층을 생성하려면 세 가지 일반적인 단계를 거칩니다.

1. 계층 콘텐츠를 패키징합니다. 즉, 함수에 사용하려는 종속성이 포함된 .zip 파일 아카이브를 생성합니다.

1. Lambda에서 계층을 생성합니다.

1. 계층을 함수에 추가합니다.

**Topics**
+ [

## 계층 콘텐츠 패키징
](#ruby-layers-package)
+ [

## Lambda에서 계층 생성
](#publishing-layer)
+ [

## 함수의 계층에서 gem 사용
](#ruby-layers-bundler-limitations)
+ [

## 함수에 계층 추가
](#ruby-layer-adding)
+ [

## 샘플 애플리케이션
](#ruby-layer-sample-app)

## 계층 콘텐츠 패키징
<a name="ruby-layers-package"></a>

계층을 생성하려면 다음 요구 사항을 충족하는 .zip 파일 아카이브로 패키지를 번들링합니다.
+ Lambda 함수에 사용하려는 것과 동일한 Ruby 버전을 사용하여 계층을 생성합니다. 예를 들어 Ruby 3.4용 계층을 생성하는 경우 함수에 Ruby 3.4 런타임을 사용합니다.
+ 계층의 .zip 파일은 다음 디렉터리 구조 중 하나를 사용해야 합니다.
  + `ruby/gems/x.x.x`(여기서 *x.x.x*는 Ruby 버전, 예: `3.4.0`)
  + `ruby/lib`

  자세한 내용은 [각 Lambda 런타임에 대한 계층 경로](packaging-layers.md#packaging-layers-paths) 섹션을 참조하세요.
+ 계층의 패키지는 Linux와 호환되어야 합니다. Lambda 함수는 Amazon Linux에서 실행됩니다.

타사 Ruby gem 또는 자체 Ruby 모듈 및 클래스가 포함된 계층을 생성할 수 있습니다. 널리 사용되는 Ruby gem에는 Lambda Linux 환경에 대해 컴파일해야 하는 기본 확장(C 코드)이 포함되어 있습니다.

### 순수 Ruby gem
<a name="ruby-layers-pure-ruby-gems"></a>

순수 Ruby gem에는 Ruby 코드만 포함되어 있으며 컴파일이 필요하지 않습니다. 이러한 gem은 다양한 플랫폼에서 더 간단하게 패키징하고 작동할 수 있습니다.

**순수 Ruby gem을 사용하여 계층을 생성하려면**

1. `Gemfile`을 생성하여 계층에 포함할 순수 Ruby gem을 지정합니다.  
**Example Gemfile**  

   ```
   source 'https://rubygems.org'
   
   gem 'tzinfo'
   ```

1. 번들러를 사용하여 gem을 `vendor/bundle` 디렉터리에 설치합니다.

   ```
   bundle config set --local path vendor/bundle
   bundle install
   ```

1. 설치된 gem을 Lambda에 필요한 디렉터리 구조(`ruby/gems/3.4.0`)에 복사합니다.

   ```
   mkdir -p ruby/gems/3.4.0
   cp -r vendor/bundle/ruby/3.4.0*/* ruby/gems/3.4.0/
   ```

1. 계층 콘텐츠를 .zip 파일로 압축합니다.

------
#### [ Linux/macOS ]

   ```
   zip -r layer.zip ruby/
   ```

------
#### [ PowerShell ]

   ```
   Compress-Archive -Path .\ruby -DestinationPath .\layer.zip
   ```

------

   .zip 파일의 디렉터리 구조는 다음과 같아야 합니다.

   ```
   ruby/              
   └── gems/
       └── 3.4.0/
           ├── gems/
           │   ├── concurrent-ruby-1.3.5/
           │   └── tzinfo-2.0.6/
           ├── specifications/
           ├── cache/
           ├── build_info/
           └── (other bundler directories)
   ```
**참고**  
함수 코드에 각 gem을 개별적으로 불러와야 합니다. `bundler/setup` 또는 `Bundler.require`를 사용할 수 없습니다. 자세한 내용은 [함수의 계층에서 gem 사용](#ruby-layers-bundler-limitations) 섹션을 참조하세요.

### 네이티브 확장이 있는 gem
<a name="ruby-layers-native-extensions"></a>

널리 사용되는 Ruby gem에는 대상 플랫폼에 대해 컴파일해야 하는 기본 확장(C 코드)이 포함되어 있습니다. 기본 확장이 있는 인기 gem은 [nokogiri](https://rubygems.org/gems/nokogiri/), [pg](https://rubygems.org/gems/pg/), [mysql2](https://rubygems.org/gems/mysql2/), [sqlite3](https://rubygems.org/gems/sqlite3/), [ffi](https://rubygems.org/gems/ffi/) 등입니다. 이러한 gem은 Lambda 런타임과 호환되는 Linux 환경에 구축해야 합니다.

**기본 확장이 있는 gem을 사용하여 계층을 생성하려면**

1. `Gemfile`를 만듭니다.  
**Example Gemfile**  

   ```
   source 'https://rubygems.org'
   
   gem 'nokogiri'
   gem 'httparty'
   ```

1. Docker를 사용하여 Lambda와 호환되는 Linux 환경에서 gem을 빌드합니다. Dockerfile에서 [AWS 기본 이미지](ruby-image.md#ruby-image-base)를 지정합니다.  
**Example Ruby 3.4용 Dockerfile**  

   ```
   FROM public.ecr.aws/lambda/ruby:3.4
   
   # Copy Gemfile
   COPY Gemfile ./
   
   # Install system dependencies for native extensions
   RUN dnf update -y && \
       dnf install -y gcc gcc-c++ make
   
   # Configure bundler and install gems
   RUN bundle config set --local path vendor/bundle && \
       bundle install
   
   # Create the layer structure
   RUN mkdir -p ruby/gems/3.4.0 && \
       cp -r vendor/bundle/ruby/3.4.0*/* ruby/gems/3.4.0/
   
   # Create the layer zip file
   RUN zip -r layer.zip ruby/
   ```

1. 이미지를 빌드하고 계층을 추출합니다.

   ```
   docker build -t ruby-layer-builder .
   docker run --rm -v $(pwd):/output --entrypoint cp ruby-layer-builder layer.zip /output/
   ```

   그러면 올바른 Linux 환경에 gem이 빌드되고 `layer.zip` 파일이 로컬 디렉터리에 복사됩니다. .zip 파일의 디렉터리 구조는 다음과 같아야 합니다.

   ```
   ruby/
   └── gems/
       └── 3.4.0/
           ├── gems/
           │   ├── bigdecimal-3.2.2/
           │   ├── csv-3.3.5/
           │   ├── httparty-0.23.1/
           │   ├── mini_mime-1.1.5/
           │   ├── multi_xml-0.7.2/
           │   ├── nokogiri-1.18.8-x86_64-linux-gnu/
           │   └── racc-1.8.1/
           ├── build_info/
           ├── cache/
           ├── specifications/
           └── (other bundler directories)
   ```
**참고**  
함수 코드에 각 gem을 개별적으로 불러와야 합니다. `bundler/setup` 또는 `Bundler.require`를 사용할 수 없습니다. 자세한 내용은 [함수의 계층에서 gem 사용](#ruby-layers-bundler-limitations) 섹션을 참조하세요.

### 사용자 지정 Ruby 모듈
<a name="custom-ruby-modules"></a>

**자체 코드를 사용하여 계층을 생성하려면 다음을 수행하세요.**

1. 계층에 필요한 디렉터리 구조를 생성합니다.

   ```
   mkdir -p ruby/lib
   ```

1. `ruby/lib` 디렉터리에서 Ruby 모듈을 생성합니다. 다음 예시 모듈은 주문에 필수 정보가 포함되어 있는지 확인하여 주문을 검증합니다.  
**Example ruby/lib/order\$1validator.rb**  

   ```
   require 'json'
   
   module OrderValidator
     class ValidationError < StandardError; end
   
     def self.validate_order(order_data)
       # Validates an order and returns formatted data
       required_fields = %w[product_id quantity]
       
       # Check required fields
       missing_fields = required_fields.reject { |field| order_data.key?(field) }
       unless missing_fields.empty?
         raise ValidationError, "Missing required fields: #{missing_fields.join(', ')}"
       end
       
       # Validate quantity
       quantity = order_data['quantity']
       unless quantity.is_a?(Integer) && quantity > 0
         raise ValidationError, 'Quantity must be a positive integer'
       end
       
       # Format and return the validated data
       {
         'product_id' => order_data['product_id'].to_s,
         'quantity' => quantity,
         'shipping_priority' => order_data.fetch('priority', 'standard')
       }
     end
   
     def self.format_response(status_code, body)
       # Formats the API response
       {
         statusCode: status_code,
         body: JSON.generate(body)
       }
     end
   end
   ```

1. 계층 콘텐츠를 .zip 파일로 압축합니다.

------
#### [ Linux/macOS ]

   ```
   zip -r layer.zip ruby/
   ```

------
#### [ PowerShell ]

   ```
   Compress-Archive -Path .\ruby -DestinationPath .\layer.zip
   ```

------

   .zip 파일의 디렉터리 구조는 다음과 같아야 합니다.

   ```
   ruby/              
   └── lib/
       └── order_validator.rb
   ```

1. 함수에서 모듈을 불러와서 사용합니다. 함수 코드에 각 gem을 개별적으로 불러와야 합니다. `bundler/setup` 또는 `Bundler.require`를 사용할 수 없습니다. 자세한 내용은 [함수의 계층에서 gem 사용](#ruby-layers-bundler-limitations) 섹션을 참조하세요. 예시:

   ```
   require 'json'
   require 'order_validator'
   
   def lambda_handler(event:, context:)
     begin
       # Parse the order data from the event body
       order_data = JSON.parse(event['body'] || '{}')
       
       # Validate and format the order
       validated_order = OrderValidator.validate_order(order_data)
       
       OrderValidator.format_response(200, {
         message: 'Order validated successfully',
         order: validated_order
       })
     rescue OrderValidator::ValidationError => e
       OrderValidator.format_response(400, {
         error: e.message
       })
     rescue => e
       OrderValidator.format_response(500, {
         error: 'Internal server error'
       })
     end
   end
   ```

   다음 [테스트 이벤트](testing-functions.md#invoke-with-event)를 사용하여 함수를 간접적으로 호출할 수 있습니다.

   ```
   {
       "body": "{\"product_id\": \"ABC123\", \"quantity\": 2, \"priority\": \"express\"}"
   }
   ```

   예상 응답:

   ```
   {
     "statusCode": 200,
     "body": "{\"message\":\"Order validated successfully\",\"order\":{\"product_id\":\"ABC123\",\"quantity\":2,\"shipping_priority\":\"express\"}}"
   }
   ```

## Lambda에서 계층 생성
<a name="publishing-layer"></a>

AWS CLI 또는 Lambda 콘솔을 사용하여 계층을 게시할 수 있습니다.

------
#### [ AWS CLI ]

[publish-layer-version](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/publish-layer-version.html) AWS CLI 명령을 실행하여 Lambda 계층을 생성합니다.

```
aws lambda publish-layer-version --layer-name my-layer --zip-file fileb://layer.zip --compatible-runtimes ruby3.4
```

[호환되는 런타임](https://docs.aws.amazon.com/lambda/latest/api/API_PublishLayerVersion.html#lambda-PublishLayerVersion-request-CompatibleRuntimes) 파라미터는 선택 사항입니다. 지정된 경우 Lambda는 이 파라미터를 사용하여 Lambda 콘솔에서 계층을 필터링합니다.

------
#### [ Console ]

**계층을 생성하려면(콘솔)**

1. Lambda 콘솔의 [계층 페이지](https://console.aws.amazon.com/lambda/home#/layers)를 엽니다.

1. **계층 생성**을 선택합니다.

1. **.zip 파일 업로드를** 선택한 다음 이전에 생성한 .zip 아카이브를 업로드합니다.

1. (선택 사항) **호환되는 런타임**에서 계층을 빌드하는 데 사용한 Ruby 버전에 해당하는 Ruby 런타임을 선택합니다.

1. **생성(Create)**을 선택합니다.

------

## 함수의 계층에서 gem 사용
<a name="ruby-layers-bundler-limitations"></a>

함수 코드에서 사용하려는 각 gem을 명시적으로 불러와야 합니다. `bundler/setup` 및 `Bundler.require`와 같은 번들러 명령은 지원되지 않습니다. Lambda 함수의 계층에서 gem을 올바르게 사용하는 방법은 다음과 같습니다.

```
# Correct: Use explicit requires for each gem
require 'nokogiri'
require 'httparty'

def lambda_handler(event:, context:)
  # Use the gems directly
  doc = Nokogiri::HTML(event['html'])
  response = HTTParty.get(event['url'])
  # ... rest of your function
end

# Incorrect: These Bundler commands will not work
# require 'bundler/setup'
# Bundler.require
```

## 함수에 계층 추가
<a name="ruby-layer-adding"></a>

------
#### [ AWS CLI ]

함수에 계층을 연결하려면 [update-function-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-configuration.html) AWS CLI 명령을 실행합니다. `--layers` 파라미터의 경우 계층 ARN을 사용합니다. ARN은 버전을 지정해야 합니다(예: `arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1`). 자세한 내용은 [계층 및 계층 버전](chapter-layers.md#lambda-layer-versions) 섹션을 참조하세요.

```
aws lambda update-function-configuration --function-name my-function --cli-binary-format raw-in-base64-out --layers "arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1"
```

**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에서 참조하세요*.

------
#### [ Console ]

**함수에 계층을 추가하려면 다음을 수행하세요.**

1. Lambda 콘솔의 [함수 페이지](https://console.aws.amazon.com/lambda/home#/functions)를 엽니다.

1. 함수를 선택합니다.

1. 아래로 스크롤하여 **계층** 섹션으로 이동하고 **계층 추가**를 선택하세요.

1. **계층 선택**에서 **사용자 지정 계층**을 선택하고 계층을 선택합니다.
**참고**  
계층을 생성할 때 [호환되는 런타임](https://docs.aws.amazon.com/lambda/latest/api/API_PublishLayerVersion.html#lambda-PublishLayerVersion-request-CompatibleRuntimes)을 추가하지 않은 경우 여기에 계층이 나열되지 않습니다. 대신 계층 ARN을 지정할 수 있습니다.

1. **추가**를 선택합니다.

------

## 샘플 애플리케이션
<a name="ruby-layer-sample-app"></a>

Lambda 계층을 사용하는 방법의 자세한 예는 AWS Lambda Developer Guide GitHub 리포지토리의 [layer-ruby](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-ruby) 샘플 애플리케이션을 참조하세요. 이 애플리케이션에는 [tzinfo](https://rubygems.org/gems/tzinfo) 라이브러리가 있는 계층이 포함되어 있습니다. 계층을 생성한 후 해당 함수를 배포하고 간접적으로 호출하여 계층이 예상대로 작동하는지 확인할 수 있습니다.