Skip to content

Commit b9eca9d

Browse files
committed
Dockerfile poetry in dev pip in production
* Changes Docker structure so that there is poetry in the development step, and pip in the production step * Cleands up the documentation in the dockerfile * Adds some directories and filenames to .gitignore and .dockerignore * init.sh has shellcheck improvements and installs python packages
1 parent a4647f6 commit b9eca9d

File tree

7 files changed

+93
-72
lines changed

7 files changed

+93
-72
lines changed

.dockerignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.venv
2+
.env

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
.bash_history
33
.python_history
44
.cache/
5+
.venv
6+
.local
7+
__pycache__

Dockerfile

Lines changed: 70 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,90 @@
1-
# PYTHON image
2-
# Use the official Docker Python image because it has the absolute latest bugfix version of Python
3-
# it has the absolute latest system packages
4-
# it’s based on Debian Bookworm (Debian 12), released June 2023
5-
# Initial Image size is 51MB
6-
# At the end Image size is 156MB
1+
################################################################################
2+
# BASE #
3+
################################################################################
4+
FROM python:3.11-slim-bookworm AS base
75

8-
# I did not recommed using an alpine image because it lacks the package installer pip and the support for installing
9-
# wheel packages, which are both needed for installing applications like Pandas and Numpy.
6+
ARG POETRY_VERSION=1.8.3
7+
ARG UID=1000
8+
ARG GID=1000
9+
10+
# Where python should look for packages and modules when using import
11+
ENV PYTHONPATH="/app"
1012

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

14-
# Allowing the argumenets to be read into the dockerfile. Ex: .env > compose.yml > Dockerfile
15-
ARG POETRY_VERSION
16-
# true = development / false = production
17-
ARG DEV
16+
# Extend the socket timeout. Default would be 15s
17+
ENV PIP_DEFAULT_TIMEOUT=100
18+
19+
RUN groupadd -g ${GID} -o app
20+
RUN useradd -m -d /app -u ${UID} -g ${GID} -o -s /bin/bash app
21+
22+
# RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
23+
# vim-tiny
1824

19-
# Set the working directory to /app
2025
WORKDIR /app
2126

22-
# Use this page as a reference for python and poetry environment variables: https://docs.python.org/3/using/cmdline.html#envvar-PYTHONUNBUFFERED
23-
# Ensure the stdout and stderr streams are sent straight to terminal, then you can see the output of your application
24-
ENV PYTHONUNBUFFERED=1\
25-
# Avoid the generation of .pyc files during package install
26-
# Disable pip's cache, then reduce the size of the image
27-
PIP_NO_CACHE_DIR=off \
28-
# Save runtime because it is not look for updating pip version
29-
PIP_DISABLE_PIP_VERSION_CHECK=on \
30-
PIP_DEFAULT_TIMEOUT=100 \
31-
# Disable poetry interaction
32-
POETRY_NO_INTERACTION=1 \
33-
POETRY_VIRTUALENVS_CREATE=1 \
34-
POETRY_VIRTUALENVS_IN_PROJECT=1 \
35-
POETRY_CACHE_DIR=/tmp/poetry_cache
27+
CMD ["tail", "-f", "/dev/null"]
28+
29+
################################################################################
30+
# POETRY
31+
################################################################################
32+
#
33+
# Both BUILD and DEVELOPMENT need poetry
34+
#
35+
FROM base AS poetry
3636

3737
RUN pip install poetry==${POETRY_VERSION}
3838

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

42-
# 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
43-
# --no-root, poetry will install only the dependencies avoiding to install the project itself, we will install the project in the final layer
44-
# --without dev to avoid installing dev dependencies, we do not need test and linters in production environment
45-
# --with dev to install dev dependencies, we need test and linters in development environment
46-
# --mount, mount a folder for plugins with poetry cache, this will speed up the process of building the image
47-
RUN if [ {${DEV}} ]; then \
48-
echo "Installing dev dependencies"; \
49-
poetry install --no-root --with dev \
50-
else \
51-
echo "Skipping dev dependencies"; \
52-
poetry install --no-root --without dev && rm -rf ${POETRY_CACHE_DIR}; \
53-
fi
54-
55-
# Set up our final runtime layer
56-
FROM python:3.11-slim-bookworm as runtime
43+
# Create the virtual environment if it does not already exist
44+
ENV POETRY_VIRTUALENVS_CREATE=1
5745

58-
ARG UID=1000
59-
ARG GID=1000
46+
################################################################################
47+
# BUILD #
48+
################################################################################
49+
#
50+
# This step uses poetry to generate a requirements.txt file for PRODUCTION
51+
#
52+
FROM poetry AS build
6053

