在容器镜像中使用 Lambda 层和扩展

发布时间: 更新时间: 总字数:3701 阅读时间:8m 作者: IP上海 分享 网址

在本篇文章中,我将介绍如何通过打包并部署为容器镜像的 Lambda 函数使用 AWS Lambda 层和扩展。

标签

  • Amazon EC2 Container Registry
  • Amazon Simple Storage Service (S3)
  • AWS Lambda
  • AWS Serverless Application Model
  • Containers
  • Serverless

正文

以前,Lambda 函数只能打包为 .zip 压缩包。这包括在 AWS 管理控制台中创建的函数。现在,您还可以将 Lambda 函数打包为容器镜像并进行部署。

您可以使用熟悉的容器工具,如 Docker CLIDockerfile 在本地构建、测试和标记镜像。使用容器镜像构建的 Lambda 函数最大可达 10 GB。你可以将镜像推送到亚马逊的 Elastic Container Registry (ECR) 存储库,这是一个受管理的 AWS 容器镜像注册服务。创建 Lambda 函数,将源代码指定为注册表中的 ECR 镜像 URL。

打包为容器镜像的 Lambda 函数不支持在函数配置中添加 Lambda 层。不过,有许多解决方案可以使用容器镜像的 Lambda 层功能。您需要负责在构建过程中将您偏好的运行时和依赖项打包为容器镜像的一部分。

了解 Lambda 层和扩展如何作为 .zip 压缩包工作

如果使用 .zip 压缩包部署函数代码,则可以使用 Lambda 层作为库、自定义运行时和其他函数依赖项的分发机制。

在函数中包含一个或多个层时,在初始化过程中,每个层的内容都会按顺序提取到函数执行环境中的 /opt 目录中。然后,每个运行时都会根据语言的不同在 /opt 下的不同位置查找库。每个函数最多可包含 5 个图层,这些图层将计入 250 MB 的未压缩部署包大小限制中。层会自动设置为私有,但可以与其他 AWS 账户共享,也可以公开共享。

Lambda 扩展是增强 Lambda 功能的一种方式,并作为 Lambda 层部署。您可以使用 Lambda 扩展将功能与您偏好的监控、可观察性、安全性和治理工具集成在一起。您可以从 AWS、AWS Lambda Ready 合作伙伴和 AWS 合作伙伴提供的大量工具中进行选择,也可以创建自己的 Lambda 扩展。有关详细信息,请参阅 Introducing AWS Lambda Extensions.

扩展可以内部和外部两种模式运行。外部扩展在执行环境中作为独立进程运行。它们可以在运行时进程之前启动,也可以在函数调用完全处理完毕后继续运行。内部扩展作为运行时进程的一部分运行,在进程内与你的代码一起运行。

Lambda 会搜索 /opt/extensions 目录,并开始初始化找到的任何扩展。扩展必须是可执行的二进制文件或脚本。由于函数代码目录是只读的,因此扩展不能修改函数代码。

理解 Lambda 层和扩展只是在函数初始化期间复制到执行环境中特定文件路径的文件,会有所帮助。这些文件在执行环境中是只读的。

使用 Lambda 理解容器镜像

容器镜像是根据 Dockerfile 构建的打包模板。镜像是根据 Dockerfile 中的命令组装或构建的,可以从父镜像或基础镜像开始,也可以从头开始。然后,每条命令都会在镜像中创建一个新层,并按顺序堆叠在前一层之上。容器镜像一旦从打包的模板中构建出来,就不可更改且只读。

对于 Lambda 而言,容器镜像包括基本操作系统、运行时、任何 Lambda 扩展、应用程序代码及其依赖项。Lambda 提供了一组开源基本镜像,您可以使用它们来构建容器镜像。在函数初始化过程中,Lambda 会使用镜像来构建执行环境。Lambda 还会优化镜像,并将其缓存到靠近函数运行的位置,因此冷启动时间与 .zip 压缩包相同。您可以使用 AWS Serverless Application Model (AWS SAM) CLI 或本地容器工具(如 Docker CLI)在本地构建和测试容器镜像。

在容器镜像中使用 Lambda 图层

容器图层被添加到容器镜像中,这与 Lambda 图层被添加到 .zip 压缩包函数中的方式类似。

有多种方法可以使用容器镜像分层将 Lambda 层的功能添加到 Lambda 函数容器镜像中。

使用 Lambda 层的容器镜像版本

Lambda 图层发布者可以拥有与 Lambda 图层等价的容器镜像格式。为了保持与 Lambda 图层相同的文件路径,发布的容器镜像必须包含位于 /opt 目录中的等效文件。包含扩展的镜像必须包含 /opt/extensions 目录中的文件。

一个打包为 .zip 压缩包的 Lambda 函数示例包含两个层。一层包含共享库,另一层是来自 AWS 合作伙伴的 Lambda 扩展。

aws lambda create-function --region us-east-1 --function-name my-function \\
    --role arn:aws:iam::123456789012:role/lambda-role \\
    --layers \\
        "arn:aws:lambda:us-east-1:123456789012:layer:shared-lib-layer:1" \\
        "arn:aws:lambda:us-east-1:987654321987:extensions-layer:1" \\
    …

