使用容器映像部署 Node.js Lambda 函数 - AWS Lambda

使用容器映像部署 Node.js Lambda 函数

有三种方法可以为 Node.js Lambda 函数构建容器映像:

提示

要缩短 Lambda 容器函数激活所需的时间,请参阅 Docker 文档中的使用多阶段构建。要构建高效的容器映像,请遵循编写 Dockerfiles 的最佳实践

此页面介绍了如何为 Lambda 构建、测试和部署容器映像。

Node.js 的 AWS 基本映像

AWS 为 Node.js 提供了以下基本映像:

标签 运行时 操作系统 Dockerfile 淘汰

20

Node.js 20 Amazon Linux 2023 GitHub 上适用于 Node.js 20 的 Dockerfile

未计划

18

Node.js 18 Amazon Linux 2 GitHub 上适用于 Node.js 18 的 Dockerfile

2025 年 7 月 31 日

Amazon ECR 存储库:gallery.ecr.aws/lambda/nodejs

Node.js 20 及更高版本的基础映像基于 Amazon Linux 2023 最小容器映像。早期的基础映像使用 Amazon Linux 2。与 Amazon Linux 2 相比,AL2023 具有多项优势,包括较小的部署占用空间以及 glibc 等更新版本的库。

基于 AL2023 的映像使用 microdnf(符号链接为 dnf)作为软件包管理器,而不是 Amazon Linux 2 中的默认软件包管理器 yummicrodnfdnf 的独立实现。有关基于 AL2023 的映像中已包含软件包的列表,请参阅 Comparing packages installed on Amazon Linux 2023 Container Images 中的 Minimal Container 列。有关 AL2023 和 Amazon Linux 2 之间区别的更多信息,请参阅 AWS 计算博客上的 Introducing the Amazon Linux 2023 runtime for AWS Lambda

注意

要在本地运行基于 AL2023 的映像,包括使用 AWS Serverless Application Model(AWS SAM),您必须使用 Docker 版本 20.10.10 或更高版本。

使用 Node.js 的 AWS 基本映像

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

从 Node.js 的 AWS 的基本映像创建容器映像
  1. 为项目创建一个目录,然后切换到该目录。

    mkdir example cd example
  2. 使用 npm 创建新的 Node.js 项目。要在交互式体验中接受提供的默认选项,请按 Enter

    npm init
  3. 创建名为 index.js 的新文件。您可以将以下示例函数代码添加到文件中进行测试,也可以使用您自己的函数代码。

    例 CommonJS 处理程序
    exports.handler = async (event) => { const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };
  4. 如果函数依赖于 AWS SDK for JavaScript 之外的库,请使用 npm 将其添加到程序包。

  5. 使用以下配置创建一个新的 Dockerfile。

    请注意,示例 Dockerfile 不包含 USER 指令。当您将容器映像部署到 Lambda 时,Lambda 会自动定义具有最低权限的默认 Linux 用户。这与标准 Docker 行为不同,标准 Docker 在未提供 USER 指令时默认为 root 用户。

    例 Dockerfile
    FROM public.ecr.aws/lambda/nodejs:20 # Copy function code COPY index.js ${LAMBDA_TASK_ROOT} # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile) CMD [ "index.handler" ]
  6. 使用 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 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

将备用基本映像与运行时系统接口客户端配合使用

如果使用仅限操作系统的基础映像或者备用基础映像,则必须在映像中包括运行时系统接口客户端。运行时系统接口客户端可扩展 将 Lambda 运行时 API 用于自定义运行时,用于管理 Lambda 和函数代码之间的交互。

使用 npm 包管理器安装 Node.js 运行时系统接口客户端

npm install aws-lambda-ric

您也可以从 GitHub 下载 Node.js 运行时接口客户端。运行时系统接口客户端支持以下 NodeJS 版本:

  • 14.x

  • 16.x

  • 18.x

  • 20.x

以下示例演示了如何使用非 AWS 基本映像为 Node.js 构建容器映像。示例 Dockerfile 使用 buster 基本映像。Docker 包含运行时系统接口客户端。

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

