Skip to content

Commit

Permalink
feat(docker): Cut docker image size down to a half
Browse files Browse the repository at this point in the history
Using a couple best practices for saving space and build cache optimizations to get better build times and much smaller final image.

Notably:
- Python packages are now kept in a virtual environment, which is fully prepared in the builder stage, later simply copied to the same path of the final image
- Any python cache .pyc files are not part of the final image
- Git binary needed to automatically determine the package version is not part of the final image
- Many auxiliary project source files (incl. the local .git dir(!)) are also omitted from the final image
- Use RUN --mount instead of COPY where the files are needed only for the command
- Keep various COPY operations to the end of a stage not to invalidate semantically unrelated cached layers
- Remove deprecated (and misplaced) MAINTAINER directive in favor of a particular "authors" LABEL
  • Loading branch information
vit-zikmund committed Jan 2, 2025
1 parent 02e41c0 commit 6d70618
Showing 1 changed file with 89 additions and 47 deletions.
136 changes: 89 additions & 47 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,66 +1,108 @@
# Dockerfile for uWSGI wrapped Giftless Git LFS Server
# Shared build ARGs among stages
ARG WORKDIR=/app
ARG VENV="$WORKDIR/.venv"

### --- Build Depdendencies ---
FROM python:3.12 AS builder
ARG UWSGI_VERSION=2.0.23
# Common WSGI middleware modules to be pip-installed
# These are not required in every Giftless installation but are common enough
ARG EXTRA_PACKAGES="wsgi_cors_middleware"
# expose shared ARGs
ARG WORKDIR
ARG VENV

FROM python:3.12 as builder
MAINTAINER "Shahar Evron <[email protected]>"
# Set WORKDIR (also creates the dir)
WORKDIR $WORKDIR

# Build wheels for uWSGI and all requirements
RUN DEBIAN_FRONTEND=noninteractive apt-get update \
&& apt-get install -y build-essential libpcre3 libpcre3-dev git
RUN pip install -U pip
RUN mkdir /wheels

ARG UWSGI_VERSION=2.0.23
RUN pip wheel -w /wheels uwsgi==$UWSGI_VERSION
RUN set -eux ;\
export DEBIAN_FRONTEND=noninteractive ;\
apt-get update ;\
apt-get install -y --no-install-recommends build-essential libpcre3 libpcre3-dev git ;\
rm -rf /var/lib/apt/lists/*

# Create virtual env to store dependencies, "activate" it
RUN python -m venv --upgrade-deps "$VENV"
ENV VIRTUAL_ENV="$VENV" PATH="$VENV/bin:$PATH"

# Set a couple pip-related settings
# Wait a bit longer for slow connections
ENV PIP_TIMEOUT=100
# Don't nag about newer pip
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
# Don't cache pip packages
ENV PIP_NO_CACHE_DIR=1
# Require activated virtual environment
ENV PIP_REQUIRE_VIRTUALENV=1
# Eventual python cache files go here (not to be copied)
ENV PYTHONPYCACHEPREFIX=/tmp/__pycache__

# Install runtime dependencies
RUN --mount=source=requirements/main.txt,target=requirements/main.txt \
pip install -r requirements/main.txt
RUN pip install uwsgi==$UWSGI_VERSION
# Install extra packages into the virtual env
RUN pip install ${EXTRA_PACKAGES}

COPY requirements/main.txt /requirements.txt
RUN pip wheel -w /wheels -r /requirements.txt
# Copy project contents necessary for an editable install
COPY .git .git/
COPY giftless giftless/
COPY pyproject.toml .
# Editable-install the giftless package (add a kind of a project path reference in site-packages)
# To detect the package version dynamically, setuptools-scm needs the git binary
RUN pip install -e .

### --- Build Final Image ---

FROM python:3.12-slim

RUN DEBIAN_FRONTEND=noninteractive apt-get update \
&& apt-get install -y libpcre3 libxml2 tini git \
&& apt-get clean \
&& apt -y autoremove

RUN mkdir /app

# Install dependencies
COPY --from=builder /wheels /wheels
RUN pip install /wheels/*.whl

# Copy project code
COPY . /app
RUN pip install -e /app
FROM python:3.12-slim AS final
LABEL org.opencontainers.image.authors="Shahar Evron <[email protected]>"

ARG USER_NAME=giftless
# Writable path for local LFS storage
ARG STORAGE_DIR=/lfs-storage
ENV GIFTLESS_TRANSFER_ADAPTERS_basic_options_storage_options_path $STORAGE_DIR

RUN useradd -d /app $USER_NAME
RUN mkdir $STORAGE_DIR
RUN chown $USER_NAME $STORAGE_DIR

# Pip-install some common WSGI middleware modules
# These are not required in every Giftless installation but are common enough
ARG EXTRA_PACKAGES="wsgi_cors_middleware"
RUN pip install ${EXTRA_PACKAGES}

WORKDIR /app

ENV UWSGI_MODULE "giftless.wsgi_entrypoint"

# Set to true to add a runtime dockerhub deprecation warning
ARG IS_DOCKERHUB
# Override default docker entrypoint for dockerhub
RUN --mount=target=/build-ctx set -e ;\
if [ "$IS_DOCKERHUB" = true ]; then \
cp /build-ctx/scripts/docker-entrypoint-dockerhub.sh scripts/docker-entrypoint.sh ;\
# expose shared ARGs
ARG WORKDIR
ARG VENV

# Set WORKDIR (also creates the dir)
WORKDIR $WORKDIR

# Create a user and set local storage write permissions
RUN set -eux ;\
useradd -d "$WORKDIR" "$USER_NAME" ;\
mkdir "$STORAGE_DIR" ;\
chown "$USER_NAME" "$STORAGE_DIR"

# Install runtime dependencies
RUN set -eux ;\
export DEBIAN_FRONTEND=noninteractive ;\
apt-get update ;\
apt-get install -y libpcre3 libxml2 tini ;\
rm -rf /var/lib/apt/lists/*

# Use the virtual env with dependencies from builder stage
COPY --from=builder "$VENV" "$VENV"
ENV VIRTUAL_ENV="$VENV" PATH="$VENV/bin:$PATH"
# Copy project source back into the same path referenced by the editable install
COPY --from=builder "$WORKDIR/giftless" "giftless"

# Copy desired docker-entrypoint
RUN --mount=target=/build-ctx set -eux ;\
target_de=scripts/docker-entrypoint.sh ;\
mkdir -p "$(dirname "$target_de")" ;\
if [ "${IS_DOCKERHUB:-}" = true ]; then \
cp /build-ctx/scripts/docker-entrypoint-dockerhub.sh "$target_de" ;\
else \
cp /build-ctx/scripts/docker-entrypoint.sh "$target_de" ;\
fi

# Set runtime properties
USER $USER_NAME
ENV GIFTLESS_TRANSFER_ADAPTERS_basic_options_storage_options_path="$STORAGE_DIR"
ENV UWSGI_MODULE="giftless.wsgi_entrypoint"

ENTRYPOINT ["tini", "--", "scripts/docker-entrypoint.sh"]
CMD ["uwsgi", "-s", "127.0.0.1:5000", "-M", "-T", "--threads", "2", "-p", "2", \
Expand Down

0 comments on commit 6d70618

Please sign in to comment.