Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.venv
.env
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
.bash_history
.python_history
.cache/
.venv
.local
__pycache__
132 changes: 70 additions & 62 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,82 +1,90 @@
# PYTHON image
# Use the official Docker Python image because it has the absolute latest bugfix version of Python
# it has the absolute latest system packages
# it’s based on Debian Bookworm (Debian 12), released June 2023
# Initial Image size is 51MB
# At the end Image size is 156MB
################################################################################
# BASE #
################################################################################
FROM python:3.11-slim-bookworm AS base

# I did not recommed using an alpine image because it lacks the package installer pip and the support for installing
# wheel packages, which are both needed for installing applications like Pandas and Numpy.
ARG POETRY_VERSION=1.8.3
ARG UID=1000
ARG GID=1000

# Where python should look for packages and modules when using import
ENV PYTHONPATH="/app"

# The base layer will contain the dependencies shared by the other layers
FROM python:3.11-slim-bookworm as base
# Ensure the stdout and stderr streams are sent straight to terminal
ENV PYTHONUNBUFFERED=1

# Allowing the argumenets to be read into the dockerfile. Ex: .env > compose.yml > Dockerfile
ARG POETRY_VERSION
# true = development / false = production
ARG DEV
# Extend the socket timeout. Default would be 15s
ENV PIP_DEFAULT_TIMEOUT=100
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ENV PIP_DEFAULT_TIMEOUT=100
ENV PIP_DEFAULT_TIMEOUT=100


RUN groupadd -g ${GID} -o app
RUN useradd -m -d /app -u ${UID} -g ${GID} -o -s /bin/bash app

# RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
# vim-tiny
Comment on lines +22 to +23
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be removed? Or do we want to add a comment explaining this is how to add packages if you need them?


# Set the working directory to /app
WORKDIR /app

# Use this page as a reference for python and poetry environment variables: https://docs.python.org/3/using/cmdline.html#envvar-PYTHONUNBUFFERED
# Ensure the stdout and stderr streams are sent straight to terminal, then you can see the output of your application
ENV PYTHONUNBUFFERED=1\
# Avoid the generation of .pyc files during package install
# Disable pip's cache, then reduce the size of the image
PIP_NO_CACHE_DIR=off \
# Save runtime because it is not look for updating pip version
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
# Disable poetry interaction
POETRY_NO_INTERACTION=1 \
POETRY_VIRTUALENVS_CREATE=1 \
POETRY_VIRTUALENVS_IN_PROJECT=1 \
POETRY_CACHE_DIR=/tmp/poetry_cache
CMD ["tail", "-f", "/dev/null"]

################################################################################
# POETRY
################################################################################
#
# Both BUILD and DEVELOPMENT need poetry
#
FROM base AS poetry

RUN pip install poetry==${POETRY_VERSION}

# Install the app. Just copy the files needed to install the dependencies
COPY pyproject.toml poetry.lock README.md ./
# Ensure that the virtual environment directory is in the project. This path
# will be be `/app/.venv/`
ENV POETRY_VIRTUALENVS_IN_PROJECT=1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ENV POETRY_VIRTUALENVS_IN_PROJECT=1
ENV POETRY_VIRTUALENVS_IN_PROJECT=1


# Poetry cache is used to avoid installing the dependencies every time the code changes, we will keep this folder in development environment and remove it in production
# --no-root, poetry will install only the dependencies avoiding to install the project itself, we will install the project in the final layer
# --without dev to avoid installing dev dependencies, we do not need test and linters in production environment
# --with dev to install dev dependencies, we need test and linters in development environment
# --mount, mount a folder for plugins with poetry cache, this will speed up the process of building the image
RUN if [ {${DEV}} ]; then \
echo "Installing dev dependencies"; \
poetry install --no-root --with dev \
else \
echo "Skipping dev dependencies"; \
poetry install --no-root --without dev && rm -rf ${POETRY_CACHE_DIR}; \
fi

# Set up our final runtime layer
FROM python:3.11-slim-bookworm as runtime
# Create the virtual environment if it does not already exist
ENV POETRY_VIRTUALENVS_CREATE=1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ENV POETRY_VIRTUALENVS_CREATE=1
ENV POETRY_VIRTUALENVS_CREATE=1


ARG UID=1000
ARG GID=1000
################################################################################
# BUILD #
################################################################################
#
# This step uses poetry to generate a requirements.txt file for PRODUCTION
#
FROM poetry AS build

