-
-
Notifications
You must be signed in to change notification settings - Fork 6.1k
docker: Colab-grade JupyterLab and Studio UX for the Unsloth image #6681
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: docker-blackwell-build
Are you sure you want to change the base?
Changes from 7 commits
c9ff52b
7b5bb24
e496095
50f7170
b963403
dde7a26
2eba8a4
30e7e09
9a53256
a56a7a8
2e4699c
38f1115
6fd9744
3fb8804
d1a5b58
9cd1951
2482719
0a8ae80
2c190aa
04452eb
67c0a8e
5d41a03
38df387
b558bc7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,9 @@ | ||
| # Full Unsloth image: base training stack + Studio + JupyterLab + sshd. | ||
| # | ||
| # This is the image published as docker.io/unsloth/unsloth:latest. It layers | ||
| # Unsloth Studio on top of the lean base image (Dockerfile, published under | ||
| # the `base` tags) and runs the same service trio as the previous production | ||
| # This is the image published as docker.io/unsloth/unsloth:studio (and the | ||
| # default :latest). It layers Unsloth Studio on top of the lean core image | ||
| # (Dockerfile, published under the `core` tags) and runs the same service trio | ||
| # as the previous production | ||
| # image: Studio on 8000, JupyterLab on 8888, key-only sshd on 22. | ||
| # | ||
| # Build (local): | ||
|
|
@@ -28,6 +29,27 @@ | |
| # images always ship the same stack. | ||
|
|
||
| ARG BASE_IMAGE=unsloth-blackwell:test | ||
|
|
||
| # --- builder stage: prebuild the Unsloth JupyterLab extension ----------------- | ||
| # Builds the named "Unsloth Dark" (Monokai) theme + the Colab-style Down/Up | ||
| # cell-navigation keymap. Node lives ONLY in this throwaway stage; the final | ||
| # image copies just the prebuilt static labextension, so the runtime stays | ||
| # Node-free. Uses the base image's bundled jlpm + jupyterlab (version-matched). | ||
| FROM ${BASE_IMAGE} AS labext-builder | ||
| ENV DEBIAN_FRONTEND=noninteractive | ||
| # JupyterLab 4.6's build tooling declares a Node >=20 engine; Ubuntu 24.04's | ||
| # distro nodejs is 18, so pull Node 20 LTS from NodeSource (it bundles npm). | ||
| # This stage is thrown away, so the extra apt sources never reach the runtime. | ||
| RUN apt-get update \ | ||
| && apt-get install -y --no-install-recommends ca-certificates curl gnupg git \ | ||
| && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ | ||
| && apt-get install -y --no-install-recommends nodejs \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
Comment on lines
+43
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
On the Ubuntu 24.04 CUDA base, Useful? React with 👍 / 👎. |
||
| COPY jupyter/unsloth_labext /opt/labext-src | ||
| RUN cd /opt/labext-src \ | ||
| && /opt/unsloth-venv/bin/jlpm install \ | ||
| && /opt/unsloth-venv/bin/jlpm build:prod | ||
|
|
||
| FROM ${BASE_IMAGE} | ||
|
|
||
| # Studio source ref to clone. Defaults to `main`, but a CI publish pipeline | ||
|
|
@@ -170,6 +192,46 @@ COPY fetch_llama_prebuilt.py /usr/local/lib/unsloth/fetch_llama_prebuilt.py | |
| # Optional public Cloudflare tunnel for JupyterLab (UNSLOTH_JUPYTER_CLOUDFLARE=1, | ||
| # or `unsloth-jupyter-tunnel --force`); supervisord runs it as jupyter-cloudflare. | ||
| COPY unsloth_jupyter_tunnel.sh /usr/local/bin/unsloth-jupyter-tunnel | ||
| # JupyterLab defaults baked for every container: the named "Unsloth Dark" | ||
| # (Monokai) theme with adaptive light/dark by system preference, a per-cell run | ||
| # button that does NOT auto-advance, a labeled "Restart & Run All", windowing | ||
| # disabled so collapsing a long output does not snap to the cell top, | ||
| # ArrowDown/Up jumping to the TOP of the next/previous cell, and the official | ||
| # Jupyter "get notified about news" prompt suppressed (fetchNews/checkForUpdates | ||
| # off). overrides.json is the system-wide settings override (read from the base | ||
| # venv's share/jupyter/lab/settings); the theme + keymap + Unsloth top-bar logo | ||
| # ship as the prebuilt labextension built in the labext-builder stage above. | ||
| COPY jupyter/overrides.json /opt/unsloth-venv/share/jupyter/lab/settings/overrides.json | ||
| COPY --from=labext-builder /opt/labext-src/unsloth-jupyterlab/labextension /opt/unsloth-venv/share/jupyter/labextensions/unsloth-jupyterlab | ||
| # Unsloth branding (all served by jupyter_server, so applied to its site-packages | ||
| # the same way): replace the browser-tab favicon and the page logo with the | ||
| # Unsloth logo, and brand the login screen (dark Unsloth-themed login.html). | ||
| # Also disable + lock the stock top-left Jupyter logo plugin so the Unsloth logo | ||
| # widget shipped by the labextension is the only one rendered in the top bar | ||
| # (lock keeps users from re-enabling it in the UI). | ||
| COPY jupyter/favicon.ico /tmp/unsloth-branding/favicon.ico | ||
| COPY jupyter/logo.png /tmp/unsloth-branding/logo.png | ||
| COPY jupyter/login.html /tmp/unsloth-branding/login.html | ||
| COPY jupyter/install_sloth_stickers.py /tmp/unsloth-branding/install_sloth_stickers.py | ||
| RUN JS="$(/opt/unsloth-venv/bin/python -c 'import os, jupyter_server; print(os.path.dirname(jupyter_server.__file__))')" \ | ||
| && for n in favicon.ico favicon-notebook.ico favicon-file.ico favicon-terminal.ico; do \ | ||
| cp /tmp/unsloth-branding/favicon.ico "${JS}/static/favicons/${n}"; \ | ||
| done \ | ||
| && cp /tmp/unsloth-branding/logo.png "${JS}/static/logo/logo.png" \ | ||
| && cp /tmp/unsloth-branding/login.html "${JS}/templates/login.html" \ | ||
| # Copy the curated Studio sloth stickers the login page rotates through into | ||
| # jupyter_server's static dir (sloth/NN.png). Fail-soft -- but scoped to ONLY | ||
| # the sticker step via the { ...; } group so a failure in a REQUIRED branding | ||
| # step above (JS resolve, favicon/logo/login copy) still fails the build | ||
| # instead of being swallowed by this fallback. If the Studio public folder | ||
| # ever moves, login.html's onerror falls back to the logo. | ||
| && { /opt/unsloth-venv/bin/python /tmp/unsloth-branding/install_sloth_stickers.py \ | ||
| --src "${UNSLOTH_STUDIO_HOME}/src/studio/frontend/public/Sloth emojis" \ | ||
| --dest "${JS}/static/sloth" \ | ||
| || echo ">> sloth stickers not installed (login falls back to the Unsloth logo)"; } \ | ||
| && rm -rf /tmp/unsloth-branding \ | ||
| && /opt/unsloth-venv/bin/jupyter labextension disable @jupyterlab/application-extension:logo \ | ||
| && /opt/unsloth-venv/bin/jupyter labextension lock @jupyterlab/application-extension:logo | ||
| RUN chmod +x /usr/local/bin/unsloth-studio-launch \ | ||
| /usr/local/bin/unsloth-studio-update \ | ||
| /usr/local/bin/unsloth-llama-update \ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,7 +23,7 @@ | |
| # Studio chat / Jupyter / GGUF tooling still validate. | ||
| # | ||
| # Env overrides: IMAGE (default unsloth/unsloth:latest) | ||
| # BASE_IMAGE (default unsloth/unsloth:base) | ||
| # BASE_IMAGE (default unsloth/unsloth:core) | ||
| # GPUS=all|none|0|0,1 (default: auto-detect) | ||
| # PORT_STUDIO=18000 PORT_JUPYTER=18888 | ||
| # WORK=~/unsloth_docker_test (logs) | ||
|
|
@@ -33,7 +33,7 @@ | |
| set -uo pipefail | ||
|
|
||
| IMAGE="${IMAGE:-unsloth/unsloth:latest}" | ||
| BASE_IMAGE="${BASE_IMAGE:-unsloth/unsloth:base}" | ||
| BASE_IMAGE="${BASE_IMAGE:-unsloth/unsloth:core}" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This default now pulls Useful? React with 👍 / 👎. |
||
| GPUS="${GPUS:-auto}" | ||
| PORT_STUDIO="${PORT_STUDIO:-18000}" | ||
| PORT_JUPYTER="${PORT_JUPYTER:-18888}" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When building
Dockerfile.studiowithdocker/as the context, this allowlist still excludesjupyter/install_sloth_stickers.pybecause the file is not whitelisted after the top-level**ignore. The newCOPY jupyter/install_sloth_stickers.py ...in the studio Dockerfile therefore fails with a missing source before the image can build; add an exception for that helper alongside the otherjupyter/assets.Useful? React with 👍 / 👎.