Skip to content

Commit 7e2de5a

Browse files
committed
Migrate to Alpine with 57.9% size reduction
Ubuntu-based image, powered by eclipse-temurin:11-jre-noble, was 1.3 GB, unnecessarily large for a Jupyter notebook environment. Debian base includes many unnecessary packages, apt cache bloat, and no aggressive Python artifact cleanup. Fix: - Migrate from Ubuntu to Alpine Linux 3.22 (musl-based, 5.4MB base) - Multi-architecture support (linux/amd64, linux/arm64) via BuildKit TARGETARCH - Aggressive Python optimization: * Remove __pycache__, *.pyc, *.pyo files * Strip Babel locale data (31.4MB → 640KB, keeping only en_*) * Remove test directories and pip/setuptools from site-packages - Virtual build dependencies pattern (gcc/g++/musl-dev cleaned after Jupyter install) - Move curl to intermediate-builder stage only (not in final image) - Optimize COPY with --chown to eliminate extra chown layer - Architecture-specific coursier binaries: * amd64: Official musl static build (v2.1.24) * arm64: VirtusLab glibc build (v2.1.24) with gcompat layer - Enhanced .dockerignore to exclude dev artifacts Results: - Image size: 1.305GB → 549.8MB (57.9% reduction) - Architecture: linux/amd64, linux/arm64 validated - Functionality: All notebooks work, GraphViz rendering verified Known limitations: - Jupyter authentication disabled (intentional for local dev, see source/jupyter_server_config.py) - Python 3.12 paths hardcoded (will need update on Alpine Python updates) - Scala 2.12.10 + Almond 0.9.1 (newer versions require source changes per patch)
1 parent e2d7b74 commit 7e2de5a

File tree

2 files changed

+75
-28
lines changed

2 files changed

+75
-28
lines changed

.dockerignore

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1-
/Dockerfile
2-
/diagrams/*
3-
/.ipynb_checkpoints/
1+
.git
2+
.gitignore
3+
*.md
4+
*.patch
5+
.ipynb_checkpoints
6+
**/.ipynb_checkpoints
7+
node_modules
8+
__pycache__
9+
*.pyc
10+
.DS_Store
11+
.vscode
12+
.idea
13+
*.swp
14+
*.swo
15+
*~

Dockerfile

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,81 @@
11
# First stage : setup the system and environment
2-
FROM eclipse-temurin:11-jre-noble AS base
2+
FROM alpine:3.22 AS base
33

