使用容器镜像在 Lambda 中部署转换后的 TypeScript 代码
您可以将 TypeScript 代码作为 Node.js 容器镜像部署到 AWS Lambda 函数中。AWS 将为 Node.js 提供基本镜像,以帮助您构建容器镜像。这些基本映像会预加载一个语言运行时和在 Lambda 上运行映像所需的其他组件。AWS 为每个基本映像提供 Dockerfile,以帮助构建容器映像。
如果使用社群或私有企业基本镜像,则必须将 Node.js 运行时接口客户端 (RIC) 添加到该基本镜像,以使其与 Lambda 兼容。
Lambda 提供了可用于本地测试的运行时系统接口仿真器。Node.js 的 AWS 基本映像包含运行时系统接口仿真器。如果您使用备用基本映像,例如 Alpine Linux 或 Debian 映像,则可将仿真器构建到映像中
使用 Node.js 基本映像构建和打包 TypeScript 函数代码
要完成本节中的步骤,您必须满足以下条件:
-
Node.js 20.x
通过AWS基本映像为 Lambda 创建映像
-
在本地计算机上,为新函数创建项目目录。
-
使用
npm
或您选择的软件包管理器创建一个新的 Node.js 项目。npm init
-
添加 @types/aws-lambda
和 esbuild 软件包作为开发依赖项。 @types/aws-lambda
程序包包含 Lambda 的类型定义。npm install -D @types/aws-lambda esbuild
-
将构建脚本
添加到 package.json
文件。"scripts": { "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js" }
-
创建名为
index.ts
的新文件。将以下示例代码添加到该新文件。这是适用于 Lambda 函数的代码。该函数将返回一条hello world
消息。注意
import
语句从 @types/aws-lambda中导入类型定义。它不导入 aws-lambda
NPM 程序包,这是一个无关的第三方工具。有关更多信息,请参阅 DefinitelyTyped GitHub 存储库中的 aws-lambda。 import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda'; export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => { console.log(`Event: ${JSON.stringify(event, null, 2)}`); console.log(`Context: ${JSON.stringify(context, null, 2)}`); return { statusCode: 200, body: JSON.stringify({ message: 'hello world', }), }; };
-
使用以下配置创建一个新的 Dockerfile。
-
将
FROM
属性设置为基本映像的 URI。 -
设置
CMD
参数以指定 Lambda 函数处理程序。
以下示例 Dockerfile 将使用多阶段构建。第一步将 TypeScript 代码转换为 JavaScript。第二步生成仅包含 JavaScript 文件和生产依赖项的容器映像。
请注意,示例 Dockerfile 不包含 USER 指令
。当您将容器映像部署到 Lambda 时,Lambda 会自动定义具有最低权限的默认 Linux 用户。这与标准 Docker 行为不同,标准 Docker 在未提供 USER
指令时默认为root
用户。例 Dockerfile
FROM public.ecr.aws/lambda/nodejs:20 as builder WORKDIR /usr/app COPY package.json index.ts ./ RUN npm install RUN npm run build FROM public.ecr.aws/lambda/nodejs:20 WORKDIR ${LAMBDA_TASK_ROOT} COPY --from=builder /usr/app/dist/* ./ CMD ["index.handler"]
-
-
使用 docker build
命令构建 Docker 映像。以下示例将映像命名为 docker-image
并为其提供test
标签。 docker build --platform linux/amd64 -t
docker-image
:test
.注意
该命令指定了
--platform linux/amd64
选项,可确保无论生成计算机的架构如何,容器始终与 Lambda 执行环境兼容。如果打算使用 ARM64 指令集架构创建 Lambda 函数,请务必将命令更改为使用--platform linux/arm64
选项。
-
使用 docker run 命令启动 Docker 映像。在此示例中,
docker-image
是映像名称,test
是标签。docker run --platform linux/amd64 -p 9000:8080 --read-only
docker-image
:test
此命令会将映像作为容器运行,并在
localhost:9000/2015-03-31/functions/function/invocations
创建本地端点。注意
如果为 ARM64 指令集架构创建 Docker 映像,请务必使用
--platform linux/
选项,而不是arm64
--platform linux/
选项。amd64
-
在新的终端窗口中,将事件发布到本地端点。
-
获取容器 ID。
docker ps
-
使用 docker kill
命令停止容器。在此命令中,将 3766c4ab331c
替换为上一步中的容器 ID。docker kill
3766c4ab331c
将映像上传到 Amazon ECR 并创建 Lambda 函数
-
运行 get-login-password
命令,以针对 Amazon ECR 注册表进行 Docker CLI 身份验证。 -
将
--region
值设置为要在其中创建 Amazon ECR 存储库的 AWS 区域。 -
将
111122223333
替换为您的 AWS 账户 ID。
aws ecr get-login-password --region
us-east-1
| docker login --username AWS --password-stdin111122223333
.dkr.ecr.us-east-1
.amazonaws.com -
-
使用 create-repository
命令在 Amazon ECR 中创建存储库。 aws ecr create-repository --repository-name
hello-world
--regionus-east-1
--image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE注意
Amazon ECR 存储库必须与 Lambda 函数位于同一 AWS 区域 内。
如果成功,您将会看到如下响应:
{ "repository": { "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world", "registryId": "111122223333", "repositoryName": "hello-world", "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world", "createdAt": "2023-03-09T10:39:01+00:00", "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": true }, "encryptionConfiguration": { "encryptionType": "AES256" } } }
-
从上一步的输出中复制
repositoryUri
。 -
运行 docker tag
命令,将本地映像作为最新版本标记到 Amazon ECR 存储库中。在此命令中: -
docker-image:test
是 Docker 映像的名称和标签。这是您在 docker build
命令中指定的映像名称和标签。 -
将
<ECRrepositoryUri>
替换为复制的repositoryUri
。确保 URI 末尾包含:latest
。
docker tag docker-image:test
<ECRrepositoryUri>
:latest例如:
docker tag
docker-image
:test
111122223333
.dkr.ecr.us-east-1
.amazonaws.com/hello-world
:latest -
-
运行 docker push
命令,以将本地映像部署到 Amazon ECR 存储库。确保存储库 URI 末尾包含 :latest
。docker push
111122223333
.dkr.ecr.us-east-1
.amazonaws.com/hello-world
:latest -
如果您还没有函数的执行角色,请创建执行角色。在下一步中,您需要提供角色的 Amazon 资源名称(ARN)。
-
创建 Lambda 函数。对于
ImageUri
,指定之前的存储库 URI。确保 URI 末尾包含:latest
。aws lambda create-function \ --function-name
hello-world
\ --package-type Image \ --code ImageUri=111122223333
.dkr.ecr.us-east-1
.amazonaws.com/hello-world
:latest \ --rolearn:aws:iam::111122223333:role/lambda-ex
注意
只要映像与 Lambda 函数位于同一区域内,您就可以使用其他 AWS 账户中的映像创建函数。有关更多信息,请参阅 Amazon ECR 跨账户权限。
-
调用函数。
aws lambda invoke --function-name
hello-world
response.json应出现如下响应:
{ "ExecutedVersion": "$LATEST", "StatusCode": 200 }
-
要查看函数的输出,请检查
response.json
文件。
要更新函数代码,您必须再次构建映像,将新映像上传到 Amazon ECR 存储库,然后使用 update-function-code
Lambda 会将映像标签解析为特定的映像摘要。这意味着,如果您将用于部署函数的映像标签指向 Amazon ECR 中的新映像,则 Lambda 不会自动更新该函数以使用新映像。
要将新映像部署到相同的 Lambda 函数,即使 Amazon ECR 中的映像标签保持不变,也必须使用 update-function-code--publish
选项使用更新的容器映像创建函数的新版本。
aws lambda update-function-code \ --function-name
hello-world
\ --image-uri111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
\ --publish