Skip to content

Commit e3425fb

Browse files
authored
s390x(jupyter/datascience): make image buildable on s390x (#2432)
forward-ports the changes from our good IBM fellow engineers * red-hat-data-services#1539 * red-hat-data-services#1560
1 parent e834e28 commit e3425fb

File tree

3 files changed

+223
-55
lines changed

3 files changed

+223
-55
lines changed

jupyter/datascience/ubi9-python-3.12/Dockerfile.cpu

Lines changed: 137 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,24 @@ FROM registry.access.redhat.com/ubi9/go-toolset:latest AS mongocli-builder
1111
ARG MONGOCLI_VERSION=2.0.4
1212

1313
WORKDIR /tmp/
14-
RUN curl -Lo mongodb-cli-mongocli-v${MONGOCLI_VERSION}.zip https://github.com/mongodb/mongodb-cli/archive/refs/tags/mongocli/v${MONGOCLI_VERSION}.zip
15-
RUN unzip ./mongodb-cli-mongocli-v${MONGOCLI_VERSION}.zip
16-
RUN cd ./mongodb-cli-mongocli-v${MONGOCLI_VERSION}/ && \
17-
CGO_ENABLED=1 GOOS=linux go build -a -tags strictfipsruntime -o /tmp/mongocli ./cmd/mongocli/
14+
15+
ARG TARGETARCH
16+
17+
# Keep s390x special-case from original (create dummy binary) but
18+
# include explicit curl/unzip steps from the delta for non-s390x.
19+
RUN arch="${TARGETARCH:-$(uname -m)}" && \
20+
arch=$(echo "$arch" | cut -d- -f1) && \
21+
if [ "$arch" = "s390x" ]; then \
22+
echo "Skipping mongocli build for ${arch}, creating dummy binary"; \
23+
mkdir -p /tmp && echo -e '#!/bin/sh\necho "mongocli not supported on s390x"' > /tmp/mongocli && \
24+
chmod +x /tmp/mongocli; \
25+
else \
26+
echo "Building mongocli for ${arch}"; \
27+
curl -Lo mongodb-cli-mongocli-v${MONGOCLI_VERSION}.zip https://github.com/mongodb/mongodb-cli/archive/refs/tags/mongocli/v${MONGOCLI_VERSION}.zip && \
28+
unzip ./mongodb-cli-mongocli-v${MONGOCLI_VERSION}.zip && \
29+
cd ./mongodb-cli-mongocli-v${MONGOCLI_VERSION}/ && \
30+
CGO_ENABLED=1 GOOS=linux GOARCH=${arch} GO111MODULE=on go build -a -tags strictfipsruntime -o /tmp/mongocli ./cmd/mongocli/; \
31+
fi
1832

1933
####################
2034
# cpu-base #
@@ -25,6 +39,7 @@ WORKDIR /opt/app-root/bin
2539

2640
# OS Packages needs to be installed as root
2741
USER root
42+
ARG TARGETARCH
2843

2944
# Inject the official UBI 9 repository configuration into the AIPCC base image.
3045
# The Quay-based AIPCC image is "repo-less" by default (https://gitlab.com/redhat/rhel-ai/core/base-images/app#repositories), so dnf cannot upgrade or install packages.
@@ -37,7 +52,38 @@ RUN dnf -y upgrade --refresh --best --nodocs --noplugins --setopt=install_weak_d
3752
# upgrade first to avoid fixable vulnerabilities end
3853

3954
# Install useful OS packages
40-
RUN dnf install -y perl mesa-libGL skopeo && dnf clean all && rm -rf /var/cache/yum
55+
RUN --mount=type=cache,target=/var/cache/dnf \
56+
echo "Building for architecture: ${TARGETARCH}" && \
57+
if [ "$TARGETARCH" = "s390x" ]; then \
58+
PACKAGES="perl mesa-libGL skopeo gcc gcc-c++ make openssl-devel autoconf automake libtool cmake python3-devel pybind11-devel openblas-devel unixODBC-devel"; \
59+
else \
60+
PACKAGES="perl mesa-libGL skopeo"; \
61+
fi && \
62+
echo "Installing: $PACKAGES" && \
63+
dnf install -y $PACKAGES && \
64+
dnf clean all && rm -rf /var/cache/yum
65+
66+
RUN if [ "$TARGETARCH" = "s390x" ]; then \
67+
# Install Rust and set up environment
68+
mkdir -p /opt/.cargo && \
69+
export HOME=/root && \
70+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup-init.sh && \
71+
chmod +x rustup-init.sh && \
72+
CARGO_HOME=/opt/.cargo HOME=/root ./rustup-init.sh -y --no-modify-path && \
73+
rm -f rustup-init.sh && \
74+
chown -R 1001:0 /opt/.cargo && \
75+
# Set environment variables
76+
echo 'export PATH=/opt/.cargo/bin:$PATH' >> /etc/profile.d/cargo.sh && \
77+
echo 'export CARGO_HOME=/opt/.cargo' >> /etc/profile.d/cargo.sh && \
78+
echo 'export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1' >> /etc/profile.d/cargo.sh; \
79+
fi
80+
81+
# Set python alternatives only for s390x (not needed for other arches)
82+
RUN if [ "$TARGETARCH" = "s390x" ]; then \
83+
alternatives --install /usr/bin/python python /usr/bin/python3.12 1 && \
84+
alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1 && \
85+
python --version && python3 --version; \
86+
fi
4187

4288
# Other apps and tools installed as default user
4389
USER 1001
@@ -53,6 +99,64 @@ RUN curl -L https://mirror.openshift.com/pub/openshift-v4/$(uname -m)/clients/oc
5399
rm -f /tmp/openshift-client-linux.tar.gz
54100
# Install the oc client end
55101

102+
##############################
103+
# wheel-builder stage #
104+
# NOTE: Only used in s390x
105+
##############################
106+
FROM cpu-base AS s390x-builder
107+
108+
ARG TARGETARCH
109+
USER 0
110+
WORKDIR /tmp/build-wheels
111+
112+
# Build pyarrow optimized for s390x
113+
RUN --mount=type=cache,target=/root/.cache/pip \
114+
--mount=type=cache,target=/root/.cache/dnf \
115+
if [ "$TARGETARCH" = "s390x" ]; then \
116+
# Install build dependencies (shared for pyarrow and onnx)
117+
dnf install -y cmake make gcc-c++ pybind11-devel wget && \
118+
dnf clean all && \
119+
# Build and collect pyarrow wheel
120+
git clone --depth 1 https://github.com/apache/arrow.git && \
121+
cd arrow/cpp && \
122+
mkdir release && cd release && \
123+
cmake -DCMAKE_BUILD_TYPE=Release \
124+
-DCMAKE_INSTALL_PREFIX=/usr/local \
125+
-DARROW_PYTHON=ON \
126+
-DARROW_PARQUET=ON \
127+
-DARROW_ORC=ON \
128+
-DARROW_FILESYSTEM=ON \
129+
-DARROW_JSON=ON \
130+
-DARROW_CSV=ON \
131+
-DARROW_DATASET=ON \
132+
-DARROW_DEPENDENCY_SOURCE=BUNDLED \
133+
-DARROW_WITH_LZ4=OFF \
134+
-DARROW_WITH_ZSTD=OFF \
135+
-DARROW_WITH_SNAPPY=OFF \
136+
-DARROW_BUILD_TESTS=OFF \
137+
-DARROW_BUILD_BENCHMARKS=OFF \
138+
.. && \
139+
make -j$(nproc) VERBOSE=1 && \
140+
make install -j$(nproc) && \
141+
cd ../../python && \
142+
pip install --no-cache-dir -r requirements-build.txt && \
143+
PYARROW_WITH_PARQUET=1 \
144+
PYARROW_WITH_DATASET=1 \
145+
PYARROW_WITH_FILESYSTEM=1 \
146+
PYARROW_WITH_JSON=1 \
147+
PYARROW_WITH_CSV=1 \
148+
PYARROW_PARALLEL=$(nproc) \
149+
python setup.py build_ext --build-type=release --bundle-arrow-cpp bdist_wheel && \
150+
mkdir -p /tmp/wheels && \
151+
cp dist/pyarrow-*.whl /tmp/wheels/ && \
152+
chmod -R 777 /tmp/wheels && \
153+
# Ensure wheels directory exists and has content
154+
ls -la /tmp/wheels/; \
155+
else \
156+
# Create empty wheels directory for non-s390x
157+
mkdir -p /tmp/wheels; \
158+
fi
159+
56160
####################
57161
# jupyter-minimal #
58162
####################
@@ -79,12 +183,14 @@ WORKDIR /opt/app-root/src
79183

80184
ENTRYPOINT ["start-notebook.sh"]
81185

186+
82187
########################
83188
# jupytyer-datascience #
84189
########################
85190
FROM jupyter-minimal AS jupyter-datascience
86191

87192
ARG DATASCIENCE_SOURCE_CODE=jupyter/datascience/ubi9-python-3.12
193+
ARG TARGETARCH
88194

89195
LABEL name="odh-notebook-jupyter-datascience-ubi9-python-3.12" \
90196
summary="Jupyter data science notebook image for ODH notebooks" \
@@ -110,22 +216,45 @@ COPY --from=mongocli-builder /tmp/mongocli /opt/app-root/bin/
110216
# Other apps and tools installed as default user
111217
USER 1001
112218

219+
# Copy wheels from build stage (s390x only)
220+
COPY --from=s390x-builder /tmp/wheels /tmp/wheels
221+
RUN if [ "$TARGETARCH" = "s390x" ]; then \
222+
pip install --no-cache-dir /tmp/wheels/*.whl; \
223+
else \
224+
echo "Skipping wheel install for $TARGETARCH"; \
225+
fi
226+
113227
# Install Python packages and Jupyterlab extensions from requirements.txt
114228
COPY ${DATASCIENCE_SOURCE_CODE}/pylock.toml ./
115229
# Copy Elyra setup to utils so that it's sourced at startup
116230
COPY ${DATASCIENCE_SOURCE_CODE}/setup-elyra.sh ${DATASCIENCE_SOURCE_CODE}/utils ./utils/
117231

118-
RUN echo "Installing softwares and packages" && \
232+
RUN --mount=type=cache,target=/root/.cache/pip \
233+
echo "Installing softwares and packages" && \
119234
# This may have to download and compile some dependencies, and as we don't lock requirements from `build-system.requires`,
120235
# we often don't know the correct hashes and `--require-hashes` would therefore fail on non amd64, where building is common.
121-
uv pip install --strict --no-deps --no-cache --no-config --no-progress --verify-hashes --compile-bytecode --index-strategy=unsafe-best-match --requirements=./pylock.toml && \
236+
if [ "$TARGETARCH" = "s390x" ]; then \
237+
# For s390x, we need special flags and environment variables for building packages
238+
GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1 \
239+
CFLAGS="-O3" CXXFLAGS="-O3" \
240+
uv pip install --strict --no-deps --no-cache --no-config --no-progress \
241+
--verify-hashes --compile-bytecode --index-strategy=unsafe-best-match \
242+
--requirements=./pylock.toml; \
243+
else \
244+
# This may have to download and compile some dependencies, and as we don't lock requirements from `build-system.requires`,
245+
# we often don't know the correct hashes and `--require-hashes` would therefore fail on non amd64, where building is common.
246+
uv pip install --strict --no-deps --no-cache --no-config --no-progress \
247+
--verify-hashes --compile-bytecode --index-strategy=unsafe-best-match \
248+
--requirements=./pylock.toml; \
249+
fi && \
122250
# setup path for runtime configuration
123251
mkdir /opt/app-root/runtimes && \
124252
mkdir /opt/app-root/pipeline-runtimes && \
125253
# Remove default Elyra runtime-images \
126254
rm /opt/app-root/share/jupyter/metadata/runtime-images/*.json && \
127255
# Replace Notebook's launcher, "(ipykernel)" with Python's version 3.x.y \
128-
sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" /opt/app-root/share/jupyter/kernels/python3/kernel.json && \
256+
sed -i -e "s/Python.*/$(python --version | cut -d '.' -f-2)\",/" \
257+
/opt/app-root/share/jupyter/kernels/python3/kernel.json && \
129258
# copy jupyter configuration
130259
install -D -m 0644 /opt/app-root/bin/utils/jupyter_server_config.py \
131260
/opt/app-root/etc/jupyter/jupyter_server_config.py && \

0 commit comments

Comments
 (0)