4+
# Install OpenJDK 11 and runtime dependencies
45
RUN \
5-
apt-get update && \
6-
DEBIAN_FRONTEND=noninteractive apt-get install -y \
7-
ca-certificates-java \
8-
curl \
6+
apk add --no-cache \
7+
openjdk11-jre-headless \
98
graphviz \
9+
python3 \
10+
py3-pip \
11+
bash \
12+
libstdc++ \
13+
&& \
14+
apk add --no-cache --virtual .build-deps \
1015
gcc \
16+
g++ \
17+
musl-dev \
18+
linux-headers \
1119
python3-dev \
1220
&& \
13-
rm -rf /var/lib/apt/lists/*
21+
pip3 install --no-cache-dir --break-system-packages jupyter jupyterlab && \
22+
find /usr/lib/python3.12 -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true && \
23+
find /usr/lib/python3.12 -type f -name '*.pyc' -delete && \
24+
find /usr/lib/python3.12 -type f -name '*.pyo' -delete && \
25+
find /usr/lib/python3.12/site-packages/babel/locale-data -mindepth 1 ! -name 'en_*' -a ! -name 'root.dat' -delete 2>/dev/null || true && \
26+
find /usr/lib/python3.12/site-packages -type d -name tests -exec rm -rf {} + 2>/dev/null || true && \
27+
find /usr/lib/python3.12/site-packages -type d -name testing -exec rm -rf {} + 2>/dev/null || true && \
28+
rm -rf /usr/lib/python3.12/site-packages/pip /usr/lib/python3.12/site-packages/setuptools && \
29+
apk del .build-deps
1430

15-
RUN apt-get update && apt-get install -y python3-pip && rm -rf /var/lib/apt/lists/*
16-
RUN pip3 install --no-cache-dir --break-system-packages jupyter jupyterlab
31+
ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk
32+
ENV PATH=$JAVA_HOME/bin:$PATH
1733

18-
RUN useradd -ms /bin/bash bootcamp
34+
RUN adduser -D -s /bin/bash bootcamp
1935

2036
ENV SCALA_VERSION=2.12.10
2137
ENV ALMOND_VERSION=0.9.1
22-
38+
ENV COURSIER_VERSION=2.1.24
2339
ENV COURSIER_CACHE=/coursier_cache
40+
ENV JUPYTER_CONFIG_DIR=/jupyter/config
41+
ENV JUPYTER_DATA_DIR=/jupyter/data
2442

25-
ADD . /chisel-bootcamp/
43+
COPY . /chisel-bootcamp/
2644
WORKDIR /chisel-bootcamp
2745

28-
ENV JUPYTER_CONFIG_DIR=/jupyter/config
29-
ENV JUPITER_DATA_DIR=/jupyter/data
30-
31-
RUN mkdir -p $JUPYTER_CONFIG_DIR/custom
32-
RUN cp source/custom.js $JUPYTER_CONFIG_DIR/custom/
33-
RUN cp source/jupyter_server_config.py $JUPYTER_CONFIG_DIR/
46+
RUN mkdir -p $JUPYTER_CONFIG_DIR/custom && \
47+
cp source/custom.js $JUPYTER_CONFIG_DIR/custom/ && \
48+
cp source/jupyter_server_config.py $JUPYTER_CONFIG_DIR/
3449

3550
# Second stage - download Scala requirements and the Scala kernel
3651
FROM base AS intermediate-builder
3752

53+
ARG TARGETARCH
54+
3855
RUN mkdir /coursier_cache
3956

57+
# Install glibc for ARM64 coursier binary (x86-64 uses static musl build)
58+
RUN \
59+
apk add --no-cache curl && \
60+
if [ "$TARGETARCH" = "arm64" ]; then \
61+
apk add --no-cache wget gcompat libstdc++ && \
62+
wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \
63+
wget -q https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.35-r1/glibc-2.35-r1.apk && \
64+
apk --no-cache --force-overwrite add glibc-2.35-r1.apk && \
65+
rm glibc-2.35-r1.apk && \
66+
ln -s /lib/ld-musl-aarch64.so.1 /lib/ld-linux-aarch64.so.1 2>/dev/null || true; \
67+
fi
68+
4069
RUN \
41-
curl -L -o coursier https://git.io/coursier-cli && \
70+
case "$TARGETARCH" in \
71+
amd64|"") \
72+
CS_URL="https://github.com/coursier/coursier/releases/download/v${COURSIER_VERSION}/cs-x86_64-pc-linux.gz" ;; \
73+
arm64) \
74+
CS_URL="https://github.com/VirtusLab/coursier-m1/releases/download/v${COURSIER_VERSION}/cs-aarch64-pc-linux.gz" ;; \
75+
*) \
76+
echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; \
77+
esac && \
78+
curl -fL --retry 3 "$CS_URL" | gzip -d > coursier && \
4279
chmod +x coursier && \
4380
./coursier \
4481
bootstrap \
@@ -47,7 +84,7 @@ RUN \
4784
--default=true \
4885
-o almond && \
4986
./almond --install --global && \
50-
\rm -rf almond couriser /root/.cache/coursier
87+
rm -rf almond coursier /root/.cache/coursier
5188

5289
# Execute a notebook to ensure Chisel is downloaded into the image for offline work
5390
# Disabled: dotvisualizer has JSON4s compatibility issues with Chisel 3.6
@@ -57,13 +94,11 @@ RUN \
5794
# Last stage
5895
FROM base AS final
5996

60-
# copy the Scala requirements and kernel into the image
61-
COPY --from=intermediate-builder /coursier_cache/ /coursier_cache/
62-
COPY --from=intermediate-builder /usr/local/share/jupyter/kernels/scala/ /usr/local/share/jupyter/kernels/scala/
97+
# copy the Scala requirements and kernel into the image
98+
COPY --from=intermediate-builder --chown=bootcamp:bootcamp /coursier_cache/ /coursier_cache/
99+
COPY --from=intermediate-builder --chown=bootcamp:bootcamp /usr/local/share/jupyter/kernels/scala/ /usr/local/share/jupyter/kernels/scala/
63100

64-
RUN chown -R bootcamp:bootcamp /chisel-bootcamp
65-
RUN chown -R bootcamp:bootcamp /jupyter
66-
RUN chown -R bootcamp:bootcamp /coursier_cache
101+
RUN chown -R bootcamp:bootcamp /chisel-bootcamp /jupyter
67102

68103
USER bootcamp
69104
WORKDIR /chisel-bootcamp

0 commit comments

Comments
 (0)