Python Lambda运行时:配置与依赖管理

说起 Lambda 的运行时配置,我记得刚开始做第一个自动化巡检函数时,纠结了好久该用哪个 Python 版本。其实 AWS 支持 Python 3.8、3.9、3.10、3.11 甚至 3.12,但好多项目还在用 3.8。我个人习惯是——如果没有历史包袱,直接上最新稳定版。为什么?因为 Lambda 的底层运行环境会定期更新,老版本迟早退役,到时候你得迁一次,不如一开始就用新的。

运行时版本选择

目前主流的 Lambda Python 运行时版本对比如下:

运行时标识Python 版本底层 OS建议场景
python3.93.9Amazon Linux 2多数新项目推荐
python3.103.10Amazon Linux 2需要 match 语句等新特性
python3.113.11Amazon Linux 2023性能最优,推荐长期项目
python3.123.12Amazon Linux 2023最新,但少数第三方库可能不兼容
我的小建议:如果你是第一次部署日志巡检 Lambda,优先选 python3.11。它兼顾了性能和生态兼容性。我在项目里从 3.8 迁到 3.11 后,冷启动快了大约 300ms。

依赖管理:三种主流方式

Lambda 不是一台完整的服务器,你不能直接 pip install 然后跑。你需要把依赖包和代码一起打包,或者用 Lambda Layer 共享。说白了,就是让你的 Python 代码在云端能找到那些第三方库。

方式一:直接打包进 ZIP

最原始的方式。把 requirements.txt 里列出的库用 pip 装到一个目录,然后和函数代码一起压缩。

步骤:

  1. 创建函数目录,比如 my-function/
  2. 编写 requirements.txt,例如:
    boto3==1.28.0
    requests==2.31.0
    pytz==2023.3
  3. 在本机运行:
    pip install -r requirements.txt -t my-function/
    cd my-function/
    zip -r ../function.zip .
  4. 上传 function.zip 到 Lambda
我曾经踩过的坑:打包时要注意,不要包含 __pycache__ 和 .pyc 文件,否则上传后可能因为缓存冲突导致函数失败。我习惯在 .gitignore 里加上 *.pyc,打包前用 find . -name '*.pyc' -delete 清理一遍。

方式二:Lambda Layer(推荐)

如果你有多个函数共享同一套依赖,用 Layer 最省事。Layer 本质上也是一个 ZIP 包,但需要按特定目录结构存放:

  • python/lib/python3.x/site-packages/ —— 放第三方库
  • python/lib/ —— 可选,放自定义模块

我一般这样创建:

mkdir -p layer/python/lib/python3.11/site-packages
pip install requests -t layer/python/lib/python3.11/site-packages
cd layer
zip -r layer.zip python

然后在 AWS 控制台或 CLI 中创建 Layer,再附加给函数。一次创建,所有函数都能用。更新依赖时只需要新 Layer,函数代码不用改。

最佳实践:每个 Layer 版本上限是 5 层,每层最大 250MB(解压后)。如果你的依赖超过 250MB,怎么办?别急,看第三种方式。

方式三:容器镜像 (ECR)

当你的依赖特别重,比如用了 Pandas、OpenCV、Pillow 等大型库,或者需要自定义 C 扩展库时,直接打包 ZIP 可能超限,Layer 也顶不住。这时 Lambda 支持用容器镜像部署。

你需要:

  1. 写一个 Dockerfile,继承官方的 Lambda Python 基础镜像:
    FROM public.ecr.aws/lambda/python:3.11
    COPY requirements.txt .
    RUN pip install -r requirements.txt
    COPY app.py .
    CMD ["app.lambda_handler"]
  2. 构建镜像并推送到 ECR:
    aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <account-id>.dkr.ecr.us-east-1.amazonaws.com
    docker build -t my-log-check .
    docker tag my-log-check:latest <repo-uri>:latest
    docker push <repo-uri>:latest
  3. 创建 Lambda 函数时,选择「容器镜像」并填写镜像 URI

注意,镜像最多 10GB。启动时间会比 ZIP 长一点,但胜在灵活。我个人在日志巡检中只用过一次镜像,因为那个函数需要调用 OCR 库,依赖实在太大。

依赖管理决策流程图

下面这张图梳理了三种方式的选择逻辑,你写自动化巡检脚本时可以直接套用:

Lambda 依赖管理决策流程 开始:评估依赖 依赖 < 250MB? 多函数 共享? 多函数 共享? 使用 Lambda Layer 打包进 ZIP 容器镜像 容器镜像 说明: • ZIP 部署包最适合依赖少、函数独立的场景,简单直接。 • Lambda Layer 推荐给多个函数共享依赖的场景,更新方便。 • 容器镜像适合大型依赖(>250MB)或需要自定义二进制库的极端情况。

环境变量与密钥管理

日志巡检要用到 CloudWatch 日志组、S3 存储桶、可能还有外部 。千万别在代码里写死。Lambda 提供了环境变量,直接在控制台设置即可。

我的习惯:敏感信息(比如 Webhook )用 AWS Secrets Manager 或 Systems Manager Parameter Store,Lambda 函数运行时通过 SDK 读取。不要在环境变量里存明文密码。

示例代码(读取 Parameter Store):

import boto3
ssm = boto3.client('ssm')
def get_config(key):
    resp = ssm.get_parameter(Name=key, WithDecryption=True)
    return resp['Parameter']['Value']
# 使用
slack_url = get_config('/log-monitor/slack-webhook')
要点总结:
  • 运行时版本选 python3.11 稳中求快
  • 依赖优先考虑 Layer,超过 250MB 用容器镜像
  • 打包时注意清理缓存文件,避免莫名其妙报错
  • 密钥走 Parameter Store,别硬编码

避坑指南

我最后再列几个实际中容易翻车的地方:

  • 本地环境与 Lambda 环境不一致:你本机用 macOS,pip 装的可能是 macosx_* 的 wheel,上传到 Amazon Linux 上就报错。一定要用 pip install --platform manylinux2014_x86_64 --only-binary=:all: 来限制平台。或者老老实实去 EC2 或 CodeBuild 上打包。
  • Layer 解压路径弄错:我曾经把第三方库放在了 python/lib/python3.9/site-packages/ 下面,但函数运行时版本是 3.11,死活找不到库。检查一下 Layer 的目录结构,版本号要对上。
  • 容器镜像冷启动慢:如果你用容器镜像做日志巡检,冷的请求可能多等 2~3 秒。可以用 Provisioned Concurrency 预先热好,但会多花钱。权衡一下。
  • ZIP 包超过 50MB?:Lambda 的控制台直接上传 ZIP 有限制 50MB,超过就要放 S3 然后通过 URL 上传。

嗯,以上就是关于 Lambda 运行时配置与依赖管理的主要干货。你写自动化巡检脚本时,把这部分的规格定好,后面其他章节的代码就能顺畅跑起来。到底用 ZIP、Layer 还是镜像,根据你的依赖规模和多函数复用程度决定就好。