使用容器镜像在 Lambda 中部署转换后的 TypeScript 代码 - AWS Lambda

使用容器镜像在 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 函数代码

要完成本节中的步骤,您必须满足以下条件:

通过AWS基本映像为 Lambda 创建映像
  1. 在本地计算机上,为新函数创建项目目录。

  2. 使用 npm 或您选择的软件包管理器创建一个新的 Node.js 项目。

    npm init
  3. 添加 @types/aws-lambdaesbuild 软件包作为开发依赖项。@types/aws-lambda 程序包包含 Lambda 的类型定义。

    npm install -D @types/aws-lambda esbuild
  4. 构建脚本添加到 package.json 文件。

    "scripts": { "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js" }
  5. 创建名为 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', }), }; };
  6. 使用以下配置创建一个新的 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"]
  7. 使用 docker build 命令构建 Docker 映像。以下示例将映像命名为 docker-image 并为其提供 test 标签

    docker build --platform linux/amd64 -t docker-image:test .
    注意

    该命令指定了 --platform linux/amd64 选项,可确保无论生成计算机的架构如何,容器始终与 Lambda 执行环境兼容。如果打算使用 ARM64 指令集架构创建 Lambda 函数,请务必将命令更改为使用 --platform linux/arm64 选项。

  1. 使用 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 选项。

  2. 在新的终端窗口中,将事件发布到本地端点。

    Linux/macOS

    在 Linux 和 macOS 中,运行以下 curl 命令:

    curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'

    此命令使用空事件调用函数并返回响应。如果您使用自己的函数代码而不是示例函数代码,则可能需要使用 JSON 负载调用函数。例如:

    curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
    PowerShell

    在 PowerShell 中,运行以下 Invoke-WebRequest 命令:

    Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"

    此命令使用空事件调用函数并返回响应。如果您使用自己的函数代码而不是示例函数代码,则可能需要使用 JSON 负载调用函数。例如:

    Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
  3. 获取容器 ID。

    docker ps
  4. 使用 docker kill 命令停止容器。在此命令中,将 3766c4ab331c 替换为上一步中的容器 ID。

    docker kill 3766c4ab331c
将映像上传到 Amazon ECR 并创建 Lambda 函数
  1. 运行 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-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
  2. 使用 create-repository 命令在 Amazon ECR 中创建存储库。

    aws ecr create-repository --repository-name hello-world --region us-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" } } }
  3. 从上一步的输出中复制 repositoryUri

  4. 运行 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
  5. 运行 docker push 命令,以将本地映像部署到 Amazon ECR 存储库。确保存储库 URI 末尾包含 :latest

    docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
  6. 如果您还没有函数的执行角色,请创建执行角色。在下一步中,您需要提供角色的 Amazon 资源名称(ARN)。

  7. 创建 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 \ --role arn:aws:iam::111122223333:role/lambda-ex
    注意

    只要映像与 Lambda 函数位于同一区域内,您就可以使用其他 AWS 账户中的映像创建函数。有关更多信息,请参阅 Amazon ECR 跨账户权限

  8. 调用函数。

    aws lambda invoke --function-name hello-world response.json

    应出现如下响应:

    { "ExecutedVersion": "$LATEST", "StatusCode": 200 }
  9. 要查看函数的输出,请检查 response.json 文件。

要更新函数代码,您必须再次构建映像,将新映像上传到 Amazon ECR 存储库,然后使用 update-function-code 命令将映像部署到 Lambda 函数。

Lambda 会将映像标签解析为特定的映像摘要。这意味着,如果您将用于部署函数的映像标签指向 Amazon ECR 中的新映像,则 Lambda 不会自动更新该函数以使用新映像。

要将新映像部署到相同的 Lambda 函数,即使 Amazon ECR 中的映像标签保持不变,也必须使用 update-function-code 命令。在以下示例中,--publish 选项使用更新的容器映像创建函数的新版本。

aws lambda update-function-code \ --function-name hello-world \ --image-uri 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \ --publish