在 monorepo 环境中使用 Docker 和热重载本地运行 AWS Lambda 函数

问题描述 投票:0回答:1

为方便起见,这里提供了应用程序用例的演示:https://github.com/tal-rofe/demo-lambda


我设置了一个 monorepo 环境,其中只有

apps
文件夹,其中包含 2 个应用程序,
frontend
pixel-api

我想通过热重载在本地运行这些两者。意思是——每当我修改每个项目的源代码时,工件都会刷新。例如,我使用 NextJS 运行前端应用程序,因此可以通过在 docker 容器内运行

next dev
并使用 Bind Mount 到主机上的源代码来轻松支持它。

问题是我尝试用 Lambda 函数做同样的事情。 AWS 支持

sam local start-api
(https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-start-api.html) 命令这很有帮助,但我不想将
sam
CLI 安装到开发人员机器上。

所以我的目的是在 Docker 内运行 SAM CLI。

我发现此评论描述了如何执行此操作:https://github.com/aws/aws-sam-cli/issues/55#issuecomment-1717711860 还有这个:https://github.com/aws/aws-sam-cli/issues/55#issuecomment-1717819156

我复制了代码并尝试将其调整为我的项目,但效果不佳。

根/docker-compose.dev.yaml:

version: '3.8'

services:
    pixel-api:
        build:
            context: .
            dockerfile: ./docker/Dockerfile.pixel-api-dev
        command: sam local start-api -t "${PWD}/apps/pixel-api/template.yaml" -v "${PWD}/.aws-sam/build" --host=0.0.0.0 --container-host=host.docker.internal --container-host-interface=127.0.0.1
        ports:
            - '3000:3000'
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock:ro
            - ${PWD}:${PWD}:ro
            - /dashboard/apps/pixel-api/node_modules
            - /dashboard/node_modules
        environment:
            SAM_CLI_TELEMETRY: 0
            SAM_CLI_CONTAINER_CONNECTION_TIMEOUT: 30
            sam_local_environment: 'true'

    frontend:
        container_name: frontend
        build:
            context: .
            dockerfile: ./docker/Dockerfile.frontend-dev
        env_file:
            - ./apps/frontend/envs/.env.development
        ports:
            - 8080:8080
        restart: always
        networks:
            - dashboard_network
        volumes:
            - type: bind
              source: ./apps/frontend/src
              target: /dashboard/apps/frontend/src
            - /dashboard/apps/frontend/node_modules

networks:
    dashboard_network:
        driver: bridge

“前端”服务按预期工作并成功。

根/apps/pixel-api/template.yaml:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM template for running locally API Gateway & Lambda function for Pixel API function

Globals:
    Api:
        Cors:
            AllowMethods: "'POST,OPTIONS'"
            AllowHeaders: "'content-type','x-api-key','x-amz-security-token','authorization','x-amz-user-agent','x-amz-date'"
            AllowOrigin: "'*'"
            AllowCredentials: "'*'"

Resources:
    AwsApiGateway:
        Type: AWS::Serverless::HttpApi
        Properties:
            Name: AWS API Gateway - Pixel API
            StageName: development

    MyLambdaFunction:
        Type: 'AWS::Serverless::Function'
        Properties:
            Runtime: nodejs20.x
            Handler: index.handler
            CodeUri: build
            Timeout: 30
            Description: 'Pixel API Lambda function'
            Environment:
                Variables:
                    sam_local_environment: 'true'
            Events:
                Api:
                    Type: HttpApi
                    Properties:
                        ApiId: !Ref AwsApiGateway
                        Path: /
                        Method: POST

