docker build产生损坏的pythin库安装

时间:2018-08-15 18:56:20

标签: python docker pip dockerfile

在很多情况下,我的docker build运行会导致python库安装损坏。有时,这会导致docker构建本身在库安装步骤中失败。但更严重的是,它可能会静默失败,并且在运行该应用程序时只会看到错误。确切的python库在构建时会有所不同。重新安装相同版本的损坏的库将解决此问题。使用--no-cache似乎更好,但即使使用此构建选项,仍会发生。

示例如下:

$ docker build --no-cache --force-rm --rm -f Dockerfile . -t mypy                           

$ docker run --rm -it --entrypoint /bin/bash mypy                   
root:/# python
Python 3.6.6 (default, Jul 31 2018, 22:36:30)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import statsmodels.api as sm_api
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/statsmodels/__init__.py", line 8, in <module>
    from .tools.sm_exceptions import (ConvergenceWarning, CacheWriteWarning,
  File "/usr/local/lib/python3.6/site-packages/statsmodels/tools/__init__.py", line 1, in <module>
    from .tools import add_constant, categorical
  File "/usr/local/lib/python3.6/site-packages/statsmodels/tools/tools.py", line 11, in <module>
    from statsmodels.datasets import webuse
  File "/usr/local/lib/python3.6/site-packages/statsmodels/datasets/__init__.py", line 5, in <module>
    from . import (anes96, cancer, committee, ccard, copper, cpunish, elnino,
  File "/usr/local/lib/python3.6/site-packages/statsmodels/datasets/scotland/__init__.py", line 1
    6,�R��A�L
     ^
SyntaxError: invalid syntax

root:/# pip list | grep statsmodels
statsmodels            0.8.0

root:/# pip uninstall statsmodels

root:/# pip install statsmodels==0.8.0
Collecting statsmodels==0.8.0
  Using cached https://files.pythonhosted.org/packages/0d/e9/70d80b48c8c52a8de3ec7cd50e2aa2b1f3cf3f95e42b15fdcb59bd7189f3/statsmodels-0.8.0-cp36-cp36m-manylinux1_x86_64.whl
Requirement already satisfied: pandas in /usr/local/lib/python3.6/site-packages (from statsmodels==0.8.0) (0.19.2)
Requirement already satisfied: scipy in /usr/local/lib/python3.6/site-packages (from statsmodels==0.8.0) (1.1.0)
Requirement already satisfied: patsy in /usr/local/lib/python3.6/site-packages (from statsmodels==0.8.0) (0.5.0)
Requirement already satisfied: numpy>=1.7.0 in /usr/local/lib/python3.6/site-packages (from pandas->statsmodels==0.8.0) (1.12.1)
Requirement already satisfied: python-dateutil>=2 in /usr/local/lib/python3.6/site-packages (from pandas->statsmodels==0.8.0) (2.7.3)
Requirement already satisfied: pytz>=2011k in /usr/local/lib/python3.6/site-packages (from pandas->statsmodels==0.8.0) (2018.5)
Requirement already satisfied: six in /usr/local/lib/python3.6/site-packages (from patsy->statsmodels==0.8.0) (1.11.0)
Installing collected packages: statsmodels
Successfully installed statsmodels-0.8.0
root:/# python
Python 3.6.6 (default, Jul 31 2018, 22:36:30)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import statsmodels.api as sm_api
>>>
root:/#

Dockerfile非常简单,例如:

FROM python:3.6-slim
ARG app_dir=/root/myapp
ARG aws_access_key_id
ARG aws_secret_access_key

RUN test -n "$aws_access_key_id" && test -n "$aws_secret_access_key"

RUN mkdir -p ${app_dir} /root/.aws

RUN echo "[default]" > /root/.aws/credentials && \
  echo "aws_access_key_id = $aws_access_key_id" >> /root/.aws/credentials && \
  echo "aws_secret_access_key = $aws_secret_access_key" >> /root/.aws/credentials

ADD requirements.txt ${app_dir}/requirements.txt

RUN apt-get update -qqy && apt-get install -qqy --no-install-recommends \
  build-essential libopenblas-dev gfortran procps less nano wget

RUN pip install -r ${app_dir}/requirements.txt

这些无提示错误非常危险,因为我们不会使用针对Docker映像的特定于应用程序的单元测试来进行广泛的验证。我们希望看到可复制的图像。如何防止这些错误?

1 个答案:

答案 0 :(得分:0)

我没有答案,只是一个建议。

如果依赖项仅是构建依赖项,而不是运行时依赖项,请使用多阶段构建。

这样,您可以在构建的第一步中生产车轮,然后在第二步中安装车轮。如果创建的车轮损坏了,则有可能无法安装,但我不确定。

基于Dockerfile的示例:

FROM python:3.6-slim as builder

ADD requirements.txt requirements.txt

RUN apt-get update -qqy && apt-get install -qqy --no-install-recommends \
  build-essential libopenblas-dev gfortran gcc gfortran g++  

RUN mkdir /wheels && \
    pip install -U pip wheel setuptools && pip wheel -r requirements.txt --wheel-dir=/wheels

FROM python3.6-slim as prod

ARG app_dir=/root/myapp
ARG aws_access_key_id
ARG aws_secret_access_key

RUN echo "[default]" > /root/.aws/credentials && \
  echo "aws_access_key_id = $aws_access_key_id" >> /root/.aws/credentials && \
  echo "aws_secret_access_key = $aws_secret_access_key" >> /root/.aws/credentials

COPY --from=builder /wheels /tmp/wheels
ADD requirements.txt requirements.txt

RUN pip install --no-cache-dir --no-index --find-links=/tmp/wheels/. -r requirements.txt 

WORKDIR $app_dir

如果您不介意较长的构建过程,则可以在prod和builder之间添加一个步骤,该步骤将安装和导入所有模块以测试导入是否失败:

FROM python:3.6-slim as builder

ADD requirements.txt requirements.txt

RUN apt-get update -qqy && apt-get install -qqy --no-install-recommends \
  build-essential libopenblas-dev gfortran gcc gfortran g++  

RUN mkdir /wheels && \
    pip install -U pip wheel setuptools && pip wheel -r requirements.txt --wheel-dir=/wheels

FROM python3.6-slim as test

COPY --from=builder /wheels /tmp/wheels
ADD requirements.txt requirements.txt

RUN pip install --no-cache-dir --no-index --find-links=/tmp/wheels/. -r requirements.txt 
# Will fail if one of requirements cannot be imported
RUN python -c 'f = open("requirements.txt") ; modules = [line.strip() for line in f.readlines() if line.strip()] ; f.close() ; list(map(__import__, modules))'

FROM python3.6-slim as prod

ARG app_dir=/root/myapp
ARG aws_access_key_id
ARG aws_secret_access_key

RUN echo "[default]" > /root/.aws/credentials && \
  echo "aws_access_key_id = $aws_access_key_id" >> /root/.aws/credentials && \
  echo "aws_secret_access_key = $aws_secret_access_key" >> /root/.aws/credentials

COPY --from=builder /wheels /tmp/wheels
ADD requirements.txt requirements.txt

RUN pip install --no-cache-dir --no-index --find-links=/tmp/wheels/. -r requirements.txt 

WORKDIR $app_dir

这是一个非常丑陋的建议,但也许可以帮助您...