自推出以来,亚马逊 Lambda 通过其无服务器(serverless)计算模型革新了应用程序的运行方式,使开发者能够运行代码而无需管理底层服务器,从而极大地简化了运维负担 。最初,Lambda 函数主要通过.zip
文件包的形式进行部署,这种方式在一定程度上限制了其在某些复杂场景下的应用,尤其是在处理大型依赖或特定运行时需求时。
然而,随着云计算技术的发展和容器化技术的普及,亚马逊 Lambda 在2020年引入了对容器镜像(Open Container Initiative - OCI 兼容打包)的部署支持 。这一重大更新使得开发者能够使用熟悉的 Docker 工具和工作流来打包和部署 Lambda 函数,极大地扩展了 Lambda 的应用范围和灵活性。通过这种支持,已容器化的 Web 应用程序能够无缝迁移到无服务器环境,从而利用 Lambda 固有的优势,如自动扩缩、内置高可用性以及按价值付费的计费模式,而无需投入额外的工程精力来适应新的工具或开发工作流 。
在开始之前,先注册个亚马逊云科技的账号。

亚马逊 Lambda 对容器镜像的支持不仅仅是其功能集的一个新添特性,它更代表了 亚马逊在云计算服务领域的一种战略性融合。这种融合旨在弥合无服务器和容器化部署之间长期存在的鸿沟,从而使 Lambda 能够接触到更广泛的开发者群体,特别是那些已经投入到容器工作流和工具中的开发者 。这种演进承认了虽然无服务器提供了显著的运营优势,但容器提供了许多开发者偏好或特定工作负载所需的熟悉度和控制力。这种融合也预示着云计算的未来可能不再是严格地在无服务器和容器之间做出选择,而是如何充分利用两者的优势,实现混合架构和更平滑的过渡路径。
此外,对容器镜像的支持直接解决了容器开发者在考虑采用 Lambda 时所面临的一个关键心理和实际障碍。通过允许他们继续使用熟悉的 Docker 工具和工作流,亚马逊云显著降低了开发者在学习新范式时的认知负担和所需的再培训成本 。这意味着开发者可以利用他们现有的 Dockerfile、构建过程甚至本地测试环境,只需进行少量 Lambda 特定的调整,从而使向无服务器的过渡过程变得不那么令人生畏,更具吸引力。这种策略加速了无服务器在大量开发者群体中的采用,这些开发者可能因为感知到的复杂性或需要放弃现有容器投资而犹豫不决。它促进了一个更具包容性的生态系统,其中不同的开发偏好可以在无服务器范式中共存。

理解亚马逊 Lambda 的核心编程模型
亚马逊 Lambda 的核心在于其独特的编程模型,它定义了应用程序代码与 Lambda 服务之间的交互方式。理解这一模型对于容器开发者至关重要,因为它与传统容器应用(通常是长时间运行的进程或 Web 服务器)的交互模式有所不同。
"Lambda魔法":应用与服务间的简单契约
亚马逊 Lambda 的编程模型可以被理解为应用程序代码与 Lambda 服务之间的一个明确且简单的契约 。这个契约的核心在于应用程序如何与 Lambda 服务进行交互,以接收请求并发送响应 。实现这一契约的关键机制是 Lambda 运行时 API(Runtime API)。该 API 提供了一种标准化的方式,允许应用程序获取事件数据并向 Lambda 服务报告执行结果 。开发者可以将容器实例视为一个长时间运行的进程,它会重复检查是否有事件需要处理,然后执行相应的工作,并将结果告知 Lambda 服务 。