我还有“Root/apps/pixel-api/build/index.js` 文件作为 Lambda 函数 NodeJS 函数。

我还有 Pixel-api 服务的 Dockerfile:

根/docker/Dockerfile.pixel-api-dev:

FROM public.ecr.aws/docker/library/docker

ENV PIP_BREAK_SYSTEM_PACKAGES 1

RUN apk update && \
    apk add gcc py-pip python3-dev libffi-dev musl-dev && \
    pip install --upgrade pip setuptools wheel && \
    pip install --upgrade aws-sam-cli

WORKDIR /var/opt

ENTRYPOINT []
CMD ["/bin/bash"]

当我使用

docker-compose up -d
运行服务时,两项服务都会成功。但是当我运行
curl -X POST http://localhost:3000
时 - 调用 Lambda 函数失败:

Mounting MyLambdaFunction at http://0.0.0.0:3000/ [POST]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. If you used sam build before running local commands, you will need to re-run sam build for the changes to be picked up. You only need to restart SAM CLI if you update your AWS SAM template
2024-03-20 07:24:30 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:3000
 * Running on http://172.20.0.2:3000
2024-03-20 07:24:30 Press CTRL+C to quit
Invoking index.handler (nodejs20.x)
Local image was not found.
Removing rapid images for repo public.ecr.aws/sam/emulation-nodejs20.x
Building image..........................................................................................................................................................................................................................................................................................................................................................
Using local image: public.ecr.aws/lambda/nodejs:20-rapid-x86_64.

Mounting /MY_MACHINE_PATH/dashboard/.aws-sam/build/build as /var/task:ro,delegated, inside runtime container
START RequestId: 3e76c0ee-26bb-4250-983c-f60252289641 Version: $LATEST
2024-03-20T07:25:35.076Z        undefined       ERROR   Uncaught Exception  {"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'index'\nRequire stack:\n- /var/runtime/index.mjs","stack":["Runtime.ImportModuleError: Error: Cannot find module 'index'","Require stack:","- /var/runtime/index.mjs","    at _loadUserApp (file:///var/runtime/index.mjs:1087:17)","    at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1119:21)","    at async start (file:///var/runtime/index.mjs:1282:23)","    at async file:///var/runtime/index.mjs:1288:1"]}
20 Mar 2024 07:25:35,212 [ERROR] (rapid) Init failed error=Runtime exited with error: exit status 129 InvokeID=
20 Mar 2024 07:25:35,216 [ERROR] (rapid) Invoke failed error=Runtime exited with error: exit status 129 InvokeID=33a8293f-9315-4d2a-808f-265f5620f20f
20 Mar 2024 07:25:35,218 [ERROR] (rapid) Invoke DONE failed: Sandbox.Failure

2024-03-20 07:25:36 192.168.65.1 - - [20/Mar/2024 07:25:36] "POST / HTTP/1.1" 500 -

我的问题:

  1. 请注意,我根本没有运行
    sam build
    ,我的主机上什至没有
    sam
    CLI。 如果我需要这样做,我该如何在 Docker 中进行?
  2. 在尝试使用
    nodejs20.x
    版本来实现我的功能后,您可以从我附加的日志中看到:
Local image was not found.
Removing rapid images for repo public.ecr.aws/sam/emulation-nodejs20.x
Building image..........................................................................................................................................................................................................................................................................................................................................................
Using local image: public.ecr.aws/lambda/nodejs:20-rapid-x86_64.

所以,好吧,没有图像,但它在第一次 lambda 请求触发后运行。有没有办法提前在 Dockerfile.pixel-api-dev 上完成此操作?所以第一个请求不需要等待图像下载...

  1. 当然还有主要问题 - 为什么它找不到我的 Lambda 函数?

  2. 此外,如何启用此 lambda 函数的热重载,以便每次修改

    Root/apps/pixel-api/build/index.js
    文件时,lambda 函数都会在
    localhost:3000
    上刷新?请注意我附加的日志中的评论:

You do not need to restart/reload SAM CLI while working on your functions,
changes will be reflected instantly/automatically.
If you used sam build before running local commands, you will need to re-run sam build for the changes to be picked up

再次强调,如果可能的话,我不想在我的主机上使用

sam
CLI。

docker docker-compose aws-lambda aws-sam-cli
1个回答
0
投票

这不是直接解决方案,而是迁移到其他框架的解决方案。由于我不介意用于测试我的 Lambda 函数代码的底层框架,因此这个解决方案对我来说很好。

我迁移了开发框架以使用无服务器框架。然后我刚刚创建了这个

serverless.yaml
文件:

org: kynesis
app: pixel-api
console: true
service: pixel-http-api
frameworkVersion: '3'
configValidationMode: error

provider:
    name: aws
    httpApi:
        cors:
            allowedOrigins:
                - '*'
            allowedHeaders:
                - Content-Type
            allowedMethods:
                - POST
            allowCredentials: false

custom:
    serverless-offline:
        # * https://forum.serverless.com/t/possible-to-run-serverless-in-a-docker-container/5764/4
        host: 0.0.0.0

plugins:
    - serverless-offline

functions:
    pixel-api:
        name: pixel-api
        runtime: nodejs20.x
        handler: ./build/index.handler
        events:
            - httpApi:
                  path: /
                  method: POST

将我的 docker compose 文件修改为:

version: '3.8'

services:
    pixel-api:
        container_name: pixel-api
        build:
            context: .
            dockerfile: ./docker/Dockerfile.pixel-api-dev
        ports:
            - 3000:3000
        restart: always
        networks:
            - dashboard_network
        volumes:
            - type: bind
              source: ./apps/pixel-api/src
              target: /dashboard/apps/pixel-api/src
            - /dashboard/apps/pixel-api/node_modules
            - /dashboard/node_modules

    frontend:
        container_name: frontend
        build:
            context: .
            dockerfile: ./docker/Dockerfile.frontend-dev
        env_file:
            - ./apps/frontend/envs/.env.development
        ports:
            - 8080:8080
        restart: always
        networks:
            - dashboard_network
        volumes:
            - type: bind
              source: ./apps/frontend/src
              target: /dashboard/apps/frontend/src
            - /dashboard/apps/frontend/node_modules
            - /dashboard/node_modules

networks:
    dashboard_network:
        driver: bridge

将我的 Dockerfile 修改为

FROM node:20.11.1

RUN npm i -g [email protected]

WORKDIR /dashboard

COPY ./package.json ./pnpm-workspace.yaml ./.npmrc ./
COPY ./apps/pixel-api/package.json ./apps/pixel-api/

RUN pnpm i -w
RUN pnpm --filter pixel-api i

COPY ./tsconfig.base.json ./nx.json ./
COPY ./apps/pixel-api/ ./apps/pixel-api/

CMD ["pnpm", "exec", "nx", "start:dev", "blabla"]

然后我还配置了

nodemon.json
文件来重建我的 Lambda 代码并重新启动无服务器框架服务器:

{
    "$schema": "https://json.schemastore.org/nodemon.json",
    "watch": ["./src", "./serverless.yaml"],
    "ext": "ts,json",
    "exec": "node ./esbuild.js && sls offline --httpPort 3000"
}
© www.soinside.com 2019 - 2024. All rights reserved.