diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d8ba132..3208947 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -306,8 +306,6 @@ jobs: id: docker_build uses: docker/build-push-action@v5 with: - build-args: | - VERSION=${{ needs.prepare.outputs.source_version }} cache-from: type=local,src=${{ env.BUILDX_CACHE_DIR }} cache-to: type=local,dest=${{ env.BUILDX_CACHE_DIR }} context: . @@ -459,8 +457,6 @@ jobs: id: docker_build uses: docker/build-push-action@v5 with: - build-args: | - VERSION=${{ needs.prepare.outputs.source_version }} cache-from: type=local,src=${{ env.BUILDX_CACHE_DIR }} cache-to: type=local,dest=${{ env.BUILDX_CACHE_DIR }} context: . diff --git a/Dockerfile b/Dockerfile index 1aae8db..6a00b36 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,59 @@ -ARG VERSION=unspecified - # Official Docker images are in the form library/ while non-official # images are in the form /. -FROM docker.io/library/python:3.12.0-alpine3.18 +FROM docker.io/library/python:3.12.0-alpine3.18 as compile-stage + +### +# Unprivileged user variables +### +ARG CISA_USER="cisa" +ENV CISA_HOME="/home/${CISA_USER}" +ENV VIRTUAL_ENV="${CISA_HOME}/.venv" + +# Versions of the Python packages installed directly +ENV PYTHON_PIP_VERSION=24.0 +ENV PYTHON_PIPENV_VERSION=2023.12.1 +ENV PYTHON_SETUPTOOLS_VERSION=69.1.0 +ENV PYTHON_WHEEL_VERSION=0.42.0 + +### +# Install the specified versions of pip, setuptools, and wheel into the system +# Python environment; install the specified version of pipenv into the system Python +# environment; set up a Python virtual environment (venv); and install the specified +# versions of pip, setuptools, and wheel into the venv. +# +# Note that we use the --no-cache-dir flag to avoid writing to a local +# cache. This results in a smaller final image, at the cost of +# slightly longer install times. +### +RUN python3 -m pip install --no-cache-dir --upgrade \ + pip==${PYTHON_PIP_VERSION} \ + setuptools==${PYTHON_SETUPTOOLS_VERSION} \ + wheel==${PYTHON_WHEEL_VERSION} \ + && python3 -m pip install --no-cache-dir --upgrade \ + pipenv==${PYTHON_PIPENV_VERSION} \ + # Manually create the virtual environment + && python3 -m venv ${VIRTUAL_ENV} \ + # Ensure the core Python packages are installed in the virtual environment + && ${VIRTUAL_ENV}/bin/python3 -m pip install --no-cache-dir --upgrade \ + pip==${PYTHON_PIP_VERSION} \ + setuptools==${PYTHON_SETUPTOOLS_VERSION} \ + wheel==${PYTHON_WHEEL_VERSION} + +### +# Check the Pipfile configuration and then install the Python dependencies into +# the virtual environment. +# +# Note that pipenv will install into a virtual environment if the VIRTUAL_ENV +# environment variable is set. +### +WORKDIR /tmp +COPY src/Pipfile src/Pipfile.lock ./ +RUN pipenv check --verbose \ + && pipenv install --clear --deploy --extra-pip-args "--no-cache-dir" --verbose -ARG VERSION +# Official Docker images are in the form library/ while non-official +# images are in the form /. +FROM docker.io/library/python:3.12.0-alpine3.18 as build-stage ### # For a list of pre-defined annotation keys and value types see: @@ -31,11 +80,6 @@ ENV CISA_GROUP=${CISA_USER} ENV CISA_HOME="/home/${CISA_USER}" ENV VIRTUAL_ENV="${CISA_HOME}/.venv" -# Versions of the Python packages installed directly -ENV PYTHON_PIP_VERSION=24.0 -ENV PYTHON_SETUPTOOLS_VERSION=69.1.0 -ENV PYTHON_WHEEL_VERSION=0.42.0 - ### # Create unprivileged user ### @@ -43,31 +87,15 @@ RUN addgroup --system --gid ${CISA_GID} ${CISA_GROUP} \ && adduser --system --uid ${CISA_UID} --ingroup ${CISA_GROUP} ${CISA_USER} ### -# Set up a Python virtual environment (venv); install the specified versions of pip, -# setuptools, and wheel into it; and then install the Python dependencies for -# the application. -# -# Note that we use the --no-cache-dir flag to avoid writing to a local -# cache. This results in a smaller final image, at the cost of -# slightly longer install times. -### -RUN python3 -m venv ${VIRTUAL_ENV} \ - && ${VIRTUAL_ENV}/bin/python3 -m pip install --no-cache-dir --upgrade \ - pip==${PYTHON_PIP_VERSION} \ - setuptools==${PYTHON_SETUPTOOLS_VERSION} \ - wheel==${PYTHON_WHEEL_VERSION} \ - && ${VIRTUAL_ENV}/bin/python3 -m pip install --no-cache-dir --upgrade \ - https://github.com/cisagov/skeleton-python-library/archive/v${VERSION}.tar.gz - -### -# Sym-link the Python binary in the venv to the system-wide Python and add the venv to -# the PATH. +# Copy in the Python virtual environment created in compile-stage, Sym-link the +# Python binary in the venv to the system-wide Python and add the venv to the PATH. # # Note that we sym-link the Python binary in the venv to the system-wide Python so that # any calls to `python3` will use our virtual environment. We are using short flags # because the ln binary in Alpine Linux does not support long flags. The -f instructs # ln to remove the existing file and the -s instructs ln to create a symbolic link. ### +COPY --from=compile-stage --chown=${CISA_USER}:${CISA_GROUP} ${VIRTUAL_ENV} ${VIRTUAL_ENV} RUN ln -fs "$(command -v python3)" "${VIRTUAL_ENV}"/bin/python3 ENV PATH="${VIRTUAL_ENV}/bin:$PATH" diff --git a/README.md b/README.md index 57f8c30..8d926e4 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,6 @@ Build the image locally using this git repository as the [build context](https:/ ```console docker build \ - --build-arg VERSION=0.0.1 \ --tag cisagov/example:0.0.1 \ https://github.com/cisagov/example.git#develop ``` @@ -227,7 +226,6 @@ Docker: docker buildx build \ --file Dockerfile-x \ --platform linux/amd64 \ - --build-arg VERSION=0.0.1 \ --output type=docker \ --tag cisagov/example:0.0.1 . ``` diff --git a/requirements-dev.txt b/requirements-dev.txt index cb51627..bdc1615 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,3 +1,4 @@ --requirement requirements-test.txt ipython +pipenv semver diff --git a/src/Pipfile b/src/Pipfile new file mode 100644 index 0000000..56f2fc9 --- /dev/null +++ b/src/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +# List any Python dependencies for the image here +[packages] +# This should match the version of the image +example = {file = "https://github.com/cisagov/skeleton-python-library/archive/v0.0.1.tar.gz"} + +# This version should match the version of Python in the image +[requires] +python_full_version = "3.12.0" diff --git a/src/Pipfile.lock b/src/Pipfile.lock new file mode 100644 index 0000000..d39d053 --- /dev/null +++ b/src/Pipfile.lock @@ -0,0 +1,38 @@ +{ + "_meta": { + "hash": { + "sha256": "654452851fea1eb2c8811649e5efe8873c8ff51f5c14dd27a4a8ebb5b15a27c4" + }, + "pipfile-spec": 6, + "requires": { + "python_full_version": "3.12.0" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "docopt": { + "hashes": [ + "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" + ], + "version": "==0.6.2" + }, + "example": { + "file": "https://github.com/cisagov/skeleton-python-library/archive/v0.0.1.tar.gz" + }, + "setuptools": { + "hashes": [ + "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56", + "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8" + ], + "markers": "python_version >= '3.8'", + "version": "==69.1.1" + } + }, + "develop": {} +}