|
| 1 | +# CPU Training Image Dockerfile |
| 2 | +# |
| 3 | +# FIPS-friendly Features: |
| 4 | +# - uv is used only in build stage (not shipped in runtime image) |
| 5 | +# - Build tools are isolated in intermediate stages |
| 6 | +# - Final image contains only runtime dependencies |
| 7 | + |
| 8 | +################################################################################ |
| 9 | +# Build Arguments |
| 10 | +################################################################################ |
| 11 | +# Align base with notebooks minimal CPU |
| 12 | +ARG BASE_IMAGE=registry.redhat.io/rhai/base-image-cpu-rhel9:3.2.0-1764872006 |
| 13 | +ARG PYTHON_VERSION=3.12 |
| 14 | +ARG SRC_DIR=cpu-torch290-py312 |
| 15 | + |
| 16 | +############################ |
| 17 | +# Stage 1: PDF Tool Build # |
| 18 | +############################ |
| 19 | +FROM registry.access.redhat.com/ubi9/python-312:latest AS pdf-builder |
| 20 | + |
| 21 | +WORKDIR /opt/app-root/bin |
| 22 | +USER 0 |
| 23 | + |
| 24 | +# Build pandoc for architectures that need it (ppc64le) |
| 25 | +COPY --chmod=0755 utils/install_pandoc.sh ./install_pandoc.sh |
| 26 | +RUN ./install_pandoc.sh |
| 27 | + |
| 28 | +################################################################################ |
| 29 | +# Builder Stage - Install uv for dependency resolution |
| 30 | +################################################################################ |
| 31 | +FROM ${BASE_IMAGE} AS builder |
| 32 | + |
| 33 | +USER 0 |
| 34 | +WORKDIR /tmp/builder |
| 35 | + |
| 36 | +# Install latest version of uv in builder stage |
| 37 | +RUN pip install --no-cache-dir uv |
| 38 | + |
| 39 | +################################################################################ |
| 40 | +# Base Stage |
| 41 | +################################################################################ |
| 42 | +FROM ${BASE_IMAGE} AS base |
| 43 | + |
| 44 | +LABEL name="cpu:py312-torch290" \ |
| 45 | + summary="CPU Python 3.12 image with PyTorch 2.9.0" \ |
| 46 | + description="CPU image combining minimal Jupyter workbench and runtime ML stack (PyTorch 2.9.0) on UBI9" \ |
| 47 | + io.k8s.display-name="CPU Python 3.12 (Workbench + Runtime)" \ |
| 48 | + io.k8s.description="CPU image: Jupyter workbench by default; runtime when command provided." |
| 49 | + |
| 50 | +# Fallback public indexes if RHOAI index lacks a package |
| 51 | +ENV PIP_INDEX_URL=https://pypi.org/simple \ |
| 52 | + UV_INDEX_URL=https://pypi.org/simple \ |
| 53 | + UV_DEFAULT_INDEX=https://pypi.org/simple |
| 54 | + |
| 55 | +# Copy license file |
| 56 | +ARG SRC_DIR |
| 57 | +COPY ${SRC_DIR}/LICENSE.md /licenses/cpu-license.md |
| 58 | + |
| 59 | +USER 0 |
| 60 | +WORKDIR /opt/app-root/bin |
| 61 | + |
| 62 | +################################################################################ |
| 63 | +# System Dependencies Stage |
| 64 | +################################################################################ |
| 65 | +FROM base AS system-deps |
| 66 | + |
| 67 | +ARG SRC_DIR |
| 68 | +USER 0 |
| 69 | +WORKDIR /opt/app-root/bin |
| 70 | + |
| 71 | +# Register and refresh subscription (required for RHEL base) |
| 72 | +RUN /bin/bash <<'EOF' |
| 73 | +set -Eeuxo pipefail |
| 74 | +subscription-manager register --org 18631088 --activationkey thisisunsafe |
| 75 | +if command -v subscription-manager &> /dev/null; then |
| 76 | + subscription-manager identity &>/dev/null && subscription-manager refresh || echo "No identity, skipping refresh." |
| 77 | +fi |
| 78 | +EOF |
| 79 | + |
| 80 | +# Core OS packages (minimal, keep from notebooks) |
| 81 | +RUN dnf install -y --setopt=install_weak_deps=False \ |
| 82 | + perl \ |
| 83 | + mesa-libGL \ |
| 84 | + skopeo && \ |
| 85 | + dnf clean all && rm -rf /var/cache/dnf/* |
| 86 | + |
| 87 | +# Install the oc client (matches notebooks) |
| 88 | +RUN /bin/bash <<'EOF' |
| 89 | +set -Eeuxo pipefail |
| 90 | +curl -L https://mirror.openshift.com/pub/openshift-v4/$(uname -m)/clients/ocp/stable/openshift-client-linux.tar.gz \ |
| 91 | + -o /tmp/openshift-client-linux.tar.gz |
| 92 | +tar -xzvf /tmp/openshift-client-linux.tar.gz oc |
| 93 | +rm -f /tmp/openshift-client-linux.tar.gz |
| 94 | +EOF |
| 95 | + |
| 96 | +# Notebook utils and PDF deps (local copy) |
| 97 | +COPY utils/ /opt/app-root/bin/utils/ |
| 98 | +RUN chmod -R 0755 /opt/app-root/bin/utils |
| 99 | + |
| 100 | +# PDF export tooling mirrors notebook-minimal flow |
| 101 | +RUN --mount=type=cache,from=pdf-builder,source=/usr/local/,target=/pdf_builder/,rw bash <<'EOF' |
| 102 | +set -Eeuxo pipefail |
| 103 | +if [[ "$(uname -m)" == "ppc64le" ]]; then |
| 104 | + cp -r /pdf_builder/pandoc /usr/local/ |
| 105 | + ./utils/install_texlive.sh |
| 106 | +else |
| 107 | + ./utils/install_pdf_deps.sh |
| 108 | +fi |
| 109 | +EOF |
| 110 | + |
| 111 | +ENV PATH="/usr/local/texlive/bin/linux:/usr/local/pandoc/bin:${PATH}" |
| 112 | + |
| 113 | +# Copy notebook entry script and entrypoint |
| 114 | +COPY utils/start-notebook.sh /opt/app-root/bin/start-notebook.sh |
| 115 | +COPY utils/entrypoint-universal.sh /usr/local/bin/entrypoint-universal.sh |
| 116 | +RUN chmod 0755 /opt/app-root/bin/start-notebook.sh /usr/local/bin/entrypoint-universal.sh |
| 117 | + |
| 118 | +# Install build toolchain (from UBI repos) |
| 119 | +# - gcc, gcc-c++, make: C/C++ compilation tools |
| 120 | +# - python3-devel: Python headers for building native extensions |
| 121 | +# - cmake: Build system (required by some Python packages) |
| 122 | +# - git: Version control (some pip installs need it) |
| 123 | +RUN dnf install -y --setopt=install_weak_deps=False \ |
| 124 | + gcc \ |
| 125 | + gcc-c++ \ |
| 126 | + make \ |
| 127 | + python3-devel \ |
| 128 | + cmake \ |
| 129 | + git && dnf clean all && rm -rf /var/cache/dnf/* |
| 130 | + |
| 131 | +################################################################################ |
| 132 | +# Python Dependencies Stage |
| 133 | +################################################################################ |
| 134 | +FROM system-deps AS python-deps |
| 135 | + |
| 136 | +ARG SRC_DIR |
| 137 | +USER 0 |
| 138 | +WORKDIR /tmp/deps |
| 139 | + |
| 140 | +# Ensure python version arg available in this stage |
| 141 | +ARG PYTHON_VERSION |
| 142 | + |
| 143 | +# Copy uv from builder stage (FIPS: uv only used during build, not in runtime) |
| 144 | +COPY --from=builder /opt/app-root/bin/uv /usr/local/bin/uv |
| 145 | + |
| 146 | +# Copy dependency files |
| 147 | +COPY --chown=1001:0 ${SRC_DIR}/pyproject.toml ${SRC_DIR}/pylock.toml ./ |
| 148 | + |
| 149 | +# Switch to user 1001 for pip installations |
| 150 | +USER 1001 |
| 151 | +WORKDIR /opt/app-root/src |
| 152 | + |
| 153 | +# Install main dependencies from pylock.toml using uv pip sync |
| 154 | +ENV UV_NO_CACHE=1 |
| 155 | +RUN uv pip sync --python-platform=linux --python-version=3.12 /tmp/deps/pylock.toml |
| 156 | +ENV UV_NO_CACHE= |
| 157 | + |
| 158 | +# Install kubeflow-sdk from Git (not in pylock.toml) |
| 159 | +# TODO: use aipcc index |
| 160 | +RUN pip install --retries 5 --timeout 300 --no-cache-dir \ |
| 161 | + "git+https://github.com/opendatahub-io/kubeflow-sdk@main" |
| 162 | + |
| 163 | +# Apply notebook customizations (match notebooks minimal) |
| 164 | +RUN /bin/bash <<'EOF' |
| 165 | +set -Eeuo pipefail |
| 166 | +# disable announcements |
| 167 | +jupyter labextension disable "@jupyterlab/apputils-extension:announcements" || true |
| 168 | +# rename kernel launcher to current python version |
| 169 | +sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json |
| 170 | +# copy jupyter config |
| 171 | +mkdir -p /opt/app-root/etc/jupyter |
| 172 | +cp /opt/app-root/bin/utils/jupyter_server_config.py /opt/app-root/etc/jupyter |
| 173 | +# apply addons |
| 174 | +/opt/app-root/bin/utils/addons/apply.sh |
| 175 | +# usercustomize / protobuf patch |
| 176 | +cp /opt/app-root/bin/utils/usercustomize.pth /opt/app-root/lib/python${PYTHON_VERSION}/site-packages/ |
| 177 | +cp /opt/app-root/bin/utils/monkey_patch_protobuf_6x.py /opt/app-root/lib/python${PYTHON_VERSION}/site-packages/ |
| 178 | +EOF |
| 179 | + |
| 180 | +# Fix permissions for OpenShift |
| 181 | +ARG PYTHON_VERSION |
| 182 | +USER 0 |
| 183 | +RUN chmod -R g+w /opt/app-root/lib/python${PYTHON_VERSION}/site-packages \ |
| 184 | + && fix-permissions /opt/app-root -P |
| 185 | + |
| 186 | +# Clean up uv and build artifacts |
| 187 | +RUN rm -f /usr/local/bin/uv \ |
| 188 | + && rm -rf /tmp/deps \ |
| 189 | + && dnf remove -y gcc gcc-c++ cmake python3-devel \ |
| 190 | + && dnf clean all \ |
| 191 | + && rm -rf /var/cache/dnf/* |
| 192 | + |
| 193 | +################################################################################ |
| 194 | +# Final Stage - runtime (inherits deps) |
| 195 | +################################################################################ |
| 196 | +FROM python-deps AS final |
| 197 | + |
| 198 | +USER 1001 |
| 199 | +WORKDIR /opt/app-root/src |
| 200 | + |
| 201 | +ENTRYPOINT ["/usr/local/bin/entrypoint-universal.sh"] |
| 202 | +CMD ["start-notebook.sh"] |
| 203 | + |
0 commit comments