这个"简单契约"不仅仅是一个操作细节,它更是一个基本的设计原则,实现了应用程序与底层基础设施之间的显著解耦。通过标准化输入/输出机制(事件),Lambda 抽象了底层基础设施甚至特定的运行时环境。这种抽象对于应用程序的可移植性至关重要。例如,原始文章中通过调整入口点在 Lambda 之外运行 businesscode.sh
脚本的示例,证明了核心业务逻辑在很大程度上独立于 Lambda 特定的执行环境,只要满足契约(事件处理)即可 。这意味着开发者可以专注于业务逻辑的实现,而无需深入纠缠于无服务器平台的复杂性。这种解耦有助于将应用程序更容易地迁移到 Lambda(特别是容器化的应用程序,因为核心逻辑保持不变),并且如果业务需求发生变化,也可能更容易地从 Lambda 迁移出来。它促进了一种模块化的架构风格,其中计算环境是可替换的组件,而不是紧密耦合的依赖项。
事件驱动的本质与执行环境
亚马逊 Lambda 从根本上是一个事件驱动系统。这意味着所有计算操作,包括容器实例的启动和代码的执行,都是由事件触发的 。Lambda 支持来自数百种不同 亚马逊服务的事件源,例如来自 Amazon SQS 队列的消息、亚马逊 API Gateway 或亚马逊 Elastic Load Balancing 的 HTTP 调用等 。
在 Lambda 的执行模型中,一个容器实例在任何给定时间最多处理一个事件,但在其生命周期内可以顺序处理多个事件 。当事件到来时,Lambda 的编排器会将其分配给一个已初始化且空闲的容器实例;如果没有可用的空闲容器,Lambda 会启动一个新的容器实例来处理该事件 。为了优化性能和减少冷启动,Lambda 可能会选择在单次执行后保留该容器,以供未来事件使用 。如果并发事件同时涌入,Lambda 会并行启动多个容器实例,直至达到配置的函数或账户并发和突发限制 。
这种事件驱动的扩缩模型代表了与传统容器编排的重大范式转变。Lambda 不是预置和管理一个始终"在线"并可能空闲的容器集群,而是根据每个事件动态扩缩计算实例(容器)。这导致了高效的"按价值付费"计费模式 ,即只在代码执行时付费,从而最大限度地减少资源浪费。对于容器开发者来说,这意味着从管理集群容量转变为纯粹关注应用程序逻辑和事件处理,将复杂的扩缩逻辑卸载给亚马逊。容器重用是平衡"按事件付费"与性能的关键优化,有助于缓解冷启动 。这种模型非常适合尖峰、不可预测的工作负载,与始终在线的容器集群相比,它提供了卓越的成本效益和操作简便性。它促使开发者思考无状态性和事件处理,这对于高度可扩缩和弹性分布式系统至关重要。
容器化Lambda 解决了什么问题?
容器化 Lambda 的引入,旨在克服传统 Lambda 部署的固有局限性,从而为开发者提供更大的灵活性和能力,使其能够处理更广泛的应用程序类型。
突破部署包大小限制(250MB vs. 10GB)
传统亚马逊 Lambda 函数通过 ZIP 文件归档部署时,其未解压的部署包大小上限为 250MB 。这一限制对于需要包含大型机器学习模型、复杂依赖库或大量第三方库的应用程序而言,是一个显著的瓶颈。例如,大型机器学习模型通常会超过数百兆字节,复杂应用程序可能具有多个依赖项,而某些第三方库可能无法适应包大小限制 。

相比之下,Lambda 容器镜像支持高达 10GB 的部署大小 。这一巨大的提升使得 Lambda 能够轻松承载大型 ML 模型、具有多层复杂依赖的应用程序,以及需要大量自定义软件和二进制文件的场景。例如,一个用于电子邮件欺诈检测的 10GB 机器学习模型,通过容器化部署在 Lambda 上得以实现,这在标准 ZIP 部署下是无法想象的 。这种能力直接解锁了之前因打包限制而无法在 Lambda 上高效运行的用例。
运行时与依赖管理的灵活性
传统 Lambda 对支持的编程运行时(如 Node.js、Python、Java、Go)有特定限制,这给需要使用非支持运行时(如 Rust、Elixir 等)或需要手动捆绑复杂依赖的应用带来了挑战,增加了部署的复杂性 。此外,如果应用程序需要 Lambda 不原生支持的系统库或二进制文件,也会遇到困难。
Lambda 容器化部署彻底解决了这些问题。它允许开发者"自带运行时"(Bring Your Own Runtime),将任何编程语言的运行时以及所有必要的依赖项直接打包到容器镜像内部 。这消除了手动捆绑的复杂性,并使得应用程序能够包含 Lambda 原生环境不提供的特定系统级工具或库。这种对任意运行时的支持打破了 Lambda 在语言和库选择上的束缚,使得更多现有应用可以"原样"迁移。
操作系统级别的定制化能力
亚马逊 Lambda 的传统执行环境不允许对底层操作系统进行修改,这影响了那些需要特定软件、库、系统工具、自定义安全配置或依赖 OS 特定处理工具的应用程序 。
通过容器化,开发者可以在其容器镜像中包含所需的操作系统级别定制化内容,例如安装特定的 Linux 软件包、配置环境变量、甚至运行自定义的启动脚本,从而满足应用程序的特殊环境需求。
优化冷启动时间
亚马逊 Lambda 函数在长时间不活动后首次被调用时,会经历"冷启动"现象,这会导致额外的延迟,从而增加对延迟敏感型应用程序的响应时间,并在具有大量依赖项的函数中造成性能瓶颈 。
通过优化容器镜像,开发者可以显著减少冷启动时间,从而实现更快的初始化和改进的性能 。例如,使用 Docker 的多阶段构建可以减小镜像大小,从而加快 Lambda 容器函数的激活时间 。亚马逊为此提供了优化的基础镜像,这些镜像预配置了 Lambda 事件处理所需的运行时环境和基本系统依赖,进一步简化了设置过程并有助于减少冷启动时间 。
亚马逊云科技账号注册
在使用亚马逊云科技服务之前,先得有一个亚马逊云科技的账号。

1、打开官网并创建账户: 打开亚马逊云科技官网,点击右上角 "创建用户" 按钮创建新账户。

2、验证邮箱地址: 输入要创建的邮箱地址,点击 "验证邮箱地址",在邮箱中找到验证码并输入。
3、设置密码: 验证通过后,输入要创建用户的密码。



4、输入个人信息: 填写相应的个人信息。

5、提供账号信息: 一般使用 visa 卡。

6、身份验证: 确认输入的信息,选择短信验证,地区选择中国,进行短信验证。

7、选择支持计划: 根据自身情况选择,个人开发选择 "基本支持 - 免费",企业可选择 "开发人员支持" 或 "商用级支持"。