要从非 AWS 基本映像创建容器映像
  1. 为项目创建一个目录,然后切换到该目录。

    mkdir example cd example
  2. 使用 npm 创建新的 Node.js 项目。要在交互式体验中接受提供的默认选项,请按 Enter

    npm init
  3. 创建名为 index.js 的新文件。您可以将以下示例函数代码添加到文件中进行测试,也可以使用您自己的函数代码。

    例 CommonJS 处理程序
    exports.handler = async (event) => { const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };
  4. 创建新 Dockerfile。以下 Dockerfile 使用 buster 基本映像而不是 AWS 基本映像。Dockerfile 包含运行时系统接口客户端,该客户端可使映像与 Lambda 兼容。Dockerfile 使用多阶段构建。第一阶段将创建一个构建映像,作为安装函数依赖项的标准 Node.js 环境。第二阶段创建一个更精简的映像,其中包含函数代码及其依赖项。此机制可缩减最终映像大小。

    • FROM 属性设置为基本映像标识符。

    • 使用 COPY 命令将复制函数代码和运行时系统依赖项。

    • ENTRYPOINT 设置为您希望 Docker 容器在启动时运行的模块。在本例中,模块为运行时系统接口客户端。

    • CMD 参数设置为 Lambda 函数处理程序。

    请注意,示例 Dockerfile 不包含 USER 指令。当您将容器映像部署到 Lambda 时,Lambda 会自动定义具有最低权限的默认 Linux 用户。这与标准 Docker 行为不同,标准 Docker 在未提供 USER 指令时默认为 root 用户。

    例 Dockerfile
    # Define custom function directory ARG FUNCTION_DIR="/function" FROM node:20-buster as build-image # Include global arg in this stage of the build ARG FUNCTION_DIR # Install build dependencies RUN apt-get update && \ apt-get install -y \ g++ \ make \ cmake \ unzip \ libcurl4-openssl-dev # Copy function code RUN mkdir -p ${FUNCTION_DIR} COPY . ${FUNCTION_DIR} WORKDIR ${FUNCTION_DIR} # Install Node.js dependencies RUN npm install # Install the runtime interface client RUN npm install aws-lambda-ric # Grab a fresh slim copy of the image to reduce the final size FROM node:20-buster-slim # Required for Node runtimes which use npm@8.6.0+ because # by default npm writes logs under /home/.npm and Lambda fs is read-only ENV NPM_CONFIG_CACHE=/tmp/.npm # Include global arg in this stage of the build ARG FUNCTION_DIR # Set working directory to function root directory WORKDIR ${FUNCTION_DIR} # Copy in the built dependencies COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR} # Set runtime interface client as default command for the container runtime ENTRYPOINT ["/usr/local/bin/npx", "aws-lambda-ric"] # Pass the name of the function handler as an argument to the runtime CMD ["index.handler"]
  5. 使用 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. 从项目目录中,运行以下命令以从 GitHub 下载运行时系统接口仿真器(x86-64 架构)并将其安装在本地计算机上。

    Linux/macOS
    mkdir -p ~/.aws-lambda-rie && \ curl -Lo ~/.aws-lambda-rie/aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie && \ chmod +x ~/.aws-lambda-rie/aws-lambda-rie

    要安装 arm64 仿真器,请将上一条命令中的 GitHub 存储库 URL 替换为以下内容:

    https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
    PowerShell
    $dirPath = "$HOME\.aws-lambda-rie" if (-not (Test-Path $dirPath)) { New-Item -Path $dirPath -ItemType Directory } $downloadLink = "https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie" $destinationPath = "$HOME\.aws-lambda-rie\aws-lambda-rie" Invoke-WebRequest -Uri $downloadLink -OutFile $destinationPath

    要安装 arm64 模拟器,请将 $downloadLink 替换为以下内容:

    https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
  2. 使用 docker run 命令启动 Docker 映像。请注意以下几点:

    • docker-image 是映像名称,test 是标签。

    • /usr/local/bin/npx aws-lambda-ric index.handlerENTRYPOINT,后跟您 Dockerfile 中的 CMD

    Linux/macOS
    docker run --platform linux/amd64 -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \ docker-image:test \ /usr/local/bin/npx aws-lambda-ric index.handler
    PowerShell
    docker run --platform linux/amd64 -d -v "$HOME\.aws-lambda-rie:/aws-lambda" -p 9000:8080 ` --entrypoint /aws-lambda/aws-lambda-rie ` docker-image:test ` /usr/local/bin/npx aws-lambda-ric index.handler

    此命令会将映像作为容器运行,并在 localhost:9000/2015-03-31/functions/function/invocations 创建本地端点。

    注意

    如果为 ARM64 指令集架构创建 Docker 映像,请务必使用 --platform linux/arm64 选项,而不是 --platform linux/amd64 选项。

  3. 将事件发布到本地端点。

    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"
  4. 获取容器 ID。

    docker ps
  5. 使用 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