From f3f75e63db3a4f2926616539922551c98fbe7dd1 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Wed, 3 Sep 2025 11:39:45 +0300 Subject: [PATCH 1/5] docs: add mit license --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1c69ef2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 LOGIC Private Company + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From 0a6a48240b815a94a01fc7e17a26b3acf481f75d Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Wed, 3 Sep 2025 11:40:09 +0300 Subject: [PATCH 2/5] chore(uv): bump uv to `0.18.4` --- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 2 +- Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a790bd6..a75d872 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: pull_request: env: - UV_VERSION: 0.8.12 + UV_VERSION: 0.8.14 GHCR_IMAGE_REPOSITORY: ghcr.io/${{ github.repository }} PLATFORMS: linux/amd64,linux/arm64/v8 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 37cf284..ac44413 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,7 +5,7 @@ on: types: [published] env: - UV_VERSION: 0.8.12 + UV_VERSION: 0.8.14 GHCR_IMAGE_REPOSITORY: ghcr.io/${{ github.repository }} PLATFORMS: linux/amd64,linux/arm64/v8 diff --git a/Dockerfile b/Dockerfile index 909a9bf..0ad8175 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ARG PYTHON_VERSION=3.13 ARG VARIANT=bookworm -ARG UV_VERSION=0.8.12 +ARG UV_VERSION=0.8.14 FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv From f762ca49b75daf8201857ec931a416200bd1ebf3 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Wed, 3 Sep 2025 12:01:43 +0300 Subject: [PATCH 3/5] fix(ci): correct environment variable controlling uv version --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a75d872..d063906 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,6 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max build-args: | - POETRY_VERSION=${{ env.UV_VERSION }} + UV_VERSION=${{ env.UV_VERSION }} PYTHON_VERSION=${{ matrix.python }} VARIANT=${{ matrix.variant }} From 1ad602160862cc12b369d76c40b5994a62bb56ed Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Wed, 3 Sep 2025 13:00:35 +0300 Subject: [PATCH 4/5] feat: prepare for publishing --- .github/workflows/ci.yml | 2 - .github/workflows/release.yml | 44 ++++------ Dockerfile | 10 --- README.md | 147 +++++++++++++++++++++++++++++++++- 4 files changed, 163 insertions(+), 40 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d063906..8b95d5c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,9 +23,7 @@ jobs: - "3.13" variant: - bookworm - - slim-bookworm - trixie - - slim-trixie steps: - uses: actions/checkout@v5.0.0 - uses: docker/login-action@v3.5.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ac44413..f0f2063 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,14 +21,14 @@ jobs: - "3.13" variant: - bookworm - - slim-bookworm - trixie - - slim-trixie include: - python: "3.13" is_default_python: true - variant: trixie is_default_variant: true + env: + GIT_SHA_TAG: ${{ env.GHCR_IMAGE_REPOSITORY }}:${{ github.sha }}-${{ matrix.python }}-${{ matrix.variant }} steps: - uses: actions/checkout@v4.1.4 - uses: docker/login-action@v3.1.0 @@ -36,28 +36,18 @@ jobs: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Set image tags in env - run: | - TAG_SUFFIX="${{ matrix.python }}-${{ matrix.variant }}" - echo "GIT_SHA_TAG=${{ env.GHCR_IMAGE_REPOSITORY }}:${{ github.sha }}-${TAG_SUFFIX}" >> $GITHUB_ENV - echo "BASE_RELEASE_TAG=${{ env.GHCR_IMAGE_REPOSITORY }}:${{ env.UV_VERSION }}" >> $GITHUB_ENV - - name: "Python + Variant: ${{ env.UV_VERSION }}-python-${{ matrix.python }}-${{ matrix.variant }}" - run: | - RELEASE_TAG="${BASE_RELEASE_TAG}-python-${{ matrix.python }}-${{ matrix.variant }}" - docker buildx imagetools create --tag $RELEASE_TAG $GIT_SHA_TAG - - name: "Python + Default Variant: ${{ env.UV_VERSION }}-python-${{ matrix.python }}" - if: matrix.is_default_variant - run: | - RELEASE_TAG="${BASE_RELEASE_TAG}-python-${{ matrix.python }}" - docker buildx imagetools create --tag $RELEASE_TAG $GIT_SHA_TAG - - name: "Default Python + Variant: ${{ env.UV_VERSION }}-${{ matrix.variant }}" - if: matrix.is_default_python - run: | - RELEASE_TAG="${BASE_RELEASE_TAG}-${{ matrix.variant }}" - docker buildx imagetools create --tag $RELEASE_TAG $GIT_SHA_TAG - - name: "Default Python + Default Variant: ${{ env.UV_VERSION }}" - if: matrix.is_default_python && matrix.is_default_variant - run: docker buildx imagetools create --tag $BASE_RELEASE_TAG $GIT_SHA_TAG - - name: "Default Python + Default Variant: latest" - if: matrix.is_default_python && matrix.is_default_variant - run: docker buildx imagetools create --tag $GHCR_IMAGE_REPOSITORY:latest $GIT_SHA_TAG + + - name: tag ${{ matrix.python }}-${{ matrix.variant }} + run: docker buildx imagetools create --tag ${{ env.GHCR_IMAGE_REPOSITORY }}:${{ matrix.python }}-${{ matrix.variant }} $GIT_SHA_TAG + + - if: matrix.is_default_variant + name: tag for default variant (${{ matrix.python }}) + run: docker buildx imagetools create --tag ${{ env.GHCR_IMAGE_REPOSITORY }}:${{ matrix.python }} $GIT_SHA_TAG + + - if: matrix.is_default_python + name: tag for default python (${{ matrix.variant }}) + run: docker buildx imagetools create --tag ${{ env.GHCR_IMAGE_REPOSITORY }}:${{ matrix.variant }} $GIT_SHA_TAG + + - if: matrix.is_default_python && matrix.is_default_variant + name: tag for default python and variant (latest) + run: docker buildx imagetools create --tag ${{ env.GHCR_IMAGE_REPOSITORY }}:latest $GIT_SHA_TAG diff --git a/Dockerfile b/Dockerfile index 0ad8175..3c38a91 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,13 +28,3 @@ RUN mkdir -p ${UV_PROJECT_ENVIRONMENT} VOLUME [ ${UV_PROJECT_ENVIRONMENT} ] WORKDIR /usr/src/app - -FROM base AS onbuild - -ONBUILD RUN --mount=type=cache,target=/root/.cache/uv \ - --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ - --mount=type=bind,source=uv.lock,target=uv.lock \ - uv sync -ONBUILD COPY ./ ./ - -FROM base diff --git a/README.md b/README.md index f9cfefd..8f32d0d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,152 @@ # Python with LOGIC -TBD +An opinionated base Docker image used when doing [Python with LOGIC](https://withlogic.co/ref/python). Optimized for development, CI builds and production deployments. + +![uv](https://img.shields.io/badge/uv-0.8.14-lime) ![python](https://img.shields.io/badge/Python-3.13%20(default)%2C3.12%2C3.11%2C3.10-blue) ![variants](https://img.shields.io/badge/Variant-trixie%20(default)%2C%20bookworm-purple?label=Variants) + +> [!TIP] +> +> Need help with a Python project in your organizations? You are at the right place. We have been working with production Python deployments for years and we would love to help. Let's get in touch at [https://withlogic.co](https://withlogic.co/ref/python). + +## Why + +We built and published this opinionated Docker image, based on our workflow when doing Python with LOGIC. We prioritise DRY, considerate defaults and optimizing for speed and convenience across all steps in our workflow, from development to CI and deployments; preview or production. In particular this means: + +- Python and virtual environments optimized for Docker deployments +- Optimized dependency management with uv +- Preconfigured volumes for development with Docker + +## Usage + +The simplest way to get started with this image is to use the `latest` tag and copy your source code in the current working directory: + +```dockerfile +FROM ghcr.io/withlogicco/python + +COPY ./ ./ +``` + +For advanced usage scenarios, including using uv with efficient Docker image caching take a look + +## Tags + +The `latest` tag ships with the most recent uv and Python versions on Debian Trixie: + +``` +ghcr.io/withlogicco/python +``` + +There are tags available to choose a specific supported Python versions and image variants: + +- Python version: `ghcr.io/withlogicco/python:{python_version}` +- Image variant: `ghcr.io/withlogicco/python:{image_variant}` +- Python version and image variant: `ghcr.io/withlogicco/python:{python_version}-{image_variant}` + +### Examples + +- Python 3.13 on Trixie: `ghcr.io/withlogicco/python` +- Poetry 3.13 on Bookworm: `ghcr.io/withlogicco/python:bookworm` +- Poetry 3.12 on Trixie: `ghcr.io/withlogicco/python:3.12` +- Poetry 3.12 on Bookworm: `ghcr.io/withlogicco/python:3.12-bookworm` + +## Advanced usage + +### Start a new project with uv + +To start a new Python project with uv, mount your current working directory in `/usr/src/app` and just run `uv init`: + +```console +docker run -ti -v $PWD:/usr/src/app ghcr.io/withlogicco/python uv init +``` + +### Dependencies with uv + +To manage your dependencies with uv, it's suggested to just copy your `pyproject.toml` and `uv.lock` files in your Docker image first for optimized Docker build layer caching (`uv sync` will run only when your dependencies change): + +```dockerfile +FROM ghcr.io/withlogicco/python + +COPY pyproject.toml uv.lock ./ +RUN uv sync --no-install-project + +COPY . . +``` + +> [!TIP] +> +> Prefer to use `--no-install-project` with `uv sync`, to only install dependencies and not the current project, since the code is not available yet in that particular build step. + +### Optimize builds with cache mounts + +You can further optimize your Docker builds by taking advantage of Docker builder cache mounts. This means Docker can cache the `/root/.cache/uv` directory across builds, so that even when dependencies change and `uv sync` needs to run again, only the new dependencies will need to be downloaded from PyPI: + +```dockerfile +FROM ghcr.io/withlogicco/python + +COPY pyproject.toml uv.lock ./ +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --no-install-project +``` + +> [!IMPORTANT] +> +> Docker build cache mounts will **NOT** work on GitHub Actions, as they are not part of Docker image cache, but the builder daemon's. To get this feature working you will need to run your Docker builds on a host managed by you, with GitHub Actions self-hosted runners. + +### Reduce layers with build bind mounts + +You can reduce layers of built Docker images, by mounting `pyproject.toml` and `uv.lock` in the Docker image just in time for `uv sync`, instead of copying them in an additional layer above: + +```dockerfile +FROM ghcr.io/withlogicco/python + +RUN --mount=type=cache,target=/root/.cache/uv \ + --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ + --mount=type=bind,source=uv.lock,target=uv.lock \ + uv sync --no-install-project +``` + +### Persist new dependencies without rebuilding + +When working on an actively developed project, new dependencies can be added as the project moves forward. To avoid requiring rebuilding the Docker image at that case, you can mount a volume in `/opt/uv/venv`. + +The directory `/opt/uv/venv` has been configured as a volume in the image, which means that Docker volumes mounted there will be initialized with the data of the image. + +With Docker Compose the volume can be as simple as: + +```yml +services: + web: + build: . + volumes: + - .:/usr/src/app + - uv:/opt/uv/venv +``` + +> [!TIP] +> +> This is especially useful when working in small teams that do not update dependencies at the same time often. Rebuilding the image with new dependencies, will not udpate the contents of an existing Docker volume. + +## Supported software versions + +### uv + +Only the latest version of uv is included in each build. + +### Python + +A build will be provided for each Python version still under maintenance and support. The latest Python version acts as the default in each build. + +You can check the currently supported Python versions at https://devguide.python.org/versions/. + +### Variants (Linux distributions) + +- Debian Trixie (default): `trixie` +- Debian Bookworm: `bookworm` + +## License + +This project is [MIT licensed](LICENSE). --- From 27d8b49f5f89a712ab8070ccf6323d1154700b12 Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Wed, 3 Sep 2025 15:53:35 +0300 Subject: [PATCH 5/5] chore(docs): shorten readme description --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8f32d0d..4e8daa1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Python with LOGIC -An opinionated base Docker image used when doing [Python with LOGIC](https://withlogic.co/ref/python). Optimized for development, CI builds and production deployments. +An opinionated base Docker image used when doing [Python with LOGIC](https://withlogic.co/ref/python). Optimized for development, CI and production. ![uv](https://img.shields.io/badge/uv-0.8.14-lime) ![python](https://img.shields.io/badge/Python-3.13%20(default)%2C3.12%2C3.11%2C3.10-blue) ![variants](https://img.shields.io/badge/Variant-trixie%20(default)%2C%20bookworm-purple?label=Variants)