8、完成注册并登录: 点击 "完成注册",等待亚马逊云科技验证,验证通过后转到登录页面,输入创建好的账户,进入管理控制台即可使用相关服务。
应用与服务间的"简单契约"
为了直观展示,我们可以参考一个低层级的 Bash 脚本示例。以下 Dockerfile
定义了容器环境,并指定了入口点:
bash
FROM public.ecr.aws/amazonlinux/amazonlinux:2023
RUN yum install -y jq tar gzip git unzip
RUN curl -Ls "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
&& unzip awscliv2.zip \
&&./aws/install
ADD startup.sh /startup.sh
ADD businesscode.sh /businesscode.sh
ENTRYPOINT /startup.sh
此 Dockerfile
基于 Amazon Linux 2023 镜像,安装了必要的工具,并将 startup.sh
和 businesscode.sh
脚本添加到镜像中。startup.sh
作为容器的入口点,负责实现与 Lambda 运行时 API 的交互逻辑。
运行时 API 与环境约束
Lambda 容器环境虽灵活,但仍有特定约束,开发者需了解这些以确保应用正确运行和优化:
- 只读文件系统: 容器以只读根文件系统运行,
/tmp
目录是唯一可写路径,提供 512MB 至 10,240MB 的临时存储这强制应用设计为无状态,任何持久化数据需存储在外部服务(如 Amazon S3, DynamoDB)。 - 资源配置: 容器的计算能力通过内存参数配置,CPU 容量按比例分配。
- 特权限制: 不支持运行特权容器,也无法暴露 GPU。
- 执行生命周期: 容器实例的执行生命周期是人为限制的,不属于 Lambda 的"合同"一部分。开发者不应假定容器会长时间存活。
- 操作系统与架构: 仅支持基于 Linux 的容器镜像,且镜像必须只针对单一架构(ARM 或 x86)。
以下 startup.sh
脚本是 Lambda 容器的核心,它实现了与 Lambda 运行时 API 的交互循环:
bash
#!/bin/sh
set -euo pipefail
###############################################################
# The container initializes before processing the invocations #
###############################################################
echo Installing the latest version of Hugo...
cd /tmp
export LATESTHUGOBINARYURL=$(curl -s https://api.github.com/repos/gohugoio/hugo/releases/latest | jq -r '.assets.browser_download_url' | grep Linux-64bit.tar.gz | grep extended)
export LATESTHUGOBINARYARTIFACT=${LATESTHUGOBINARYURL##*/}
curl -LO $LATESTHUGOBINARYURL
tar -zxvf $LATESTHUGOBINARYARTIFACT
./hugo version
###############################################
# Processing the invocations in the container #
###############################################
while true
do
# Create a temporary file
HEADERS="$(mktemp)"
# Get an event. The HTTP request will block until one is received
EVENT_DATA=$(curl -sS -LD "$HEADERS" -X GET "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 my arbitrary program #
############################
/businesscode.sh
############################
# Send the response
curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" -d '{"statusCode": 200}'
done
startup.sh
脚本首先执行一次性初始化任务(如下载 Hugo 二进制文件到 /tmp
目录),这发生在容器冷启动时 [4]。随后,它进入一个无限循环,通过 curl
命令不断轮询本地 AWS_LAMBDA_RUNTIME_API
端点以获取新事件 [4]。一旦接收到事件,它会执行包含实际业务逻辑的 businesscode.sh
脚本,并在处理完成后通过 HTTP POST 请求通知 Lambda 服务。
businesscode.sh
示例:
bash
#!/bin/sh
set -euo pipefail
rm -rf hugo-sample-site
git clone https://github.com/${AWS_LAMBDA_FOR_THE_CONTAINERS_DEVELOPER_BLOG_GITHUB_USERNAME}/aws-lambda-for-the-containers-developer-blog
cd aws-lambda-for-the-containers-developer-blog/hugo_web_site
/tmp/hugo
aws s3 cp./public/ s3://${AWS_LAMBDA_FOR_THE_CONTAINERS_DEVELOPER_BLOG_BUCKET}/ --recursive
这个示例清晰地展示了容器的初始化逻辑与事件处理逻辑的分离。
抽象层:运行时接口客户端 (RIC) 与 Lambda Web Adapter
虽然上述 Bash 脚本展示了底层机制,但大多数开发者会利用亚马逊云提供的抽象层来简化开发:
- 运行时接口客户端 (RIC): 亚马逊云提供的开源 RIC 实现了与 Lambda 运行时 API 的底层 HTTP 交互,将事件信息作为对象传递给应用程序函数,从而抽象了复杂的通信细节开发者可以选择使用独立的 RIC、亚马逊云 Lambda 托管的基础镜像(已预装 RIC),或将业务逻辑打包为 ZIP 文件,由亚马逊云完全管理运行时环境。
- Lambda Web Adapter: 这是一个重要的抽象层,它允许传统的 Web 应用程序在 Lambda 上运行,充当 Lambda 编程模型与 Web 应用框架之间的接口,无需大幅修改 Web 应用代码即可部署。
构建与部署:无缝集成 CI/CD
构建 Lambda 兼容的容器镜像有多种方式:
- 亚马逊云 Lambda 基础镜像: 预加载了特定语言运行时、RIC 和运行时接口模拟器 (RIE),推荐使用。
- 亚马逊云仅 OS 基础镜像: 包含 Amazon Linux 和 RIE,适用于编译型语言或自定义运行时,需手动包含 RIC。
- 非亚马逊云基础镜像: 可使用来自其他容器注册表(如 Alpine Linux 或 Debian)的镜像,但必须手动包含 RIC
亚马逊 Lambda部署方式对比
特性 | .zip 文件包部署 | 容器镜像部署 |
---|---|---|
部署包大小 | 解压后最大250MB | 最大10GB |
运行时支持 | 仅限于亚马逊提供的官方运行时(Node.js, Python, Java等) | 支持任何运行时(自带运行时),包括非官方支持的语言和版本 |
依赖管理 | 需手动捆绑依赖,可能受包大小限制 | 依赖项可直接包含在容器镜像中,简化管理 |
OS级别定制 | 不允许对底层操作系统进行修改 | 允许对操作系统进行定制,包含特定系统库或二进制文件 |
CI/CD集成 | 可能需要定制化流程 | 与现有基于Docker的CI/CD管道无缝集成(如亚马逊 CodeBuild, GitHub Actions) |
适用场景 | 轻量级、标准运行时、简单微服务 | 大型机器学习模型、复杂应用、自定义运行时、传统Web应用迁移 |
无论何种方式,镜像必须满足以下核心要求:实现 Lambda 运行时 API、支持只读文件系统(/tmp
可写)、默认 Lambda 用户可读所有文件、基于 Linux 且为单架构。
将现有容器化应用迁移至 Lambda 的实践步骤通常包括:
- 本地运行测试: 克隆应用仓库,审查 Dockerfile,构建并本地测试 Docker 镜像。
perl
docker build -t my-containerized-app.
docker run -p 8080:8080 my-containerized-app
- 移植到 Lambda 运行: 定义 Lambda 函数处理器,修改容器镜像以适应 Lambda 运行时 API,并使用运行时接口模拟器 (RIE) 在本地测试容器化 Lambda 函数。 3. 部署到亚马逊云: 将构建好的容器镜像推送到 Amazon Elastic Container Registry (ECR),然后通过亚马逊云管理控制台、CLI 或基础设施即代码 (IaC) 工具(如亚马逊云 SAM 或 CloudFormation)创建或更新 Lambda 函数。
双管道 CI/CD 策略
Lambda 容器与基于 Docker 的 CI/CD 管道无缝集成 [6]。一个典型的自动化部署架构可能包含两个独立的 CI/CD 管道
容器镜像部署管道: 负责从源代码仓库拉取代码,使用 Docker 构建容器镜像并分配标签,然后将镜像推送到 Amazon ECR。
Lambda 函数部署管道: 在容器镜像部署管道完成后,通过 Amazon EventBridge 事件触发,负责使用亚马逊云 SAM 构建基于新容器镜像的 Lambda 应用程序,并将其部署或更新到亚马逊云 Lambda。
这种分离的管道设计提高了效率和灵活性,使得镜像的构建和函数的部署可以独立进行
实际应用场景:赋能复杂工作负载
容器化 Lambda 极大地拓宽了 Lambda 的应用边界:
-
大型机器学习模型部署: 10GB 的部署包大小上限,使其成为部署大型 ML 模型和复杂数据科学工作负载的理想选择,这在传统 ZIP 部署下是无法想象的。
-
自定义运行时与复杂库应用: 支持"自带运行时",轻松部署需要 Rust、Elixir 等非原生支持运行时,或需要特定系统库(如图像处理工具、FFmpeg)的应用程序。
-
传统 Web 应用容器化迁移: 为现有容器化 Web 应用程序移植到无服务器环境提供了直接途径。通过亚马逊云 API Gateway 作为代理,传统 Web 应用可以利用 Lambda 的自动扩缩优势,而无需进行大规模重构。
以上就是本文的全部内容啦。最后,友情提示一下,如果决定不再使用服务的话,记得要在控制台关闭服务,以防超过免费额度产生扣费~