diff --git a/images/constants.yml b/images/constants.yml index aff8c75277..6d3fbd3825 100644 --- a/images/constants.yml +++ b/images/constants.yml @@ -17,6 +17,7 @@ variables: python312osFlavors: bullseye,bookworm python313osFlavors: bullseye,bookworm python314osFlavors: noble + python315osFlavors: noble dotnet80osFlavors: bullseye,bookworm dotnet90osFlavors: bookworm dotnet100osFlavors: noble @@ -47,6 +48,8 @@ variables: python311_GPG_keys: A035C8C19219BA821ECEA86B64E628F8D684696D python312_GPG_keys: 7169605F62C751356D054A26A821E680E5FA6305 python313_GPG_keys: 7169605F62C751356D054A26A821E680E5FA6305 + python314_GPG_keys: 7169605F62C751356D054A26A821E680E5FA6305 + python315_GPG_keys: 7169605F62C751356D054A26A821E680E5FA6305 python39_GPG_keys: E3FF2839C048B25C084DEBE9B26995E310250568 ASPNET_CORE_APP_80: 8.0.26 ASPNET_CORE_APP_80_SHA: 2a5d39bfdb2d734fd765f806bf4be6138bc8d9b44f2f8aee3250ced56eaad4c0e4bf06141dec6ef2c6a46a8faf3d8ffd60b7361b687ff7d8b45179df35bb0149 @@ -81,4 +84,5 @@ variables: python311Version: 3.11.15 python312Version: 3.12.13 python313Version: 3.13.13 - python314Version: 3.14.4 \ No newline at end of file + python314Version: 3.14.4 + python315Version: 3.15.0b3 \ No newline at end of file diff --git a/images/runtime/build_runtime_images.sh b/images/runtime/build_runtime_images.sh index 51587e8bdc..2e0c1d3a42 100644 --- a/images/runtime/build_runtime_images.sh +++ b/images/runtime/build_runtime_images.sh @@ -156,6 +156,11 @@ case $stack_name in "3.14") docker build -f ./images/runtime/python/template.Dockerfile -t python314_image_$os_flavor --build-arg PYTHON_FULL_VERSION=$python314Version --build-arg PYTHON_VERSION=3.14 --build-arg PYTHON_MAJOR_VERSION=3 --build-arg OS_FLAVOR=$os_flavor --build-arg BASE_IMAGE="docker.io/library/oryx_run_base_$os_flavor" --build-arg SDK_STORAGE_BASE_URL_VALUE=$SDK_STORAGE_BASE_URL_VALUE . ;; + + "3.15") + # TODO: Update to ubuntu 26 when available. + docker build -f ./images/runtime/python/ubuntu-24.04-slim.Dockerfile -t python315_image_$os_flavor --build-arg PYTHON_FULL_VERSION=$python315Version --build-arg PYTHON_VERSION=3.15 --build-arg PYTHON_MAJOR_VERSION=3 --build-arg DEBIAN_FLAVOR=$os_flavor --build-arg BASE_IMAGE="mcr.microsoft.com/mirror/docker/library/ubuntu:24.04" --build-arg SDK_STORAGE_BASE_URL_VALUE=$SDK_STORAGE_BASE_URL_VALUE . + ;; esac ;; esac diff --git a/images/runtime/python/cgmanifest.json b/images/runtime/python/cgmanifest.json index b84ac0588e..889d9c7517 100644 --- a/images/runtime/python/cgmanifest.json +++ b/images/runtime/python/cgmanifest.json @@ -9,7 +9,8 @@ }, "Type": "pip" }, - "DevelopmentDependency": false + "DevelopmentDependency": false, + "_comment": "Used by template.Dockerfile / noble.Dockerfile (3.9-3.14). Not installed in ubuntu-24.04-slim.Dockerfile (3.15+)." }, { "Component": { @@ -19,7 +20,8 @@ }, "Type": "pip" }, - "DevelopmentDependency": false + "DevelopmentDependency": false, + "_comment": "Used by template.Dockerfile / noble.Dockerfile (3.9-3.14). Not installed in ubuntu-24.04-slim.Dockerfile (3.15+)." }, { "Component": { @@ -29,7 +31,9 @@ }, "Type": "pip" }, - "DevelopmentDependency": false + "DevelopmentDependency": false, + "_comment": "Used by template.Dockerfile / noble.Dockerfile (3.9-3.14). Not installed in ubuntu-24.04-slim.Dockerfile (3.15+)." } ] } + diff --git a/images/runtime/python/install-dependencies-slim.sh b/images/runtime/python/install-dependencies-slim.sh new file mode 100644 index 0000000000..93fe8f760f --- /dev/null +++ b/images/runtime/python/install-dependencies-slim.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT license. +# -------------------------------------------------------------------------------------------- + +set -ex + +# Core runtime libs + DB driver dev headers + tools +apt-get update \ + && apt-get upgrade -y \ + && apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + wget \ + less \ + git \ + gnupg \ + libexpat1 \ + libodbc2 \ + libpq-dev \ + default-libmysqlclient-dev + +# Microsoft ODBC Driver 18 for SQL Server (pyodbc target). +# Uses the official packages.microsoft.com ubuntu/24.04 prod feed. +# See https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server +curl -fsSL https://packages.microsoft.com/keys/microsoft.asc \ + | gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg +curl -fsSL https://packages.microsoft.com/config/ubuntu/24.04/prod.list \ + > /etc/apt/sources.list.d/mssql-release.list + +apt-get update \ + && ACCEPT_EULA=Y apt-get install -y --no-install-recommends msodbcsql18 + +mkdir -p /etc/unixODBC +cat >/etc/unixODBC/odbcinst.ini <<'EOL' +[ODBC Driver 18 for SQL Server] +Description=Microsoft ODBC Driver 18 for SQL Server +Driver=/opt/microsoft/msodbcsql18/lib64/libmsodbcsql-18.1.so.1.1 +Threading=1 +UsageCount=1 +EOL + +# Remove gnupg — only needed to dearmor the key above. +apt-get purge -y --auto-remove gnupg + +# Clean up — keep at the very end so every apt-get install above is included. +rm -rf /var/lib/apt/lists/* diff --git a/images/runtime/python/ubuntu-24.04-slim.Dockerfile b/images/runtime/python/ubuntu-24.04-slim.Dockerfile new file mode 100644 index 0000000000..d9afd255f8 --- /dev/null +++ b/images/runtime/python/ubuntu-24.04-slim.Dockerfile @@ -0,0 +1,96 @@ +ARG DEBIAN_FLAVOR +ARG BASE_IMAGE + +# Stage 1 — build the Oryx startup-script generator (the `oryx` CLI). +FROM mcr.microsoft.com/oss/go/microsoft/golang:1.26.4-bookworm AS startupCmdGen +WORKDIR /go/src +COPY src/startupscriptgenerator/src . +ARG GIT_COMMIT=unspecified +ARG BUILD_NUMBER=unspecified +ARG RELEASE_TAG_NAME=unspecified +ENV RELEASE_TAG_NAME=${RELEASE_TAG_NAME} +ENV GIT_COMMIT=${GIT_COMMIT} +ENV BUILD_NUMBER=${BUILD_NUMBER} +ENV PATH_CA_CERTIFICATE="/etc/ssl/certs/ca-certificate.crt" +RUN chmod +x build.sh && ./build.sh python /opt/startupcmdgen/startupcmdgen + + +# Stage 2 — compile CPython from source (PGO+LTO via prereqs/build.sh). +FROM ${BASE_IMAGE} AS pythonSdkBuilder +ARG DEBIAN_FLAVOR +ARG PYTHON_FULL_VERSION +ARG PYTHON_VERSION +ENV PYTHON_VERSION=${PYTHON_FULL_VERSION} +COPY platforms/python/prereqs/build.sh /tmp/build.sh +COPY platforms/python/versions/${DEBIAN_FLAVOR}/versionsToBuild.txt /tmp/versionsToBuild.txt +COPY images/receiveGpgKeys.sh /tmp/receiveGpgKeys.sh +RUN chmod +x /tmp/build.sh /tmp/receiveGpgKeys.sh +RUN set -e \ + && mkdir -p /usr/src/python && cd /usr/src/python \ + && VERSION_LINE=$(grep "^${PYTHON_VERSION}," /tmp/versionsToBuild.txt) \ + && export GPG_KEY=$(echo "$VERSION_LINE" | cut -d',' -f2 | tr -d ' ') \ + && export PYTHON_SHA256=$(echo "$VERSION_LINE" | cut -d',' -f3 | tr -d ' ') \ + && export OS_FLAVOR=${DEBIAN_FLAVOR} \ + && /tmp/build.sh + + +# Stage 3 — final runtime image. +FROM ${BASE_IMAGE} as main + +ARG SDK_STORAGE_BASE_URL_VALUE +ARG DEBIAN_FLAVOR +ENV DEBIAN_FLAVOR=${DEBIAN_FLAVOR} +ENV ORYX_SDK_STORAGE_BASE_URL=${SDK_STORAGE_BASE_URL_VALUE} + +# Layer 1 — runtime apt deps (least volatile; bumped only on driver/SSL CVEs). +# Targeted COPY of only the dep script — avoids invalidating this layer on +# every unrelated change under images/. +COPY images/runtime/python/install-dependencies-slim.sh /tmp/install-dependencies-slim.sh +RUN chmod +x /tmp/install-dependencies-slim.sh \ + && /tmp/install-dependencies-slim.sh \ + && rm -f /tmp/install-dependencies-slim.sh + +# Layer 2 — extracted Python (changes every patch bump). +ARG PYTHON_FULL_VERSION +ARG PYTHON_VERSION +ARG PYTHON_MAJOR_VERSION +ENV PYTHON_VERSION=${PYTHON_FULL_VERSION} + +COPY --from=pythonSdkBuilder /opt/python/${PYTHON_FULL_VERSION} /opt/python/${PYTHON_FULL_VERSION} + +RUN set -ex \ + && cd /opt/python/ \ + && ln -s ${PYTHON_FULL_VERSION} ${PYTHON_VERSION} \ + && ln -s ${PYTHON_VERSION} ${PYTHON_MAJOR_VERSION} \ + && echo /opt/python/${PYTHON_MAJOR_VERSION}/lib >> /etc/ld.so.conf.d/python.conf \ + && ldconfig \ + && if [ "${PYTHON_MAJOR_VERSION}" = "3" ]; then cd /opt/python/${PYTHON_MAJOR_VERSION}/bin \ + && ln -nsf idle3 idle \ + && ln -nsf pydoc3 pydoc \ + && ln -nsf python3-config python-config; fi \ + && rm -rf /var/lib/apt/lists/* + +ENV PATH="/opt/python/${PYTHON_MAJOR_VERSION}/bin:${PATH}" + +# AI + cert envs. +ARG AI_CONNECTION_STRING +ENV ORYX_AI_CONNECTION_STRING=${AI_CONNECTION_STRING} +ENV PATH_CA_CERTIFICATE="/etc/ssl/certs/ca-certificate.crt" + +# Buildpacks contract. +ENV CNB_STACK_ID="oryx.stacks.skeleton" +LABEL io.buildpacks.stack.id="oryx.stacks.skeleton" + +# Layer 3 — pip toolchain (gunicorn only; rebuilt on pip bumps). +RUN --mount=type=secret,id=pip_index_url,target=/run/secrets/pip_index_url \ + pip install --index-url $(cat /run/secrets/pip_index_url) --upgrade pip && \ + pip install --index-url $(cat /run/secrets/pip_index_url) gunicorn + +# C.UTF-8 is provided by libc — no `locales` package install required. +ENV LANG="C.UTF-8" \ + LANGUAGE="C.UTF-8" \ + LC_ALL="C.UTF-8" + +# Layer 4 — oryx CLI (per-build, tiny — last for max cache hit on rebuilds). +COPY --from=startupCmdGen /opt/startupcmdgen/startupcmdgen /opt/startupcmdgen/startupcmdgen +RUN ln -s /opt/startupcmdgen/startupcmdgen /usr/local/bin/oryx diff --git a/platforms/python/versions/noble/versionsToBuild.txt b/platforms/python/versions/noble/versionsToBuild.txt index 45a8bb4b5c..332e7756db 100644 --- a/platforms/python/versions/noble/versionsToBuild.txt +++ b/platforms/python/versions/noble/versionsToBuild.txt @@ -2,3 +2,4 @@ # version, gpg keys, SHA256 3.14.2,,CE543AB854BC256B61B71E9B27F831FFD1BFD60A479D639F8BE7F9757CF573E9, 3.14.4,,D923C51303E38E249136FC1BDF3568D56ECB03214EFDEF48516176D3D7FAAEF8, +3.15.0b3,7169605F62C751356D054A26A821E680E5FA6305,e5a18806817f912f2c9a1091ac77703f9a969b129c878d436f0f7025bf2f9e97, diff --git a/src/BuildScriptGenerator/PythonVersions.cs b/src/BuildScriptGenerator/PythonVersions.cs index 7e39133e20..f557d2ba18 100644 --- a/src/BuildScriptGenerator/PythonVersions.cs +++ b/src/BuildScriptGenerator/PythonVersions.cs @@ -31,5 +31,7 @@ public static class PythonVersions public static string Python313Version => ConstantsYamlReader.Get("python313Version"); public static string Python314Version => ConstantsYamlReader.TryGet("python314Version"); + + public static string Python315Version => ConstantsYamlReader.TryGet("python315Version"); } } \ No newline at end of file