如何配置Python3.9容器镜像以实现AWS Lambda多层目录处理程序?
解决Lambda Docker部署的模块导入问题
问题背景
应用目录结构:
. ├── Dockerfile └── app └── src └── main.py └── custom.py
原Dockerfile内容:
FROM public.ecr.aws/lambda/python:3.9 WORKDIR /app COPY /app /app RUN yum -y install gcc libmariadb-dev default-libmysqlclient-dev python-devel mysql-devel RUN /var/lang/bin/python3.9 -m pip install --upgrade pip RUN pip install -U poetry RUN poetry export --only main --without-hashes --format=requirements.txt > requirements.txt RUN pip install -r requirements.txt -t . ENV PYTHONPATH="$PYTHONPATH:${LAMBDA_TASK_ROOT}" WORKDIR ${LAMBDA_TASK_ROOT}/src ENTRYPOINT ["/lambda-entrypoint.sh"] CMD ["main.lambda_handler"]
触发Lambda时出现错误:
{ "errorMessage": "Unable to import module 'main': No module named 'main'", "errorType": "Runtime.ImportModuleError", "requestId": "...", "stackTrace": [] }
main.py中的导入语句:
from typing import Any from src.custom import Function def lambda_handler(event: dict[str, Any], context: Any): # Function相关逻辑
错误原因
- 模块路径不匹配:原Dockerfile将
app目录复制到/app,但Lambda默认从${LAMBDA_TASK_ROOT}(即/var/task)加载模块,导致无法找到main模块。 - PYTHONPATH配置不当:未将包含
src目录的路径添加到Python的模块搜索路径,同时工作目录设置为${LAMBDA_TASK_ROOT}/src,进一步加剧了路径混乱。 - 内部模块导入路径错误:
main.py中使用from src.custom import Function,但在原配置下src模块不在Python的搜索路径中。
解决方案
提供两种可行的修改方案,可根据是否允许修改代码选择:
方案一:调整目录结构与代码导入(无需复杂PYTHONPATH配置)
修改Dockerfile,将src下的内容直接复制到Lambda任务根目录,并调整代码导入为相对路径:
修改后的Dockerfile
FROM public.ecr.aws/lambda/python:3.9 # 将app/src下的所有文件复制到Lambda任务根目录(/var/task) COPY app/src/ ${LAMBDA_TASK_ROOT}/ # 复制poetry配置文件到任务根目录(确保能导出依赖) COPY app/pyproject.toml app/poetry.lock ${LAMBDA_TASK_ROOT}/ WORKDIR ${LAMBDA_TASK_ROOT} # 安装系统依赖并清理缓存 RUN yum -y install gcc libmariadb-dev default-libmysqlclient-dev python-devel mysql-devel && yum clean all # 升级pip并安装poetry RUN /var/lang/bin/python3.9 -m pip install --upgrade pip RUN pip install -U poetry # 导出requirements并安装依赖到当前目录 RUN poetry export --only main --without-hashes --format=requirements.txt > requirements.txt RUN pip install -r requirements.txt -t . # 明确PYTHONPATH包含任务根目录(默认已包含,显式设置更稳妥) ENV PYTHONPATH="${PYTHONPATH}:${LAMBDA_TASK_ROOT}" ENTRYPOINT ["/lambda-entrypoint.sh"] # 直接指定main模块中的lambda_handler函数 CMD ["main.lambda_handler"]
修改main.py的导入语句
将绝对导入改为相对导入(因为custom.py与main.py在同一目录):
from typing import Any # 相对导入同目录下的custom模块 from .custom import Function def lambda_handler(event: dict[str, Any], context: Any): # 业务逻辑 return {"statusCode": 200, "body": "Success"}
方案二:保留原目录结构(无需修改代码)
通过调整PYTHONPATH和CMD模块路径,让Python能识别原目录结构中的src模块:
修改后的Dockerfile
FROM public.ecr.aws/lambda/python:3.9 # 将整个app目录复制到Lambda任务根目录下 COPY app/ ${LAMBDA_TASK_ROOT}/app # 复制poetry配置文件到任务根目录 COPY app/pyproject.toml app/poetry.lock ${LAMBDA_TASK_ROOT}/ WORKDIR ${LAMBDA_TASK_ROOT} # 安装系统依赖并清理缓存 RUN yum -y install gcc libmariadb-dev default-libmysqlclient-dev python-devel mysql-devel && yum clean all # 升级pip并安装poetry RUN /var/lang/bin/python3.9 -m pip install --upgrade pip RUN pip install -U poetry # 导出requirements并安装依赖到当前目录 RUN poetry export --only main --without-hashes --format=requirements.txt > requirements.txt RUN pip install -r requirements.txt -t . # 将app目录添加到PYTHONPATH,让Python能找到src模块 ENV PYTHONPATH="${PYTHONPATH}:${LAMBDA_TASK_ROOT}/app" ENTRYPOINT ["/lambda-entrypoint.sh"] # 指定src.main模块中的lambda_handler函数(src是顶级模块) CMD ["src.main.lambda_handler"]
此方案下,main.py中的from src.custom import Function无需修改,因为src已被Python识别为顶级模块。
内容的提问来源于stack exchange,提问作者weekwith.me
相关产品推荐
相关产品推荐

