Skip to content

Commit 8be8d11

Browse files
committed
feat: update unsloth template (Python 3.11.14, add proxy stage, switch to start1.sh)
1 parent 632016c commit 8be8d11

2 files changed

Lines changed: 150 additions & 146 deletions

File tree

Lines changed: 149 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -1,188 +1,192 @@
11
# ===============================
2-
# logo + scripts stages
2+
# Build args
3+
# ===============================
4+
ARG PYTHON_VERSION="3.11.14"
5+
6+
# ===============================
7+
# logo + scripts + proxy stages
38
# ===============================
49
FROM scratch AS logo
510
COPY container-template/yotta.txt yotta.txt
611

712
FROM scratch AS scripts
8-
COPY container-template/start.sh start.sh
13+
COPY container-template/start1.sh start1.sh
14+
15+
FROM scratch AS proxy
16+
COPY container-template/proxy/nginx.conf nginx.conf
17+
COPY container-template/proxy/readme.html readme.html
918

1019
# ===============================
1120
# main stage
1221
# ===============================
1322
FROM nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04
1423

15-
ARG DEBIAN_FRONTEND=noninteractive
16-
ENV TZ=UTC \
24+
# Re-declare ARGs after FROM
25+
ARG PYTHON_VERSION="3.11.14"
26+
27+
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
28+
29+
ENV DEBIAN_FRONTEND=noninteractive \
30+
SHELL=/bin/bash \
31+
TZ=UTC \
1732
LANG=C.UTF-8 \
1833
LC_ALL=C.UTF-8 \
1934
PYTHONUNBUFFERED=1 \
20-
VENV_PATH=/opt/venv
35+
PATH=/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/bin:$PATH \
36+
LD_LIBRARY_PATH=/usr/local/nvidia/lib64:$LD_LIBRARY_PATH \
37+
JUPYTER_PASSWORD=yotta
2138