61-
# Create our users here in the last layer or else it will be lost in the previous discarded layers
62-
# Create a system group named "app_user" with the -r flag
63-
RUN groupadd -g ${GID} -o app
64-
RUN useradd -m -d /app -u ${UID} -g ${GID} -o -s /bin/bash app
65-
RUN mkdir -p /venv && chown ${UID}:${GID} /venv
66-
RUN which pip && sleep 10
54+
# README.md is needed so that poetry command will work.
55+
COPY pyproject.toml poetry.lock README.md ./
56+
57+
RUN poetry export --without dev -f requirements.txt --output requirements.txt
6758

68-
# By adding /venv/bin to the PATH the dependencies in the virtual environment
69-
# are used
70-
ENV VIRTUAL_ENV=/venv \
71-
PATH="/venv/bin:$PATH"
59+
################################################################################
60+
# DEVELOPMENT #
61+
################################################################################
62+
#
63+
# In development we want poetry in the container, so it inherits from the POETRY
64+
# step. This step is the place to install development-only sytem dependencies
65+
#
66+
FROM poetry AS development
7267

73-
COPY --chown=${UID}:${GID} --from=base "/app/.venv" ${VIRTUAL_ENV}
68+
# RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends \
69+
# wget\
7470

75-
# Switch to the non-root user "user"
7671
USER app
7772

78-
WORKDIR /app
73+
################################################################################
74+
# PRODUCTION #
75+
################################################################################
76+
FROM base AS production
77+
78+
# Setting this to 'off' actually turns off the cache. This is set to decrease
79+
# the size of the image.
80+
ENV PIP_NO_CACHE_DIR=off
81+
82+
# Speed up pip usage by not checking for the version
83+
ENV PIP_DISABLE_PIP_VERSION_CHECK=on
7984

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

82-
CMD ["tail", "-f", "/dev/null"]
88+
RUN pip install -r /app/requirements.txt
89+
90+
USER app

compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ services:
22
app:
33
build:
44
context: .
5-
target: runtime
5+
target: development
66
dockerfile: Dockerfile
77
args:
88
UID: ${UID:-1000}
99
GID: ${GID:-1000}
1010
DEV: ${DEV:-false}
11-
POETRY_VERSION: ${POETRY_VERSION:-1.5.1}
11+
POETRY_VERSION: ${POETRY_VERSION:-1.8.3}
1212
env_file:
1313
- .env
1414
volumes:

env.example

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
11
UID=YOUR_UID
22
GID=YOUR_GID
3-
POETRY_VERSION=1.5.1
4-
DEV=true

init.sh

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ if [ -f ".env" ]; then
55
else
66
echo "🌎 .env does not exist. Copying .env-example to .env"
77
cp env.example .env
8-
YOUR_UID=`id -u`
9-
YOUR_GID=`id -g`
10-
echo "🙂 Setting your UID ($YOUR_UID) and GID ($YOUR_UID) in .env"
11-
docker run --rm -v ./.env:/.env alpine echo "$(sed s/YOUR_UID/$YOUR_UID/ .env)" > .env
12-
docker run --rm -v ./.env:/.env alpine echo "$(sed s/YOUR_GID/$YOUR_GID/ .env)" > .env
8+
YOUR_UID=$(id -u)
9+
YOUR_GID=$(id -g)
10+
echo "🙂 Setting your UID (${YOUR_UID}) and GID (${YOUR_UID}) in .env"
11+
docker run --rm -v ./.env:/.env alpine echo "$(sed s/YOUR_UID/${YOUR_UID}/ .env)" >.env
12+
docker run --rm -v ./.env:/.env alpine echo "$(sed s/YOUR_GID/${YOUR_GID}/ .env)" >.env
1313
fi
1414

1515
echo "🚢 Build docker images"
1616
docker compose build
17+
18+
echo "📦 Build python packages"
19+
docker compose run --rm app poetry install

pyproject.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22
name = "python-starter"
33
version = "0.1.0"
44
description = "Boilerplate code for developing a python app in docker"
5-
authors = ["Monique Rio <mrio@umich.edu>, Samuel Sciolla <ssciolla@umich.edu>, Lianet Sepulveda Torres <lisepul@umich.edu>, "]
5+
authors = [
6+
"Jayamala Perumal Subramani <jayamala@umich.edu>",
7+
"Monique Rio <mrio@umich.edu>",
8+
"Samuel Sciolla <ssciolla@umich.edu>",
9+
"Lianet Sepulveda Torres <lisepul@umich.edu>",
10+
"K'ron Spar <kspar@umich.edu>",
11+
"Anthony Thomas <antmoth@umich.edu>"
12+
]
613
readme = "README.md"
714
packages = [{include = "python_starter"}]
815

0 commit comments

Comments
 (0)