Skip to content

Commit 13930a2

Browse files
committed
Updates to enable multi-version builds
1 parent ce7c6ec commit 13930a2

File tree

4 files changed

+121
-14
lines changed

4 files changed

+121
-14
lines changed

.dockerignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.git
2+
.github
3+
*.md
4+
LICENSE

.github/workflows/build-and-push.yml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@ jobs:
1111
permissions:
1212
contents: read
1313
packages: write
14+
strategy:
15+
matrix:
16+
include:
17+
- python_version: "3.9"
18+
debian_version: "bullseye"
19+
- python_version: "3.10"
20+
debian_version: "bullseye"
21+
- python_version: "3.11"
22+
debian_version: "bookworm"
23+
- python_version: "3.12"
24+
debian_version: "bookworm"
25+
- python_version: "3.13"
26+
debian_version: "bookworm"
27+
- python_version: "3.14"
28+
debian_version: "bookworm"
1429
steps:
1530
- name: Checkout repository
1631
uses: actions/checkout@v4
@@ -37,6 +52,11 @@ jobs:
3752
file: Dockerfile
3853
platforms: linux/amd64,linux/arm64
3954
push: true
40-
tags: ghcr.io/${{ github.repository_owner }}/python-container-builder:latest
55+
build-args: |
56+
DEBIAN_VERSION=${{ matrix.debian_version }}
57+
PYTHON_VERSION=${{ matrix.python_version }}
58+
tags: |
59+
ghcr.io/${{ github.repository_owner }}/python-container-builder:${{ matrix.python_version }}
60+
${{ matrix.python_version == '3.14' && format('ghcr.io/{0}/python-container-builder:latest', github.repository_owner) || '' }}
4161
provenance: false
4262
outputs: type=image,name=python-container-builder,annotation-index.org.opencontainers.image.description=build your Python distroless containers with this

