单体仓库环境下Docker本地运行带热重载的AWS Lambda问题排查
单体仓库中Docker化SAM CLI运行Lambda的问题与解决方案
场景背景
搭建了单体仓库(monorepo),包含apps目录下的frontend(基于NextJS,已通过Docker内执行next dev+挂载源码实现热重载)和pixel-api(Lambda函数)两个应用,目标是在不安装SAM CLI到宿主机的前提下,通过Docker运行SAM CLI实现Lambda本地运行+热重载。
现有配置
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
frontend服务运行正常,符合预期
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入口文件
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返回500,日志关键内容:
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",...}
问题解答
1. 如何在Docker容器内执行sam build?
修改pixel-api服务的command,串联执行构建与启动命令:
command: > sh -c "sam build -t ${PWD}/apps/pixel-api/template.yaml -b ${PWD}/.aws-sam/build && 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"
同时需要将宿主机目录挂载权限从ro改为rw,确保容器能写入构建产物:
volumes: - ${PWD}:${PWD}:rw
2. 如何提前预拉取Lambda运行时镜像?
在Dockerfile.pixel-api-dev末尾添加拉取命令,构建镜像时就会预下载运行时镜像:
RUN docker pull public.ecr.aws/sam/emulation-nodejs20.x
3. 为什么Lambda找不到index模块?
核心原因是挂载路径与构建产物结构不匹配:
- 未执行
sam build时,.aws-sam/build目录为空或结构错误 sam build会将apps/pixel-api/build下的内容打包到.aws-sam/build/MyLambdaFunction,而非.aws-sam/build/build- 当前
sam local start-api的-v参数挂载了错误路径,导致Lambda运行容器的/var/task目录下没有index.js
修正方案:
- 先执行
sam build(参考问题1的方法) - 调整挂载参数为构建后的函数目录:
-v "${PWD}/.aws-sam/build/MyLambdaFunction:/var/task",或直接省略-v参数,SAM会自动挂载正确的构建产物目录
4. 如何实现Lambda热重载?
要实现修改Root/apps/pixel-api/build/index.js后自动刷新,需完成以下配置:
- 挂载源码目录:在
pixel-api服务的volumes中添加:- ${PWD}/apps/pixel-api/build:${PWD}/apps/pixel-api/build:rw - 自动触发构建:在容器中安装
nodemon,监听源码变化自动执行sam build,修改command为:command: > sh -c "apk add nodejs npm && npm install -g nodemon && nodemon --watch ${PWD}/apps/pixel-api/build -e js --exec 'sam build --no-cached -t ${PWD}/apps/pixel-api/template.yaml -b ${PWD}/.aws-sam/build' & sam local start-api -t ${PWD}/apps/pixel-api/template.yaml --host=0.0.0.0 --container-host=host.docker.internal --container-host-interface=127.0.0.1" - SAM本地服务默认支持自动重载,构建产物更新后,下次调用Lambda会自动加载新代码,无需重启SAM服务
内容的提问来源于stack exchange,提问作者Tal Rofe
相关产品推荐
相关产品推荐

