Skip to content

Commit f67b822

Browse files
committed
Upgrade Dockerfile to use Docker hardened image as base
1 parent 5da5ee3 commit f67b822

File tree

4 files changed

+46
-43
lines changed

4 files changed

+46
-43
lines changed

.github/dependabot.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
version: 2
2+
registries:
3+
docker-hardened-images:
4+
type: docker-registry
5+
url: https://dhi.io
6+
username: ${{secrets.DOCKERHUB_USERNAME}}
7+
password: ${{secrets.DOCKERHUB_PASSWORD}}
8+
replaces-base: true
29
updates:
310
- package-ecosystem: 'uv'
411
directory: '/'
@@ -13,6 +20,7 @@ updates:
1320
commit-message:
1421
prefix: '[actions] '
1522
- package-ecosystem: 'docker'
23+
registries: '*'
1624
directory: '/'
1725
schedule:
1826
interval: 'weekly'

.github/workflows/multi-build.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ jobs:
218218
network=host
219219
220220
- name: Login to GitHub Container Registry
221-
uses: docker/login-action@v3
221+
uses: docker/login-action@v4
222222
# This step logs in to the GitHub Container Registry (GHCR) using the docker/login-action.
223223
# It uses the GitHub actor's username and the GITHUB_TOKEN secret for authentication.
224224
# The login is necessary to push the merged manifest list to GHCR.
@@ -227,6 +227,15 @@ jobs:
227227
username: ${{ github.actor }}
228228
password: ${{ secrets.GITHUB_TOKEN }}
229229

230+
- name: Log in to Docker Hardened Images Registry
231+
# This step logs into the Docker Hardened Images Registry in order to download the required images.
232+
# It uses Actions secrets that must be set on the repository in GitHub.
233+
uses: docker/login-action@v4
234+
with:
235+
registry: dhi.io
236+
username: ${{ secrets.DOCKERHUB_USERNAME }}
237+
password: ${{ secrets.DOCKERHUB_PASSWORD }}
238+
230239
- name: Get execution timestamp with RFC3339 format
231240
# This step gets the current execution timestamp in RFC3339 format.
232241
# It uses the date command to get the current UTC time and formats it as a string.

Dockerfile

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,34 @@
11
# syntax=docker/dockerfile:1
2-
# Prepare the base environment.
3-
FROM python:3.13 AS builder_base
4-
5-
# This approximately follows this guide: https://hynek.me/articles/docker-uv/
6-
# Which creates a standalone environment with the dependencies.
7-
# - Silence uv complaining about not being able to use hard links,
8-
# - tell uv to byte-compile packages for faster application startups,
9-
# - prevent uv from accidentally downloading isolated Python builds,
10-
# - pick a Python,
11-
# - and finally declare `/app` as the target for `uv sync`.
12-
ENV UV_LINK_MODE=copy \
13-
UV_COMPILE_BYTECODE=1 \
14-
UV_PYTHON_DOWNLOADS=never \
15-
UV_PROJECT_ENVIRONMENT=/app/.venv
16-
17-
COPY --from=ghcr.io/astral-sh/uv:0.9 /uv /uvx /bin/
18-
19-
# Since there's no point in shipping lock files, we move them
20-
# into a directory that is NOT copied into the runtime image.
21-
# The trailing slash makes COPY create `/_lock/` automagically.
22-
WORKDIR /_lock
23-
COPY pyproject.toml uv.lock /_lock/
24-
25-
# Synchronize dependencies.
26-
# This layer is cached until uv.lock or pyproject.toml change.
27-
RUN --mount=type=cache,target=/root/.cache uv sync --frozen --no-group dev
28-
29-
##################################################################################
30-
31-
FROM python:3.13
2+
FROM dhi.io/python:3.13-debian13-dev AS build-stage
323
LABEL org.opencontainers.image.authors=asi@dbca.wa.gov.au
334
LABEL org.opencontainers.image.source=https://github.com/dbca-wa/ssslite
345

35-
# Create a non-root user.
36-
RUN groupadd -r -g 1000 app \
37-
&& useradd -r -u 1000 -d /app -g app -N app
6+
# Install system packages required to install the project
7+
RUN apt-get update -y \
8+
# Python package dependencies: gunicorn_h1c requires gcc
9+
&& apt-get install -y --no-install-recommends gcc g++ \
10+
# Run shared library linker after installing packages
11+
&& ldconfig \
12+
&& rm -rf /var/lib/apt/lists/*
3813

14+
# Copy and configure uv, to install dependencies
15+
COPY --from=ghcr.io/astral-sh/uv:0.11 /uv /bin/
3916
WORKDIR /app
40-
COPY --from=builder_base --chown=app:app /app /app
41-
# Make sure we use the virtualenv by default
42-
ENV PATH="/app/.venv/bin:$PATH" \
43-
# Run Python unbuffered:
44-
PYTHONUNBUFFERED=1
45-
46-
# Install the project.
17+
# Install project dependencies
18+
COPY pyproject.toml uv.lock ./
19+
RUN uv sync --no-group dev --link-mode=copy --compile-bytecode --no-python-downloads --frozen \
20+
# Remove uv and lockfile after use
21+
&& rm -rf /bin/uv \
22+
&& rm uv.lock
23+
24+
# Environment variables
25+
ENV PYTHONUNBUFFERED=1
26+
ENV PATH="/app/.venv/bin:$PATH"
27+
28+
# Copy the remaining project files to finish building the project
4729
COPY gunicorn.py ibp.html todaysburns.html pyproject.toml ssslite.py ./
4830
COPY static ./static
49-
USER app
31+
32+
# Image runs as the nonroot user
5033
EXPOSE 8080
5134
CMD ["gunicorn", "ssslite", "--config", "gunicorn.py"]

gunicorn.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
bind = ":8080"
44
workers = 2
5-
# Give workers an expiry:
5+
worker_connections = 1000 # Max connections per worker
66
max_requests = 2048
77
max_requests_jitter = 256
88
preload_app = True
9+
keepalive = 5 # Keepalive timeout
10+
graceful_timeout = 30 # Graceful shutdown timeout
911
# Disable access logging.
1012
accesslog = None
13+
control_socket = "/tmp/gunicorn.ctl"

0 commit comments

Comments
 (0)