打包为容器镜像的函数的相应 Dockerfile 语法包括以下几行。这些行提取了 Lambda 层的容器镜像版本,并将其复制到函数镜像中。共享库镜像来自 ECR,扩展镜像来自 Docker Hub

FROM public.ecr.aws/myrepo/shared-lib-layer:1 AS shared-lib-layer
# Layer code
WORKDIR /opt
COPY --from=shared-lib-layer /opt/ .

FROM aws-partner/extensions-layer:1 as extensions-layer
# Extension  code
WORKDIR /opt/extensions
COPY --from=extensions-layer /opt/extensions/ .

将 Lambda 层的内容复制到容器镜像中

您可以使用现有的 Lambda 层,并在 docker build 过程中将层的内容复制到功能容器镜像的 /opt 目录中。

要在自动构建流程中使用此功能,请构建一个包含 AWS 命令行界面 的 Dockerfile,以便从 Amazon S3 复制层文件。

值得考虑的是这种方法的安全方面,因为它需要向 Dockerfile 发送凭据,以便从 S3 复制文件。请务必确保永远不要在最终容器镜像中存储 AWS 凭据。本示例使用多阶段 docker 构建流程,使用凭据获取一个层,然后继续 “从头开始”,删除上一层。这就从最终镜像中删除了凭据,而最终镜像可以用docker history来验证。确保使用并存储构建时特定的凭据,其权限范围仅限于需要访问的资源。

这种自动化方法的 Dockerfile 将两个层添加到一个镜像中,其中包括以下用于复制 Lambda 层内容的行。

FROM alpine:latest as layer-copy # Create a build stage to copy the files from S3 using credentials

ARG AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:-"us-east-1"}
ARG AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-""}
ARG AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-""}
ENV AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION}
ENV AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
ENV AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}

RUN apk add aws-cli curl unzip

RUN mkdir -p /opt

RUN curl $(aws lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:1234567890123:layer:shared-lib-layer:1 --query 'Content.Location' --output text) --output layer.zip
RUN unzip layer.zip -d /opt
RUN rm layer.zip

RUN curl $(aws lambda get-layer-version-by-arn --arn arn:aws:lambda:us-east-1:987654321987:extensions-layer:1 --query 'Content.Location' --output text) --output layer.zip
RUN unzip layer.zip -d /opt
RUN rm layer.zip

FROM scratch # Start second stage from blank image to squash all previous history, including credentials.
WORKDIR /opt
COPY --from=layer-copy /opt .

要在 Dockerfile 中运行 AWS CLI,请指定 AWS_ACCESS_KEYAWS_SECRET_ACCESS_KEY,并将所需的 AWS_DEFAULT_REGION 作为命令行参数。确保安全使用和存储最小访问凭证。

docker build . -t layer-image1:latest \\
--build-arg AWS_DEFAULT_REGION=us-east-1 \\
--build-arg AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE \\
--build-arg AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

确认认证信息未存储在图像中。

docker history layer-image1:latest

这会创建一个包含现有 Lambda 层和扩展文件的容器镜像。这可以推送到 ECR 并在函数中使用。

从 Lambda 层构建容器镜像

您可以将 Lambda 层文件内容作为容器镜像重新打包和发布。为不同的层创建单独的容器镜像,可以将它们添加到多个函数中,并以类似于 Lambda 层的方式共享它们。

您可以创建包含单个层文件的独立容器镜像,也可以将多个层的文件合并到单个镜像中。如果为层文件创建了单独的容器镜像,那么就可以将这些镜像添加到函数镜像中。

管理语言代码依赖关系有两种方法。你可以预先构建依赖关系并将文件复制到容器镜像中,或者在 docker build 过程中构建依赖关系。

在本示例中,迁移了一个现有 Python 应用程序。其中包括一个 Lambda 函数和扩展,从 .zip 压缩包迁移到独立的函数和扩展容器镜像。扩展将日志写入 S3。

你可以选择如何在存储库中存储镜像。您可以将两个镜像推送到带有不同镜像标签的同一个 ECR 存储库,也可以推送到不同的存储库。在本示例中,使用不同的 ECR 资源库。

要设置示例,请访问 GitHub repo 并按照 README.md 文件中的说明进行操作。

现有的示例扩展使用 makefile 通过 pip install 安装 boto3requirements.txt 文件。这将迁移到 docker build 进程中。你必须添加一个 Python 运行时才能运行 pip install 作为联编过程的一部分。你可以使用 python:3.8-alpine 作为最小的基础镜像。

为功能和扩展创建单独的 Dockerfile。扩展的 Dockerfile 包含以下几行。

FROM python:8-alpine AS installer
#Layer Code
COPY extensionssrc /opt/
COPY extensionssrc/requirements.txt /opt/
RUN pip install -r /opt/requirements.txt -t /opt/extensions/lib

FROM scratch AS base
WORKDIR /opt/extensions
COPY --from=installer /opt/extensions .

Build, tag、登录并将扩展容器镜像推送到现有的 ECR 资源库。

