AWS Lambda Layers 函數層管理

AWS Lambda Layers Function Layer Management

Lambda Layers 概述

AWS Lambda Layers 是一種可以包含程式庫、自訂執行環境、設定檔或其他相依性的分發機制。透過 Layers,您可以將共用的程式碼和資料與函數程式碼分開管理,使函數部署套件更加精簡,同時促進程式碼重用。

Layers 的核心優勢

  • 程式碼重用:多個函數可共享相同的程式庫和相依性
  • 精簡部署套件:減少函數程式碼的大小
  • 獨立版本控制:相依性可獨立於函數進行更新
  • 分離關注點:核心業務邏輯與相依性分離管理
  • 跨帳戶共享:可與其他 AWS 帳戶或公開分享 Layer

Layers 的限制

項目限制
每個函數最多附加的 Layers5 個
解壓縮後總大小(含所有 Layers)250 MB
Layer 版本數量無限制
Layer 壓縮套件大小50 MB(直接上傳)/ 250 MB(透過 S3)

使用場景

Lambda Layers 適用於以下常見場景:

1. 共享程式庫

將常用的程式庫打包成 Layer,供多個函數使用:

  • Python:numpy、pandas、requests 等
  • Node.js:axios、lodash、moment 等
  • Java:常用的 JAR 檔案

2. 自訂執行環境

建立包含特定版本或修補程式的執行環境:

1
2
# 例如:包含特定版本的 Python 套件
python/lib/python3.11/site-packages/

3. 共享設定檔

將設定檔、憑證或其他靜態資源集中管理:

1
2
3
4
5
# 設定檔範例
config/
  ├── database.json
  ├── api-keys.json
  └── feature-flags.json

4. 企業內部共享

在組織內部共享通用工具函數、驗證邏輯或加密模組。

建立 Layer

步驟一:準備 Layer 內容

建立符合 Lambda 執行環境要求的目錄結構:

1
2
3
4
5
6
7
8
9
# 建立工作目錄
mkdir -p my-layer/python/lib/python3.11/site-packages

# 安裝相依性到指定目錄
pip install requests -t my-layer/python/lib/python3.11/site-packages/

# 壓縮 Layer 內容
cd my-layer
zip -r ../my-layer.zip .

步驟二:使用 AWS CLI 建立 Layer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 建立 Lambda Layer
aws lambda publish-layer-version \
    --layer-name my-python-layer \
    --description "Python requests library layer" \
    --zip-file fileb://my-layer.zip \
    --compatible-runtimes python3.11 python3.12 \
    --compatible-architectures x86_64 arm64

# 輸出範例
{
    "LayerVersionArn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-python-layer:1",
    "LayerArn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-python-layer",
    "Version": 1,
    "Description": "Python requests library layer",
    "CompatibleRuntimes": ["python3.11", "python3.12"],
    "CompatibleArchitectures": ["x86_64", "arm64"]
}

透過 S3 上傳大型 Layer

1
2
3
4
5
6
7
8
9
# 上傳 Layer 套件到 S3
aws s3 cp my-large-layer.zip s3://my-bucket/layers/my-large-layer.zip

# 使用 S3 URI 建立 Layer
aws lambda publish-layer-version \
    --layer-name my-large-layer \
    --description "Large dependency layer" \
    --content S3Bucket=my-bucket,S3Key=layers/my-large-layer.zip \
    --compatible-runtimes python3.11

發布 Layer 版本

每次發布 Layer 都會建立新版本,版本號碼自動遞增且不可變更:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 更新 Layer 內容後發布新版本
aws lambda publish-layer-version \
    --layer-name my-python-layer \
    --description "Updated version with bug fixes" \
    --zip-file fileb://my-layer-v2.zip \
    --compatible-runtimes python3.11 python3.12

# 查詢 Layer 所有版本
aws lambda list-layer-versions \
    --layer-name my-python-layer

# 輸出範例
{
    "LayerVersions": [
        {
            "LayerVersionArn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-python-layer:2",
            "Version": 2,
            "Description": "Updated version with bug fixes"
        },
        {
            "LayerVersionArn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-python-layer:1",
            "Version": 1,
            "Description": "Python requests library layer"
        }
    ]
}

附加 Layer 到函數

建立函數時附加 Layer

1
2
3
4
5
6
7
8
# 建立新函數並附加 Layer
aws lambda create-function \
    --function-name my-function \
    --runtime python3.11 \
    --role arn:aws:iam::123456789012:role/lambda-execution-role \
    --handler index.handler \
    --zip-file fileb://function.zip \
    --layers arn:aws:lambda:ap-northeast-1:123456789012:layer:my-python-layer:2

更新現有函數的 Layers

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 更新函數的 Layer 配置
aws lambda update-function-configuration \
    --function-name my-function \
    --layers \
        arn:aws:lambda:ap-northeast-1:123456789012:layer:my-python-layer:2 \
        arn:aws:lambda:ap-northeast-1:123456789012:layer:my-utils-layer:1

# 移除所有 Layers
aws lambda update-function-configuration \
    --function-name my-function \
    --layers []

查詢函數的 Layer 配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 取得函數配置
aws lambda get-function-configuration \
    --function-name my-function \
    --query 'Layers'

# 輸出範例
[
    {
        "Arn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-python-layer:2",
        "CodeSize": 1234567
    }
]

Layer 路徑結構

Lambda 會將 Layer 內容解壓縮到 /opt 目錄下。不同執行環境有不同的路徑要求:

Python

1
2
3
python/lib/python3.11/site-packages/
# 解壓縮後:/opt/python/lib/python3.11/site-packages/
# Lambda 自動加入 PYTHONPATH

Node.js

1
2
3
4
nodejs/node_modules/
# 或
nodejs/node18/node_modules/
# 解壓縮後:/opt/nodejs/node_modules/

Java

1
2
3
java/lib/
# 解壓縮後:/opt/java/lib/
# JAR 檔案自動加入 CLASSPATH

Ruby

1
2
3
ruby/gems/3.2.0/
ruby/lib/
# 解壓縮後:/opt/ruby/gems/3.2.0/

自訂路徑

1
2
3
4
5
# 任何自訂內容放置於根目錄
bin/
lib/
config/
# 解壓縮後:/opt/bin/、/opt/lib/、/opt/config/

在函數中存取 Layer 內容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import json

# 存取 Layer 中的設定檔
def lambda_handler(event, context):
    # Layer 內容位於 /opt 目錄
    with open('/opt/config/settings.json', 'r') as f:
        settings = json.load(f)

    return {
        'statusCode': 200,
        'body': json.dumps(settings)
    }

跨帳戶共享 Layer

授權其他帳戶存取 Layer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 授權特定帳戶存取 Layer
aws lambda add-layer-version-permission \
    --layer-name my-python-layer \
    --version-number 1 \
    --statement-id account-123456789012 \
    --action lambda:GetLayerVersion \
    --principal 123456789012

# 授權整個組織存取
aws lambda add-layer-version-permission \
    --layer-name my-python-layer \
    --version-number 1 \
    --statement-id org-access \
    --action lambda:GetLayerVersion \
    --principal "*" \
    --organization-id o-1234567890

公開分享 Layer

1
2
3
4
5
6
7
# 將 Layer 設為公開(任何 AWS 帳戶都可使用)
aws lambda add-layer-version-permission \
    --layer-name my-public-layer \
    --version-number 1 \
    --statement-id public-access \
    --action lambda:GetLayerVersion \
    --principal "*"

使用其他帳戶的 Layer

1
2
3
4
# 使用跨帳戶 Layer
aws lambda update-function-configuration \
    --function-name my-function \
    --layers arn:aws:lambda:ap-northeast-1:987654321098:layer:shared-layer:3

查詢與移除權限

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 查詢 Layer 權限政策
aws lambda get-layer-version-policy \
    --layer-name my-python-layer \
    --version-number 1

# 移除特定權限
aws lambda remove-layer-version-permission \
    --layer-name my-python-layer \
    --version-number 1 \
    --statement-id account-123456789012

版本管理

列出所有 Layers

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 列出帳戶中所有 Layers
aws lambda list-layers

# 輸出範例
{
    "Layers": [
        {
            "LayerName": "my-python-layer",
            "LayerArn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-python-layer",
            "LatestMatchingVersion": {
                "LayerVersionArn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-python-layer:2",
                "Version": 2
            }
        }
    ]
}

刪除 Layer 版本

1
2
3
4
5
6
# 刪除特定版本
aws lambda delete-layer-version \
    --layer-name my-python-layer \
    --version-number 1

# 注意:無法刪除正在被函數使用的 Layer 版本

取得 Layer 版本詳細資訊

1
2
3
4
5
6
7
8
# 取得特定版本資訊
aws lambda get-layer-version \
    --layer-name my-python-layer \
    --version-number 2

# 透過 ARN 取得
aws lambda get-layer-version-by-arn \
    --arn arn:aws:lambda:ap-northeast-1:123456789012:layer:my-python-layer:2

最佳實踐

1. 規劃 Layer 結構

  • 將相關的相依性分組到同一個 Layer
  • 避免單一 Layer 過大,影響冷啟動時間
  • 使用有意義的命名慣例
1
2
3
# 建議的命名格式
{team}-{purpose}-{runtime}
# 範例:platform-common-libs-python311

2. 版本策略

  • 使用語意化版本控制追蹤變更
  • 在 Layer 描述中記錄變更內容
  • 保留穩定版本,及時清理過時版本
1
2
3
aws lambda publish-layer-version \
    --layer-name my-layer \
    --description "v2.1.0 - Added retry logic, fixed connection timeout"

3. 安全性考量

  • 定期更新 Layer 中的相依性以修補安全漏洞
  • 審慎管理跨帳戶存取權限
  • 避免在 Layer 中儲存敏感資訊

4. 效能優化

  • 只包含必要的相依性
  • 移除不需要的測試檔案和文件
  • 考慮使用 arm64 架構以降低成本
1
2
3
4
# 清理不必要的檔案
find . -type d -name "__pycache__" -exec rm -rf {} +
find . -type d -name "tests" -exec rm -rf {} +
find . -type f -name "*.pyc" -delete

5. CI/CD 整合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 在 CI/CD 流程中自動發布 Layer
#!/bin/bash
LAYER_NAME="my-python-layer"
VERSION=$(date +%Y%m%d%H%M%S)

# 建立 Layer 套件
pip install -r requirements.txt -t python/lib/python3.11/site-packages/
zip -r layer.zip python/

# 發布新版本
aws lambda publish-layer-version \
    --layer-name $LAYER_NAME \
    --description "Build: $VERSION" \
    --zip-file fileb://layer.zip \
    --compatible-runtimes python3.11

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy