Docker 映像在本地部署,但在 Google Cloud Run 上失败

Posted

技术标签:

【中文标题】Docker 映像在本地部署,但在 Google Cloud Run 上失败【英文标题】:Docker image deploys locally but fails on Google Cloud Run 【发布时间】:2021-10-11 11:39:24 【问题描述】:

这是我的 Dockerfile:

# Use lightweight Python image
FROM python:3.9-slim

ARG DOCKER_ENV

# PYTHONFAULTHANDLER=1 - Display trace if a sefault occurs.
# PYTHONUNBUFFERED=1 - Allow statements and log messages to immediately appear in the Knative logs
# PIP_NO_CACHE_DIR=off - Disable pip cache for smaller Docker images.
# PIP_DISABLE_PIP_VERSION_CHECK=on - Ignore pip new version warning.
# PIP_DEFAULT_TIMEOUT=100 - Give pip longer than the 15 second timeout. 
ENV DOCKER_ENV=$DOCKER_ENV \
  PYTHONFAULTHANDLER=1 \
  PYTHONUNBUFFERED=1 \
  PIP_NO_CACHE_DIR=off \
  PIP_DISABLE_PIP_VERSION_CHECK=on \
  PIP_DEFAULT_TIMEOUT=100

# Install poetry 
RUN pip install

# Set working directory in container to /app
WORKDIR /app

# Copy only dependency requirements to container to cache them in docker layer
COPY poetry.lock pyproject.toml /app/

# Don't need virtualenv because environment is already isolated in a container
RUN poetry config virtualenvs.create false

# Install production dependencies 
RUN poetry install --no-dev --no-ansi

# Copy app into container 
COPY . /app

# Run server
CMD [ "poetry", "run" , "python", "api.py"]

我可以在本地构建和部署它没有问题,服务器启动。但是,当我部署到 Cloud Run 时,我收到以下错误并且容器失败:

Creating virtualenv indie-9TtSrW0h-py3.9 in /home/.cache/pypoetry/virtualenvs
File "/app/api.py", line 6, in <module>
    import jwt
ModuleNotFoundError: No module named 'jwt'

有人知道为什么这在本地成功运行但在 Cloud Run 中缺少依赖项吗?一件奇怪的事情是,我明确告诉 docker 不要在 Dockerfile 中使用虚拟环境。这在我在本地运行映像时有效,但在 Google Cloud 上它仍然坚持构建虚拟环境。与 Google Cloud Run 的 Docker 版本和我在这里缺少的诗歌是否存在某种不兼容?

【问题讨论】:

在文件requirements.txt中指定依赖关系。 你试过你的容器是另一个环境吗?例如 Compute Engine,或者 Cloud Shell? @crazysnake99 你解决了吗?我也遇到了这个问题。 @crazysnake99 我尝试让步并将poetry config virtualenvs.createfalse 设置为true,但没有帮助。 @JohnHanley 他为什么要在requirements.txt 中指定要求? Poetry 以与 pip 相同的方式将要求安装到容器中。似乎出于某种原因,在 Cloud Run 上,来自 DockerfileCMD 命令是孤立的,与其余命令处于不同的上下文中。 【参考方案1】:

似乎出于某种原因,Cloud Run 在与 Dockerfile 的其余部分隔离的上下文中运行 CMD 命令。这就是为什么poetry 认为它应该创建一个新的 virtualenv。

解决方法

(它在 21.11.2021 对我有效)

而不是

CMD [ "poetry", "run" , "python", "api.py"]

用途:

CMD ["python", "api.py"]

它应该可以工作,因为您的依赖项已经在没有 virtualenv 的情况下安装,所以此时您不再需要 poetry

【讨论】:

【参考方案2】:

我们遇到了类似的问题 - 构建成功,但 Cloud Run 服务启动失败,找不到模块,但配置略有不同。

在我们的例子中,我们没有设置virtualenvs.create

这是解决问题的一种方法 - 设置virtualenvs.in-project true

# Create virtualenv at .venv in the project instead of ~/.cache/
RUN poetry config virtualenvs.in-project true
# Install production dependencies 
RUN poetry install --no-dev --no-ansi

另一种解决方案是显式地set the virtualenv path,这样就不依赖$HOME,例如:

# Create virtualenv at /venv in the project instead of ~/.cache/
RUN poetry config virtualenvs.path /venv
# Install production dependencies 
RUN poetry install --no-dev --no-ansi

无论哪种方式,请注意,如果诗歌看到它,它将使用 ./.venv 上的 virtualenv,因此请确保您在 .dockerignore 中有 .venv/

我很确定这是因为 this issue 如果容器用户是 root,导致 Cloud Run 设置 $HOME=home

根据此 HN 评论,这是一个错误,将被修复: https://news.ycombinator.com/item?id=28678152,另见"google cloud run" changes HOME to /home for CMD where RUN uses /root

我认为这个问题的更通用的解决方案是设置USER,所以poetry install 没有以root 身份运行。

【讨论】:

谢谢,这已经帮我解决了!

以上是关于Docker 映像在本地部署,但在 Google Cloud Run 上失败的主要内容,如果未能解决你的问题,请参考以下文章

Google Cloud Run 与本地机器相比非常慢

如何使用 Docker 映像将 Node.js HTTP/2 应用程序部署到 Google Compute Engine 上?

Google App Engine Docker容器502错误网关

Traefik docker 映像不能在 Windows 上运行但在 MacOS 上运行?

GCE 未正确部署 GCR 映像

Google App Engine Java - 对于 POST 参数,request.getParameter 在部署时返回 null,但在本地工作