# Create our users here in the last layer or else it will be lost in the previous discarded layers
# Create a system group named "app_user" with the -r flag
RUN groupadd -g ${GID} -o app
RUN useradd -m -d /app -u ${UID} -g ${GID} -o -s /bin/bash app
RUN mkdir -p /venv && chown ${UID}:${GID} /venv
RUN which pip && sleep 10
# README.md is needed so that poetry command will work.
COPY pyproject.toml poetry.lock README.md ./

RUN poetry export --without dev -f requirements.txt --output requirements.txt

# By adding /venv/bin to the PATH the dependencies in the virtual environment
# are used
ENV VIRTUAL_ENV=/venv \
PATH="/venv/bin:$PATH"
################################################################################
# DEVELOPMENT #
################################################################################
#
# In development we want poetry in the container, so it inherits from the POETRY
# step. This step is the place to install development-only sytem dependencies
#
FROM poetry AS development

COPY --chown=${UID}:${GID} --from=base "/app/.venv" ${VIRTUAL_ENV}
# RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
# wget\
Comment on lines +68 to +69
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove?


# Switch to the non-root user "user"
USER app

WORKDIR /app
################################################################################
# PRODUCTION #
################################################################################
FROM base AS production

# Setting this to 'off' actually turns off the cache. This is set to decrease
# the size of the image.
ENV PIP_NO_CACHE_DIR=off
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ENV PIP_NO_CACHE_DIR=off
ENV PIP_NO_CACHE_DIR=off


# Speed up pip usage by not checking for the version
ENV PIP_DISABLE_PIP_VERSION_CHECK=on
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ENV PIP_DISABLE_PIP_VERSION_CHECK=on
ENV PIP_DISABLE_PIP_VERSION_CHECK=on


COPY --chown=${UID}:${GID} . /app
COPY --chown=${UID}:${GID} --from=build "/app/requirements.txt" /app/requirements.txt

CMD ["tail", "-f", "/dev/null"]
RUN pip install -r /app/requirements.txt

USER app
4 changes: 2 additions & 2 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ services:
app:
build:
context: .
target: runtime
target: development
dockerfile: Dockerfile
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
DEV: ${DEV:-false}
POETRY_VERSION: ${POETRY_VERSION:-1.5.1}
POETRY_VERSION: ${POETRY_VERSION:-1.8.3}
env_file:
- .env
volumes:
Expand Down
2 changes: 0 additions & 2 deletions env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
UID=YOUR_UID
GID=YOUR_GID
POETRY_VERSION=1.5.1
DEV=true
13 changes: 8 additions & 5 deletions init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ if [ -f ".env" ]; then
else
echo "🌎 .env does not exist. Copying .env-example to .env"
cp env.example .env
YOUR_UID=`id -u`
YOUR_GID=`id -g`
echo "🙂 Setting your UID ($YOUR_UID) and GID ($YOUR_UID) in .env"
docker run --rm -v ./.env:/.env alpine echo "$(sed s/YOUR_UID/$YOUR_UID/ .env)" > .env
docker run --rm -v ./.env:/.env alpine echo "$(sed s/YOUR_GID/$YOUR_GID/ .env)" > .env
YOUR_UID=$(id -u)
YOUR_GID=$(id -g)
echo "🙂 Setting your UID (${YOUR_UID}) and GID (${YOUR_UID}) in .env"
docker run --rm -v ./.env:/.env alpine echo "$(sed s/YOUR_UID/${YOUR_UID}/ .env)" >.env
docker run --rm -v ./.env:/.env alpine echo "$(sed s/YOUR_GID/${YOUR_GID}/ .env)" >.env
fi

echo "🚢 Build docker images"
docker compose build

echo "📦 Build python packages"
docker compose run --rm app poetry install
9 changes: 8 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
name = "python-starter"
version = "0.1.0"
description = "Boilerplate code for developing a python app in docker"
authors = ["Monique Rio <mrio@umich.edu>, Samuel Sciolla <ssciolla@umich.edu>, Lianet Sepulveda Torres <lisepul@umich.edu>, "]
authors = [
"Jayamala Perumal Subramani <jayamala@umich.edu>",
"Monique Rio <mrio@umich.edu>",
"Samuel Sciolla <ssciolla@umich.edu>",
"Lianet Sepulveda Torres <lisepul@umich.edu>",
"K'ron Spar <kspar@umich.edu>",
"Anthony Thomas <antmoth@umich.edu>"
]
readme = "README.md"
packages = [{include = "python_starter"}]

Expand Down