Dockerfile

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,39 @@
11
# Based on: https://github.com/GoogleContainerTools/distroless/blob/main/examples/python3-requirements/Dockerfile
2-
# Bugfix for apt-get update errors: https://stackoverflow.com/questions/63526272/release-file-is-not-valid-yet-docker
32
# Installing uv: https://docs.astral.sh/uv/guides/integration/docker/#installing-uv
4-
FROM debian:bookworm-slim
3+
ARG PYTHON_VERSION=3.14
4+
ARG DEBIAN_VERSION=bookworm
5+
6+
# Extract Python from official image
7+
FROM python:${PYTHON_VERSION}-slim-${DEBIAN_VERSION} AS python-source
8+
9+
# Final stage - clean Debian base with Python copied in
10+
FROM debian:${DEBIAN_VERSION}-slim
11+
ARG PYTHON_VERSION
12+
513
LABEL MAINTAINER="jskii <blackdanieljames@gmail.com>"
6-
RUN echo "Acquire::Check-Valid-Until \"false\";\nAcquire::Check-Date \"false\";" | cat > /etc/apt/apt.conf.d/10no--check-valid-until
7-
RUN apt-get update && \
8-
apt-get install --no-install-suggests --no-install-recommends --yes python3-venv libpython3-dev python3-pip
14+
LABEL python_version="${PYTHON_VERSION}"
15+
16+
# Install minimal runtime dependencies
17+
# Add any additional packages you need here in the future
18+
RUN apt-get update && apt-get install -y --no-install-recommends \
19+
ca-certificates \
20+
&& rm -rf /var/lib/apt/lists/*
21+
22+
# Copy Python installation from official image
23+
COPY --from=python-source /usr/local /usr/local
24+
25+
# Copy shared libraries needed by Python
26+
COPY --from=python-source /usr/lib /usr/lib
27+
COPY --from=python-source /lib /lib
28+
29+
# Update library cache
30+
RUN ldconfig
31+
32+
# Copy uv for fast package installation
933
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
34+
35+
# Create virtual environment using uv (faster than python -m venv)
1036
RUN uv venv
37+
1138
ENV VIRTUAL_ENV=/.venv
1239
ENV PATH="/bin:$VIRTUAL_ENV/bin:$PATH"

README.md

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,48 @@
33

44
A shortcut to packaging your Python code with requirement dependencies into a Distroless image.
55

6+
## Supported Python Versions
7+
8+
This project provides pre-built images for multiple Python versions, using a hybrid approach that extracts Python from official images and installs it on a clean, customizable Debian base:
9+
10+
| Python Version | Image Tag | Python Source | Debian Base | Distroless Runtime |
11+
|----------------|-----------|---------------|-------------|-------------------|
12+
| 3.9 | `:3.9` | `python:3.9-slim-bullseye` | `debian:bullseye-slim` | `gcr.io/distroless/python3-debian11` |
13+
| 3.10 | `:3.10` | `python:3.10-slim-bullseye` | `debian:bullseye-slim` | `gcr.io/distroless/python3-debian11` |
14+
| 3.11 | `:3.11` | `python:3.11-slim-bookworm` | `debian:bookworm-slim` | `gcr.io/distroless/python3-debian12` |
15+
| 3.12 | `:3.12` | `python:3.12-slim-bookworm` | `debian:bookworm-slim` | `gcr.io/distroless/python3-debian12` |
16+
| 3.13 | `:3.13` | `python:3.13-slim-bookworm` | `debian:bookworm-slim` | `gcr.io/distroless/python3-debian12` |
17+
| 3.14 | `:3.14` or `:latest` | `python:3.14-slim-bookworm` | `debian:bookworm-slim` | `gcr.io/distroless/python3-debian12` |
18+
19+
All images support both `linux/amd64` and `linux/arm64` architectures.
20+
21+
### Build Approach
22+
23+
These images use a **hybrid multi-stage build**:
24+
1. Extract Python from official `python:X.Y-slim-debian` images (ensures reliability and latest patches)
25+
2. Copy Python into a clean `debian:X-slim` base (full control over dependencies)
26+
3. Add `uv` for fast package installation
27+
4. Pre-create a virtual environment at `/.venv`
28+
29+
This approach gives you the reliability of official Python builds while maintaining full control over the base system and dependencies.
30+
631
## Goals
732
This project seeks to:
833
- Simplify the build/packaging process for simple Python projects.
934
- Reduce usage of Github Actions free tier minutes for said projects by doing the most time-intensive part up front here instead.
10-
- Offer an base image that supports packaging into a final distroless runtime.
11-
- Keep up to date with package updates to the Debian-based build image without having to think about it.
12-
- Support both `linux/arm64` and `linux/amd64` build options.
35+
- Offer a base image that supports packaging into a final distroless runtime.
36+
- Provide a clean, customizable Debian base with reliable Python builds.
37+
- Keep up to date with package updates automatically via nightly builds.
38+
- Support both `linux/arm64` and `linux/amd64` architectures.
1339
- Be publicly available for use without needing to login to a registry.
14-
- Include `uv` as I like it in my Python toolchain.
40+
- Include `uv` for fast, modern Python package management.
1541

1642
## Getting Started
1743
### Quickstart Example
1844
> I have a standalone Python file, `main.py`, in the root folder of my repo requiring dependencies that are declared in `requirements.txt`.
19-
```
45+
46+
**Using Python 3.14 (latest):**
47+
```dockerfile
2048
FROM ghcr.io/jski/python-container-builder:latest as build-venv
2149
COPY requirements.txt /requirements.txt
2250
RUN uv pip install -r /requirements.txt
@@ -28,10 +56,38 @@ WORKDIR /app
2856
ENTRYPOINT ["/.venv/bin/python3", "-u", "main.py"]
2957
```
3058

59+
**Using Python 3.12 (stable):**
60+
```dockerfile
61+
FROM ghcr.io/jski/python-container-builder:3.12 as build-venv
62+
COPY requirements.txt /requirements.txt
63+
RUN uv pip install -r /requirements.txt
64+
65+
FROM gcr.io/distroless/python3-debian12
66+
COPY --from=build-venv /.venv /.venv
67+
COPY /main.py /app/main.py
68+
WORKDIR /app
69+
ENTRYPOINT ["/.venv/bin/python3", "-u", "main.py"]
70+
```
71+
72+
**Using Python 3.10 (for older projects):**
73+
```dockerfile
74+
FROM ghcr.io/jski/python-container-builder:3.10 as build-venv
75+
COPY requirements.txt /requirements.txt
76+
RUN uv pip install -r /requirements.txt
77+
78+
FROM gcr.io/distroless/python3-debian11
79+
COPY --from=build-venv /.venv /.venv
80+
COPY /main.py /app/main.py
81+
WORKDIR /app
82+
ENTRYPOINT ["/.venv/bin/python3", "-u", "main.py"]
83+
```
84+
85+
> **Note**: When using Python 3.9 or 3.10, make sure to use `gcr.io/distroless/python3-debian11` as your runtime image. For Python 3.11 and above, use `gcr.io/distroless/python3-debian12`.
86+
3187
### Usage/Explanation
32-
1. Declare the base image as the top FROM line in your Dockerfile.
33-
2. Copy your requirements or configuration files from your application repo, and run pip install from a virtualenv.
34-
3. Declare the final distroless container image you'll use for runtime.
88+
1. Choose your Python version and declare the corresponding base image as the top FROM line in your Dockerfile (e.g., `:3.12`, `:3.14`, or `:latest`).
89+
2. Copy your requirements or configuration files from your application repo, and run `uv pip install` (or `pip install`) from a virtualenv.
90+
3. Declare the final distroless container image you'll use for runtime, matching the Debian version to your Python version (see table above).
3591
4. Copy the virtualenv you built in the first phase of the build.
3692
5. Move your application files to the proper location on the filesystem, and setup your workdir and entrypoint. All done!
3793

0 commit comments

Comments
 (0)