22-
# -------------------------------
39+
# ===============================
40+
# Workspace
41+
# ===============================
42+
WORKDIR /
43+
RUN mkdir -p /workspace && chmod 777 /workspace /root
44+
45+
# ===============================
2346
# System packages
24-
# -------------------------------
47+
# ===============================
2548
RUN set -eux; \
26-
apt-get update; \
49+
apt-get update -y; \
2750
apt-get install -y --no-install-recommends --allow-change-held-packages \
2851
ca-certificates curl wget git \
29-
sudo \
30-
openssh-server \
31-
nginx \
32-
tini \
33-
build-essential make g++ \
52+
build-essential pkg-config \
3453
software-properties-common \
54+
locales tzdata \
55+
openssh-server nginx sudo \
3556
vim jq tree htop tmux rsync \
36-
pciutils iproute2 net-tools lsof procps; \
57+
zip unzip less procps net-tools lsof \
58+
pciutils iproute2; \
59+
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen; \
60+
locale-gen; \
61+
mkdir -p /var/run/sshd /var/log/supervisor; \
62+
chmod 700 /var/run/sshd /var/log/supervisor; \
63+
chmod 755 /var/log; \
64+
apt-get clean; \
3765
rm -rf /var/lib/apt/lists/*
3866

39-
# -------------------------------
40-
# sshd wrapper (unchanged)
41-
# -------------------------------
42-
RUN <<'EOF'
43-
set -eux
44-
if [ -x /usr/sbin/sshd ] && [ ! -x /usr/sbin/sshd.real ]; then
45-
mv /usr/sbin/sshd /usr/sbin/sshd.real
46-
cat > /usr/sbin/sshd <<'EOSSHD'
47-
#!/usr/bin/env bash
48-
set -euo pipefail
49-
REAL="/usr/sbin/sshd.real"
50-
if [[ " $* " == *" -D "* ]]; then
51-
args=()
52-
for a in "$@"; do
53-
[[ "$a" == "-D" ]] && continue
54-
args+=("$a")
55-
done
56-
exec "$REAL" "${args[@]}"
57-
fi
58-
exec "$REAL" "$@"
59-
EOSSHD
60-
chmod 755 /usr/sbin/sshd
61-
fi
62-
EOF
63-
64-
# -------------------------------
65-
# Python 3.11 + venv
66-
# -------------------------------
67+
# ===============================
68+
# Remove ubuntu user (security: prevent unauthorized SSH access)
69+
# ===============================
70+
RUN userdel -r ubuntu || true
71+
72+
# ===============================
73+
# Python (build from source, with ensurepip)
74+
# ===============================
6775
RUN set -eux; \
68-
add-apt-repository -y ppa:deadsnakes/ppa; \
69-
apt-get update; \
76+
PY_MM="$(echo "${PYTHON_VERSION}" | awk -F. '{print $1"."$2}')"; \
77+
apt-get update -y; \
7078
apt-get install -y --no-install-recommends \
71-
python3.11 python3.11-venv python3.11-dev; \
72-
rm -rf /var/lib/apt/lists/*; \
73-
python3.11 -m venv "${VENV_PATH}"; \
74-
"${VENV_PATH}/bin/pip" install -U pip setuptools wheel
75-
76-
RUN ln -sf "${VENV_PATH}/bin/python3.11" /usr/local/bin/python3.11 && \
77-
ln -sf "${VENV_PATH}/bin/python" /usr/local/bin/python || true && \
78-
ln -sf "${VENV_PATH}/bin/pip" /usr/local/bin/pip || true
79-
80-
RUN echo 'export PATH=/opt/venv/bin:$PATH' >/etc/profile.d/venv.sh && \
81-
chmod 644 /etc/profile.d/venv.sh && \
82-
echo 'Defaults secure_path="/opt/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"' \
83-
>/etc/sudoers.d/99-secure-path
84-
85-
# -------------------------------
86-
# Python packages (Unsloth)
87-
# -------------------------------
88-
RUN set -eux; \
89-
pip install --no-cache-dir \
79+
libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev \
80+
libffi-dev libncursesw5-dev xz-utils tk-dev uuid-dev liblzma-dev; \
81+
curl -fSL --retry 10 --retry-delay 2 --retry-all-errors \
82+
"https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz" \
83+
-o /tmp/Python.tgz; \
84+
mkdir -p /tmp/python-src; \
85+
tar -xzf /tmp/Python.tgz -C /tmp/python-src --strip-components=1; \
86+
rm -f /tmp/Python.tgz; \
87+
cd /tmp/python-src; \
88+
./configure --with-ensurepip=install; \
89+
make -j"$(nproc)"; \
90+
make altinstall; \
91+
cd /; \
92+
rm -rf /tmp/python-src; \
93+
ln -sf "/usr/local/bin/python${PY_MM}" /usr/bin/python; \
94+
ln -sf "/usr/local/bin/python${PY_MM}" /usr/bin/python3; \
95+
python -m pip install --no-cache-dir --upgrade pip setuptools wheel; \
96+
apt-get clean; \
97+
rm -rf /var/lib/apt/lists/*
98+
99+
# ===============================
100+
# PyTorch (cu128)
101+
# ===============================
102+
RUN python -m pip install --no-cache-dir \
90103
--index-url https://download.pytorch.org/whl/cu128 \
91-
torch torchvision torchaudio; \
92-
pip install --no-cache-dir \
93-
unsloth \
94-
jupyterlab jupyter_server ipykernel \
104+
torch torchvision torchaudio
105+
106+
# ===============================
107+
# Unsloth + dependencies
108+
# ===============================
109+
RUN python -m pip install --no-cache-dir \
110+
unsloth vllm \
95111
huggingface_hub datasets; \
96-
pip install --no-cache-dir xformers --no-deps; \
97-
pip install --no-cache-dir triton
112+
python -m pip install --no-cache-dir xformers --no-deps; \
113+
python -m pip install --no-cache-dir triton
98114

99-
RUN ln -sf "${VENV_PATH}/bin/jupyter" /usr/local/bin/jupyter || true
115+
# ===============================
116+
# Jupyter + common tools
117+
# ===============================
118+
RUN python -m pip install --no-cache-dir \
119+
jupyterlab ipywidgets jupyter-archive notebook==7.3.3 ipykernel
100120

101-
# -------------------------------
102-
# Users
103-
# -------------------------------
104-
RUN set -eux; \
105-
useradd -m -s /bin/bash -u 1000 unsloth || true; \
106-
useradd -m -s /bin/bash -u 1001 ubuntu || true; \
107-
usermod -aG sudo unsloth; \
108-
usermod -aG sudo ubuntu; \
109-
echo "unsloth ALL=(ALL) NOPASSWD:ALL" >/etc/sudoers.d/90-unsloth; \
110-
echo "ubuntu ALL=(ALL) NOPASSWD:ALL" >/etc/sudoers.d/90-ubuntu; \
111-
chmod 0440 /etc/sudoers.d/90-unsloth /etc/sudoers.d/90-ubuntu; \
112-
mkdir -p /workspace /workspace/work /workspace/unsloth-notebooks; \
113-
chown -R unsloth:unsloth /workspace
114-
115-
# =========================================================
116-
# Download Unsloth notebooks templates and flatten structure
117-
# =========================================================
121+
# ===============================
122+
# Build-time assertion: verify key packages
123+
# (unsloth requires GPU at import time, so only check it's installed)
124+
# ===============================
125+
RUN python -c "import torch; import jupyterlab; from importlib.metadata import version; print(f'unsloth=={version(\"unsloth\")} torch=={torch.__version__} ok')"
126+
127+
# ===============================
128+
# Configure JupyterLab
129+
# ===============================
130+
RUN mkdir -p /root/.jupyter && printf '%s\n' \
131+
'c.ServerApp.token = "yotta"' \
132+
'c.ServerApp.password = ""' \
133+
'c.ServerApp.allow_remote_access = True' \
134+
'c.ServerApp.allow_origin = "*"' \
135+
'c.NotebookApp.token = "yotta"' \
136+
'c.NotebookApp.password = ""' \
137+
'c.NotebookApp.allow_remote_access = True' \
138+
> /root/.jupyter/jupyter_lab_config.py && \
139+
chmod 600 /root/.jupyter/jupyter_lab_config.py
140+
141+
# ===============================
142+
# Download Unsloth notebook templates
143+
# ===============================
118144
RUN set -eux; \
119145
cd /tmp; \
120146
git clone --depth=1 https://github.com/unslothai/notebooks.git unsloth-notebooks-src; \
121-
\
122-
# Ensure target directory exists
123147
mkdir -p /workspace/unsloth-notebooks; \
124-
\
125-
# Copy all scripts from original_template to the target directory
126148
cp -a unsloth-notebooks-src/original_template/. /workspace/unsloth-notebooks/; \
127-
\
128-
# Also copy template.ipynb (if needed)
129149
cp -a unsloth-notebooks-src/template.ipynb /workspace/unsloth-notebooks/ || true; \
130-
\
131-
# Fix permissions (Jupyter runs as unsloth user)
132-
chown -R unsloth:unsloth /workspace/unsloth-notebooks; \
133-
\
134-
# Cleanup
135150
rm -rf /tmp/unsloth-notebooks-src
136151

152+
# ===============================
153+
# CUDA bin convenience
154+
# ===============================
155+
RUN ln -sf /usr/local/cuda/bin/* /usr/bin/ || true
137156

138-
# =========================================================
139-
# Key fix: do not COPY unsloth-notebooks directly
140-
# instead COPY the entire build context, then copy if present, skip if absent
141-
# =========================================================
142-
COPY . /__build_context__
157+
# ===============================
158+
# Supervisor dirs
159+
# ===============================
160+
RUN mkdir -p /var/log/supervisor /usr/local/bin && \
161+
chmod 777 /var/log/supervisor /workspace /var/run /var/lib/nginx && \
162+
mkdir -p /run/sshd && \
163+
chmod 700 /run/sshd
164+
165+
# ===============================
166+
# start1.sh
167+
# ===============================
168+
COPY --from=scripts start1.sh /start1.sh
169+
RUN chmod 755 /start1.sh && \
170+
sed -i 's/\r$//' /start1.sh
171+
172+
# ===============================
173+
# nginx / branding
174+
# ===============================
175+
COPY --from=proxy nginx.conf /etc/nginx/nginx.conf
176+
COPY --from=proxy readme.html /usr/share/nginx/html/readme.html
177+
COPY README.md /usr/share/nginx/html/README.md
143178

144-
RUN set -eux; \
145-
if [ -d /__build_context__/unsloth-notebooks ]; then \
146-
cp -a /__build_context__/unsloth-notebooks/. /workspace/unsloth-notebooks/; \
147-
chown -R unsloth:unsloth /workspace/unsloth-notebooks; \
148-
fi; \
149-
rm -rf /__build_context__
150-
151-
# -------------------------------
152-
# sshd dirs
153-
# -------------------------------
154-
RUN mkdir -p /var/run/sshd
155-
156-
# -------------------------------
157-
# Branding
158-
# -------------------------------
159179
COPY --from=logo yotta.txt /etc/yotta.txt
160180
RUN echo 'cat /etc/yotta.txt' >> /root/.bashrc
161181

162-
# -------------------------------
163-
# start.sh (must not change)
164-
# -------------------------------
165-
COPY --from=scripts start.sh /start.sh
166-
RUN chmod 755 /start.sh
167-
168-
# -------------------------------
169-
# entry.sh
170-
# -------------------------------
171-
RUN <<'EOF'
172-
cat > /entry.sh <<'EOENTRY'
173-
#!/usr/bin/env bash
174-
set -euo pipefail
175-
(/usr/sbin/sshd || true)
176-
exec sudo -u unsloth -H bash -lc \
177-
'jupyter lab --ip=0.0.0.0 --port=${JUPYTER_PORT:-8888} --no-browser \
178-
--ServerApp.token="" --ServerApp.password="" \
179-
--ServerApp.allow_origin="*" \
180-
--ServerApp.root_dir=/workspace'
181-
EOENTRY
182-
chmod 755 /entry.sh
183-
EOF
184-
185-
EXPOSE 8888 22 80
186-
187-
ENTRYPOINT ["/usr/bin/tini","--"]
188-
CMD ["/start.sh"]
182+
# ===============================
183+
# Ports
184+
# ===============================
185+
EXPOSE 22 80 8888
186+
187+
# ===============================
188+
# Entrypoint: root runs start1.sh
189+
# ===============================
190+
USER root
191+
WORKDIR /root
192+
CMD ["/bin/bash", "-c", "exec /bin/bash /start1.sh"]

official-templates/unsloth/docker-bake.hcl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ target "unsloth" {
2222
platforms = ["linux/amd64"]
2323

2424
tags = [
25-
"${PUBLISHER}/unsloth:0.6.9-py3.11-cuda12.1-cudnn-devel-ubuntu22.04",
25+
"${PUBLISHER}/unsloth:0.6.9-py3.11-cuda12.1-cudnn-devel-ubuntu22.04-260407",
2626
]
2727

2828
# Keeping contexts here to align with your existing setup

0 commit comments

Comments
 (0)