docker build -t log-extension-image:latest  .
docker tag log-extension-image:latest 1234567890dkr.ecr.us-east-amazonaws.com/log-extension-image:latest
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 1234567890dkr.ecr.us-east-amazonaws.com
docker push 1234567890dkr.ecr.us-east-amazonaws.com/log-extension-image:latest

函数 Dockerfile 包含以下几行,用于将先前创建的扩展镜像中的文件添加到函数镜像中。该函数不需要运行 pip install ,因为它不需要任何额外的依赖项。

FROM 1234567890dkr.ecr.us-east-amazonaws.com/log-extension-image:latest AS layer
FROM public.ecr.aws/lambda/python:8
# Layer code
WORKDIR /opt
COPY --from=layer /opt/ .
# Function code
WORKDIR /var/task
COPY app.py .
CMD ["app.lambda_handler"]

Build, tag 并将函数容器镜像推送到单独的现有 ECR 资源库。这将创建一个不可变的 Lambda 函数镜像。

docker build -t log-extension-function:latest  .
docker tag log-extension-function:latest 1234567890dkr.ecr.us-east-amazonaws.com/log-extension-function:latest
docker push 1234567890dkr.ecr.us-east-amazonaws.com/log-extension-function:latest

该函数需要一个唯一的 S3 桶来存储日志文件,该桶在 S3 控制台中创建。从 ECR 资源库镜像创建一个 Lambda 函数,并将桶名指定为 Lambda 环境变量。

aws lambda create-function --region us-east-1  --function-name log-extension-function \\
--package-type Image --code ImageUri=1234567890dkr.ecr.us-east-amazonaws.com/log-extension-function:latest \\
--role "arn:aws:iam:: 123456789012:role/lambda-role" \\
--environment  "Variables": {"S3_BUCKET_NAME": "s3-logs-extension-demo-logextensionsbucket-us-east-1"}

对于后续的扩展代码更改,您需要同时更新扩展和功能镜像。如果只有功能代码发生变化,则需要更新功能镜像。将功能镜像作为 :latest 镜像推送到 ECR。然后更新功能代码部署,以使用更新后的 :latest ECR 镜像。

aws lambda update-function-code --function-name log-extension-function --image-uri 1234567890dkr.ecr.us-east-amazonaws.com/log-extension-function:latest

在容器镜像中使用自定义运行时

使用 .zip 压缩包函数,可以使用 Lambda 层添加自定义运行时。有了容器镜像,就不再需要为自定义运行时复制 Lambda 层代码。

您可以从 AWS 提供的用于自定义运行时的基本镜像开始,构建自己的自定义运行时镜像。您可以在这些镜像中添加自己喜欢的运行时、依赖项和代码。要与 Lambda 通信,镜像必须实现 Lambda Runtime API。我们为所有受支持的运行时提供了 Lambda 运行时接口客户端,您也可以为其他运行时实现自己的客户端。

在容器镜像中运行扩展

在打包为容器镜像的函数中运行 Lambda 扩展的方式与 .zip 压缩包函数相同。您可以构建包含扩展文件的函数容器镜像,或添加扩展镜像层。Lambda 会在 /opt/extensions 目录中查找任何外部扩展,并开始初始化它们。扩展必须是可执行的二进制文件或脚本。

内部扩展使用特定于语言的环境变量或包装脚本修改 Lambda 运行时启动行为。对于特定于语言的环境变量,可以在函数配置中设置以下环境变量,以增强运行时命令行。

  • JAVA_TOOL_OPTIONS (Java Corretto 8 and 11)
  • NODE_OPTIONS (Node.js 10 and 12)
  • DOTNET_STARTUP_HOOKS (.NET Core 3.1)

一个 Lambda 环境变量示例 JAVA_TOOL_OPTIONS:

-javaagent:"/opt/ExampleAgent-jar"

封装脚本将运行时启动委托给脚本。脚本可以注入和更改参数、设置环境变量,或捕获指标、错误和其他诊断信息。以下运行时支持封装脚本: Node.js 10 和 12、Python 3.8、Ruby 2.7、Java 8 和 11 以及 .NET Core 3.1。

例如,您可以通过将 AWS_LAMBDA_EXEC_WRAPPER 环境变量的值设置为可执行二进制文件或脚本的文件系统路径来指定脚本:

/opt/wrapper_script

结论

除了 .zip 压缩包外,您现在还可以将 Lambda 函数打包为容器镜像并进行部署。打包为容器镜像的 Lambda 函数不像 .zip 压缩包那样直接支持在函数配置中添加 Lambda 层。

在这篇文章中,我将展示一些使用容器镜像(包括示例 Dockerfile)的 Lambda 层和扩展功能的解决方案。

我将展示如何将现有的 Lambda 函数和扩展从 .zip 压缩包迁移到独立的函数和扩展容器镜像。请按照 GitHub 存储库中的 README.md 文件中的说明进行操作。

有关更多无服务器学习资源,请访问 https://serverlessland.com.

参考

  1. https://aws.amazon.com/cn/blogs/compute/working-with-lambda-layers-and-extensions-in-container-images/

Translations

Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数