Build the app to a single native binary with graalpy's 'standalone native' command (Dockerfile.native). granian/rloop cannot be bundled into a standalone binary, so the executable serves the app over ASGI with Hypercorn via native/entrypoint.py, which also works around GraalPy standalone quirks (socket.listen, str response bodies, signal handling). Adds docker-compose.native.yml, a -native CI job, and README docs.
82 lines
2.9 KiB
Docker
82 lines
2.9 KiB
Docker
# syntax=docker/dockerfile:1
|
|
# Native standalone build for pyfconfig.
|
|
#
|
|
# Produces a single self-contained executable bundling the app, its
|
|
# dependencies, the Python standard library and the GraalPy runtime, using
|
|
# GraalPy's `standalone native` command (backed by GraalVM Native Image).
|
|
#
|
|
# Unlike Dockerfile.graalpy, the executable does not run granian/rloop: those
|
|
# are native extensions that cannot be bundled into a standalone binary and
|
|
# granian spawns workers through multiprocessing. The app is served over ASGI
|
|
# by Hypercorn (pure Python) instead; see native/entrypoint.py.
|
|
#
|
|
# Build requirements: network access to the Gitea registry, PyPI, Maven Central
|
|
# and the base images, plus enough RAM for native-image (see NATIVE_IMAGE_XMX).
|
|
|
|
ARG GRAALPY_IMAGE=ghcr.io/graalvm/graalpy-community:25
|
|
ARG NATIVE_IMAGE_TOOLS=ghcr.io/graalvm/native-image-community:25
|
|
|
|
# GraalVM CE with native-image and javac, version-matched to the GraalPy
|
|
# distribution below. Copied into the builder so the standalone build does not
|
|
# download a JDK at build time.
|
|
FROM ${NATIVE_IMAGE_TOOLS} AS tools
|
|
|
|
# --- Builder ---------------------------------------------------------------
|
|
FROM ${GRAALPY_IMAGE} AS builder
|
|
|
|
ARG NATIVE_IMAGE_XMX=5500m
|
|
|
|
COPY --from=tools /usr/lib64/graalvm/graalvm-community-java25 /usr/lib64/graalvm/graalvm-community-java25
|
|
ENV JAVA_HOME=/usr/lib64/graalvm/graalvm-community-java25 \
|
|
PATH=/usr/lib64/graalvm/graalvm-community-java25/bin:${PATH}
|
|
|
|
# native-image links the executable against zlib; the runtime library is
|
|
# present but the linker needs the -devel package (libz.so).
|
|
RUN dnf install -y zlib-devel \
|
|
&& dnf clean all
|
|
|
|
WORKDIR /build
|
|
|
|
COPY pyproject.toml README.md requirements-native.txt ./
|
|
COPY src/ ./src/
|
|
COPY native/ ./native/
|
|
|
|
RUN graalpy -m venv /opt/venv \
|
|
&& /opt/venv/bin/pip install \
|
|
--index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple \
|
|
--extra-index-url https://pypi.org/simple \
|
|
-r requirements-native.txt \
|
|
&& /opt/venv/bin/pip install --no-deps .
|
|
|
|
# -Os builds an interpreter-only Truffle runtime: much lower build memory and a
|
|
# smaller binary, at the cost of peak throughput. Remove it to enable the JIT.
|
|
# The cache mount keeps the Maven artifacts across builds.
|
|
RUN --mount=type=cache,target=/opt/graalpy-25.0.2/downloaded_standalone_resources \
|
|
mkdir -p /out \
|
|
&& graalpy -m standalone native \
|
|
-m native/entrypoint.py \
|
|
--venv /opt/venv \
|
|
-o /out/pyfconfig \
|
|
-ce -Os \
|
|
-N-J-Xmx${NATIVE_IMAGE_XMX} -N-J-Xms512m
|
|
|
|
# --- Runtime ---------------------------------------------------------------
|
|
FROM oraclelinux:10-slim
|
|
|
|
RUN useradd -r -s /sbin/nologin -d /home/app -m app
|
|
|
|
COPY --from=builder /out/pyfconfig /usr/local/bin/pyfconfig
|
|
|
|
ENV HOME=/home/app \
|
|
HOST=0.0.0.0 \
|
|
PORT=8080
|
|
|
|
USER app
|
|
|
|
EXPOSE 8080
|
|
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
|
|
CMD curl -fsS "http://127.0.0.1:${PORT}/api/health" || exit 1
|
|
|
|
CMD ["/usr/local/bin/pyfconfig"]
|