为方便起见,这里提供了应用程序用例的演示: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 -
我的问题:
sam build
,我的主机上什至没有 sam
CLI。 如果我需要这样做,我该如何在 Docker 中进行?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 上完成此操作?所以第一个请求不需要等待图像下载...
当然还有主要问题 - 为什么它找不到我的 Lambda 函数?
此外,如何启用此 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。
这不是直接解决方案,而是迁移到其他框架的解决方案。由于我不介意用于测试我的 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"
}