

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 針對 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. 壓縮層內容：

------
#### [ 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. 壓縮層內容：

------
#### [ 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. 選擇**建立**。

------

## 在函式中使用來自層的 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"
```

如果您使用 AWS CLI 第 2 版，則需要 **cli-binary-format** 選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

------
#### [ 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 repository 中的 [layer-ruby](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-ruby) 範例應用程式。此應用程式包含一個內含 [tzinfo](https://rubygems.org/gems/tzinfo) 程式庫的層。建立層之後，您可以部署並調用相應的函式，驗證層是否如預期那樣運作。