1

I am trying to build a docker image that contains cuda, cudnn and python, each with specific versions that are templatable as a base for downstream users. (In this example I have replace all the irrelevant templating with hard-coded versions, this is just FYI as a motivation).

Please note that the following questions are not duplicates:

I have achieved what I want using pyenv to install the specific python version within docker inside the nvidia image. However, this solution is not optimal since the resulting image is about 1.5GB larger than what I think should be possible. Sidenote: I know that there are other ways to reduce the image size further that I have not done in this example. This is not the question here.

I have prepared a dummy pyproject.toml and poetry.lock to demonstrate the issue that I am currently facing:

pyproject.toml

[tool.poetry]
name = "example_project"
version = "1.0.0"
description = ""
authors = ["RunOrVeith"]

[tool.poetry.dependencies]
python = ">=3.8,<3.11"
scipy = "^1.9.3"

[build-system]
requires = ["poetry-core>=1.1.0"]
build-backend = "poetry.core.masonry.api"

Working Dockerfile.pyenv

FROM nvidia/cuda:11.0.3-cudnn8-runtime-ubuntu20.04 as base
ARG PYTHON_VERSION=3.8
ENV DEBIAN_FRONTEND=noninteractive

# Set-up necessary Env vars for PyEnv
ENV PYENV_ROOT /root/.pyenv
ENV PATH $PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH
ENV PATH="/root/.local/bin/:$PATH"

# Install essentials for pyenv https://github.com/pyenv/pyenv/wiki
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
      make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget ca-certificates  \
      curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev mecab-ipadic-utf8 git \
    && rm -rf /var/lib/apt/lists/*

# Install pyenv
RUN set -ex \
    && curl https://pyenv.run | bash \
    && pyenv update \
    && pyenv install $PYTHON_VERSION \
    && pyenv global $PYTHON_VERSION \
    && pyenv rehash \
    && pip install --upgrade pip

# Install poetry
RUN curl -sSL https://install.python-poetry.org | python - \
    && poetry --version && poetry config virtualenvs.create false

FROM base as example  # The template that I want to provide ends here, this is just for demoing the issue
WORKDIR /app

COPY pyproject.toml .
COPY poetry.lock .
RUN poetry install --no-interaction --no-ansi

The version that doesn't work Dockerfile.plain

FROM nvidia/cuda:11.0.3-cudnn8-runtime-ubuntu20.04 as base
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHON_VERSION=3.8
ENV PATH="/root/.local/bin/:$PATH"

RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys A4B469963BF863CC \
    && apt update \
    && apt install -y git curl \
    && apt install -y --no-install-recommends make build-essential

# Don't be confused, distutils-3.9 also installs python 3.8 https://github.com/deadsnakes/issues/issues/150
 RUN apt install -y --no-install-recommends python${PYTHON_VERSION} python${PYTHON_VERSION}-dev python${PYTHON_VERSION}-distutils python${PYTHON_VERSION}-venv \
    && update-alternatives --install /usr/bin/python python /usr/bin/python${PYTHON_VERSION} 10 \
    && update-alternatives --install /usr/bin/python3 python3 /usr/bin/python${PYTHON_VERSION} 10 \
    && apt-get install -y --no-install-recommends python3-pip python3-setuptools \
    && update-alternatives --install /usr/local/bin/pip pip /usr/bin/pip 10 \
    && update-alternatives --install /usr/local/bin/pip3 pip3 /usr/bin/pip 10 \
    && apt-get clean

WORKDIR /virtualenvs
RUN curl -sSL https://install.python-poetry.org | python${PYTHON_VERSION} - \
    && poetry --version && poetry config virtualenvs.create false


FROM base as example
WORKDIR /app

COPY pyproject.toml .
COPY poetry.lock .
RUN poetry install --no-interaction --no-ansi

You can build this using

DOCKER_BUILDKIT=1 docker build -t github:example-plain --target example -f Dockerfile.plain  .

and then run using

docker run -it github:example-plain bash

Here is the issue: All the following commands are run from within the docker image. According to poetry, everything is installed:

root@5e1ffb1f971c:/app# poetry show
Skipping virtualenv creation, as specified in config file.
numpy 1.23.4 NumPy is the fundamental package for array computing with Python.
scipy 1.9.3  Fundamental algorithms for scientific computing in Python
root@5e1ffb1f971c:/app# poetry run pip --version
Skipping virtualenv creation, as specified in config file.
pip 20.0.2 from /usr/lib/python3/dist-packages/pip (python 3.8)

However using regular pip, there is nothing, and imports also fail. If I use poetry to import something, it also does not work.

root@5e1ffb1f971c:/app# pip --version
pip 20.0.2 from /usr/lib/python3/dist-packages/pip (python 3.8)
root@5e1ffb1f971c:/app# pip freeze
root@5e1ffb1f971c:/app# python -c "import scipy"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'scipy'
root@5e1ffb1f971c:/app# poetry run python -c "import scipy"
Skipping virtualenv creation, as specified in config file.
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'scipy'

What is also interesting is that if I upgrade pip with poetry it tells me it can't uninstall pip, I am assuming this is due to this ubuntu patch that tries to prevent me from breaking the system (even though I just install pip). Afterwards, the poetry pip executable also points somewhere else.

root@5e1ffb1f971c:/app# poetry run pip install --upgrade pip
Skipping virtualenv creation, as specified in config file.
Collecting pip
  Using cached pip-22.3.1-py3-none-any.whl (2.1 MB)
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 20.0.2
    Not uninstalling pip at /usr/lib/python3/dist-packages, outside environment /usr
    Can't uninstall 'pip'. No files were found to uninstall.
Successfully installed pip-22.3.1
root@5e1ffb1f971c:/app# poetry run pip --version
Skipping virtualenv creation, as specified in config file.
pip 22.3.1 from /usr/local/lib/python3.8/dist-packages/pip (python 3.8)

So how do I set this up so that I get a fresh python install of whichever version I configure, and it works with poetry? It is also required that the python and python3 aliases point to whatever poetry is using.

Reference with working version: If I do the same commands with the working version using pyenv, it looks like this:

root@c0a9af7f05b4:/app# pip freeze
numpy==1.23.4
scipy==1.9.3
root@c0a9af7f05b4:/app# poetry show
Skipping virtualenv creation, as specified in config file.
numpy 1.23.4 NumPy is the fundamental package for array computing with Python.
scipy 1.9.3  Fundamental algorithms for scientific computing in Python
root@c0a9af7f05b4:/app# poetry run pip --version
Skipping virtualenv creation, as specified in config file.
pip 22.3.1 from /root/.pyenv/versions/3.8.15/lib/python3.8/site-packages/pip (python 3.8)
root@c0a9af7f05b4:/app# pip --version
pip 22.3.1 from /root/.pyenv/versions/3.8.15/lib/python3.8/site-packages/pip (python 3.8)

RunOrVeith
  • 4,487
  • 4
  • 32
  • 50

0 Answers0