Docker 中的 Python 脚本在子目录中找不到模块



我的项目结构如下:

.
├── my_script.Dockerfile
├── README.rst
├── log
│   └── my_script.log
├── pickles
├── requirements.txt
├── requirements_my_script.txt
├── src
│   ├── __init__.py
│   ├── __pycache__
│   ├── main.py
│   ├── modules
│   │   ├── __init__.py
│   │   └── module.py
│   ├── other_scripts
│   │   └── my_script.py
│   └── utils
│       ├── __init__.py
│       ├── __pycache__
│       └── logging_utils.py

my_script.Dockerfile如下所示:

# syntax=docker/dockerfile:1
FROM python:3.10-slim-buster
WORKDIR /src
COPY requirements_my_script.txt requirements_my_script.txt
RUN pip3 install -r requirements_my_script.txt
COPY src/. .
CMD ["python3", "other_scripts/my_script.py"]

my_script.py:

import logging
from src.utils.logging_utils import start_logger

def main(logger):
# some code here
logger.info('done')
sleep(120)


if __name__=='__main__':
logger = start_logger('my_script.log')
try:
logger.info('Starting..')
main(logger)
except Exception as e:
logger.critical('Crashed with error: {}'.format(e))

和logging_utils.py:

import os
import logging
from logging.handlers import RotatingFileHandler
def start_logger(filename, level='INFO'): # INFO or DEBUG
# # LOGGING
log_folder = os.path.join(os.path.expanduser('~'), 'project_folder_name', 'log')
if not os.path.exists(log_folder):
os.makedirs(log_folder)
log_filename = filename
logger = logging.getLogger()
logFormatter = logging.Formatter(fmt='%(asctime)s :: %(levelname)s - %(message)s')
if level == 'DEBUG':
logger.setLevel(logging.DEBUG)
else:
logger.setLevel(logging.INFO)
# add a rotating handler
handler = RotatingFileHandler(os.path.join(log_folder, log_filename), maxBytes=1000000, backupCount=1)
handler.setFormatter(logFormatter)
logger.addHandler(handler)
return logger

这在我的机器上运行得很完美,但当我构建docker并尝试运行它时,我会得到以下错误:

from src.utils.logging_utils import start_logger
ModuleNotFoundError: No module named 'src'

我在dockerfile中尝试了几个不同的COPY语句,但没有成功。

有人能告诉我我做错了什么吗?

编辑我也试过这个dockerfile:

# syntax=docker/dockerfile:1
FROM python:3.10-slim-buster
WORKDIR /app
COPY requirements_my_script.txt requirements_my_script.txt
RUN pip3 install -r requirements_my_script.txt
COPY src/ src/
CMD ["python3", "src/other_scripts/my_script.py"]

但我得到了完全相同的错误。

在不重构代码的情况下解决此问题的方法是在dockerfile中添加ENV,如下所示:

# syntax=docker/dockerfile:1
FROM python:3.10-slim-buster
WORKDIR /app
COPY requirements_my_script.txt requirements_my_script.txt
RUN pip3 install -r requirements_my_script.txt
COPY src/ src/
ENV PYTHONPATH /app
CMD ["python3", "src/other_scripts/my_script.py"]

my_script.py:中删除此行

from src.utils.logging_utils import start_logger

将这些行添加到my_script.py:

from sys import path as syspath
from os import path as ospath
syspath.append(ospath.join(ospath.dirname(ospath.realpath(__file__)),'..','utils')) # To find out where to look, import the utils path into the script path
from logging_utils import start_logger

并在Dockerfile:中执行此操作

COPY src/ src/

当您的代码执行import

from src.utils.logging_utils ...

Python查找相对于当前目录和Python搜索路径中的任何其他目录的./src/utils/logging_utils.py。但在Dockerfile中,您去掉了src目录:

COPY src/. .

src目录的内容复制到当前目录中。我猜如果您使用docker run --rm your-image ls,您将立即在应用程序目录中看到utils目录,而不是在src子目录中。

如果您需要将主机上的子目录复制到映像中的子目录中,则需要在COPY的两侧重复目录名,如

COPY src/ src/

最新更新