Skip to content

Commit fb4265b

Browse files
committed
Add basic text, exercises and dockerfile examples
1 parent f20459a commit fb4265b

File tree

4 files changed

+340
-33
lines changed

4 files changed

+340
-33
lines changed

topics/teaching/tutorials/jbt-customization-1/tutorial.md

Lines changed: 142 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ contributors:
2929

3030
* WIP
3131

32+
```bash
33+
sudo docker run --rm -p 127.0.0.1:8888:8888 quay.io/jupyter/minimal-notebook:2025-06-23
34+
```
35+
36+
* Will print out a link to `http://localhost:8888/lab?token=<token>`
37+
3238
## Access your local Notebook Server
3339

3440
* Windows and Mac users will need verification work...
@@ -41,30 +47,152 @@ contributors:
4147

4248
* WIP
4349

44-
# Docker Compose (?)
50+
* You are now in a predefined environment. All Packages from mentioned in the docker stacks documentation are there, so you can easily open the `Python 3` Notebook presented on the start page and start working. As you are in a minimal notebook you just do have the python default libraries, but you could run this to get the current weekday:
4551

46-
* Maybe introduce compose to reduce complexity of terminal interaction
52+
```python
53+
import datetime
54+
now = datetime.datetime.now()
55+
print(now.strftime("%A"))
56+
```
4757

48-
# Build your first custom Image
58+
* For scientific work you will likely need more than just the default python libraries. Reviewing the docker stacks is helpful and maybe an image like the `scipy-notebook` will have most of the packages you need. But of course these default collections cannot have suitable package selections for the very specific needs of all courses out in the world.
4959

50-
* WIP
60+
For example, in this minimal setup you might like to have the option to print out text in a fancier way. Luckily, there is a python package for this: `cowsay`. So let's go ahead, try running
5161

52-
# Use your first custom Image
62+
```python
63+
from cowsay import cow
64+
cow('Muuuuh')
65+
```
5366

54-
* WIP
67+
As you will see, this fails as cowsay is not available in minimal-notebook.
5568

56-
## Access your local custom Notebook Server
5769

58-
* WIP
70+
# Build your first custom Image
5971

60-
## See your custom changes
72+
In order to customize this Container Image, we need a so-called `Dockerfile`. Go ahead, create a new directory as your playground. Then, create a file called `Dockerfile` in this new directory.
6173

62-
* WIP
74+
Fill it with content:
6375

64-
# Extend your custom Image
76+
```dockerfile
77+
# First, we say from which container image we want to start
78+
# This is called the base image
79+
FROM quay.io/jupyter/minimal-notebook:2025-06-23
6580

66-
* Install a simple plugin like `igv-notebook`
81+
# Now, we can run arbitrary commands in order to extend the base image
82+
RUN pip install --quiet --no-cache-dir cowsay
83+
```
6784

68-
* WIP
85+
* Build it, mind the period at the end of the command
86+
87+
```bash
88+
sudo docker build -t my-custom-jupyterlab .
89+
```
90+
91+
92+
# Use your first custom Image
6993

70-
# (WIP)
94+
```bash
95+
sudo docker run --rm -p 127.0.0.1:8888:8888 my-custom-jupyterlab
96+
```
97+
98+
Again, you'll provided with a link to open you jupyterlab. Start a Pyhton 3 Notebook by clicking the tile.
99+
100+
Again, run:
101+
102+
```python
103+
from cowsay import cow
104+
cow('Muuuuh')
105+
```
106+
107+
As you will see, the command now succeeds and prints a nice graphical text output.
108+
109+
# Exercise: build your own custom Image
110+
111+
Now, let's go ahead and try out some real usecase.
112+
113+
> Create a custom notebook from the `scipy-notebook` base image and install the `igv-browser` extension.
114+
115+
You succeeded, if you can run following snippet successfully and are provided with a genome browser with loaded track:
116+
117+
> <hands-on-title>Make this script succeed in your custom JupyterLab</hands-on-title>
118+
>
119+
>
120+
> ```python
121+
> # This example snippet is taken from https://github.com/igvteam/igv-notebook/blob/v3.1.4/README.md
122+
> # License: MIT License
123+
>
124+
> import igv_notebook
125+
> igv_notebook.init()
126+
> igv_browser= igv_notebook.Browser(
127+
> {
128+
> "genome": "hg19",
129+
> "locus": "chr22:24,376,166-24,376,456",
130+
> "tracks": [{
131+
> "name": "BAM",
132+
> "url": "https://s3.amazonaws.com/igv.org.demo/gstt1_sample.bam",
133+
> "indexURL": "https://s3.amazonaws.com/igv.org.demo/gstt1_sample.bam.bai",
134+
> "format": "bam",
135+
> "type": "alignment"
136+
> }],
137+
> "roi": [
138+
> {
139+
> "name": "ROI set 1",
140+
> "url": "https://s3.amazonaws.com/igv.org.test/data/roi/roi_bed_1.bed",
141+
> "indexed": False,
142+
> "color": "rgba(94,255,1,0.25)"
143+
> }
144+
> ]
145+
> }
146+
> )
147+
> ```
148+
{: .question}
149+
150+
> <solution-title>Proposed approach</solution-title>
151+
>
152+
> Keep in mind, there are many ways to solve this exercise. This proposed one is only one way to get the job done.
153+
>
154+
> 1. Create a new `Dockerfile`:
155+
> ```dockerfile
156+
> FROM quay.io/jupyter/scipy-notebook:2025-06-23
157+
> RUN pip install --quiet --no-cache-dir igv-notebook
158+
> ```
159+
> 2. Build the new Container Image:
160+
> ```bash
161+
> sudo docker build -t my-custom-jupyterlab .
162+
> ```
163+
> 3. Run a container from your image
164+
> ```bash
165+
> sudo docker run --rm -p 127.0.0.1:8888:8888 my-custom-jupyterlab
166+
> ```
167+
> 4. Access the JupyterLab via URL provided by the container output
168+
> 5. Open a Python 3 Jupyter Notebook, paste in the above code and run it. It should work now.
169+
{: .solution}
170+
171+
# Docker Compose
172+
173+
While running all these docker commands into the command line directly works fine, it has significant disadvantages: it's verbose and therefore error-prone, it's difficult to reproduce and it's difficult to share and version.
174+
175+
A better approach is to use a `docker-compose` setup. All relevant config is written into a file called `compose.yml`, which is sharable, reproducable and versionizable.
176+
177+
```yaml
178+
services:
179+
jupyterlab:
180+
image: my-custom-jupyterlab
181+
build:
182+
context: .
183+
dockerfile: Dockerfile
184+
ports:
185+
- 127.0.0.1:8888:8888
186+
```
187+
188+
You may now build the image simply by executing:
189+
190+
```
191+
sudo docker compose build
192+
```
193+
194+
An you may run it easily by executing:
195+
196+
```
197+
sudo docker compose up
198+
```

topics/teaching/tutorials/jbt-customization-2/tutorial.md

Lines changed: 127 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,66 @@ Now we know how to include changes, we will build something more complex and loo
2121

2222
# Install an additional Kernel
2323

24-
* e.g. rust kernel, or R
24+
https://github.com/jupyter/jupyter/wiki/Jupyter-kernels
2525

26-
* WIP
26+
Rust: https://github.com/evcxr/evcxr/tree/main/evcxr_jupyter
27+
28+
29+
```
30+
FROM quay.io/jupyter/minimal-notebook:2025-06-23
31+
32+
USER root
33+
RUN apt update \
34+
&& apt install -y build-essential \
35+
&& apt clean
36+
37+
USER ${NB_USER}
38+
ADD --chmod=755 https://sh.rustup.rs /tmp/rustup.sh
39+
RUN /tmp/rustup.sh -v -y
40+
RUN . "$HOME/.cargo/env" && cargo install --locked evcxr_jupyter
41+
RUN . "$HOME/.cargo/env" && evcxr_jupyter --install
42+
```
43+
44+
Build It.
45+
46+
Run it.
47+
48+
Try it out:
49+
50+
```rust
51+
println!("Hello World!");
52+
```
53+
54+
HINT:
55+
56+
This method installs all the kernel related resources inside the default homedir.
57+
58+
Therefore this will not work inside deployments where an empty volume is mounted as homedir, e.g. in default z2jh JupyterHub Deployments.
2759

2860
# Config Changes
2961

3062
* Where to put them
63+
You may put it in `~/.jupyter/jupyter_lab_config.py`
64+
65+
But you should put it in `/etc/jupyter/jupyter_lab_config.py` because homedir will be overriden in some infrastructures.
66+
3167

3268
* What to put there
69+
https://docs.jupyter.org/en/latest/use/config.html
3370

34-
* WIP
71+
You find all configuration options here: https://jupyter-server.readthedocs.io/en/latest/other/full-config.html
72+
73+
* How to put there
74+
Create a new local file `jupyter_lab_config.py` and fill it with content.
75+
76+
Then, in your Dockerfile add it either as system wide config (/etc) or user config (~/)
77+
78+
```dockerfile
79+
FROM quay.io/jupyter/minimal-notebook:2025-06-23
80+
81+
COPY --chown=root:root jupyter_lab_config.py /etc/jupyter/jupyter_lab_config.py
82+
83+
```
3584

3685
# Persistent Data
3786

@@ -41,12 +90,16 @@ Now we know how to include changes, we will build something more complex and loo
4190

4291
## External persistent Data
4392

93+
* Depends on your environment
94+
4495
* WIP
4596

4697
## Large Data
4798

4899
* Don't include it into your Image!
49100

101+
* S3
102+
50103
* WIP
51104

52105
## Sensitive Data (?)
@@ -55,8 +108,74 @@ Now we know how to include changes, we will build something more complex and loo
55108

56109
# Application Proxies
57110

58-
* E.G. installing `code-server`
59-
60-
# (WIP)
61-
62-
* WIP
111+
Install the pip `jupyter_server_proxy`
112+
113+
Download code-server from Github https://github.com/coder/code-server/releases
114+
115+
```
116+
wget -qO- 'https://github.com/coder/code-server/releases/download/v4.101.2/code-server-4.101.2-linux-amd64.tar.gz' | tar xzvf - -C code-server --strip-components 1
117+
```
118+
119+
Configure the proxy server application in `/etc/jupyter/jupyter_lab_config.py`:
120+
121+
```python
122+
c.ServerProxy.servers = {
123+
"code-server": {
124+
"command": [
125+
"/opt/code-server/bin/code-server",
126+
"--auth=none",
127+
"--socket={unix_socket}",
128+
"--disable-telemetry",
129+
"--disable-update-check"
130+
],
131+
"unix_socket": True,
132+
"timeout": 30,
133+
"absolute_url": False,
134+
"raw_socket_proxy": False,
135+
"launcher_entry": {
136+
"enabled": True,
137+
"title": "Code",
138+
"icon_path": "/opt/code-server/src/browser/media/favicon.svg"
139+
}
140+
}
141+
}
142+
```
143+
144+
Extend your Dockerfile:
145+
146+
```dockerfile
147+
FROM quay.io/jupyter/minimal-notebook:2025-06-23
148+
149+
USER root
150+
RUN apt update \
151+
&& apt install -y build-essential \
152+
&& apt clean
153+
154+
USER ${NB_USER}
155+
ADD --chmod=755 https://sh.rustup.rs /tmp/rustup.sh
156+
RUN /tmp/rustup.sh -v -y
157+
RUN . "$HOME/.cargo/env" && cargo install --locked evcxr_jupyter
158+
RUN . "$HOME/.cargo/env" && evcxr_jupyter --install
159+
160+
USER root
161+
ARG CS_URL=https://github.com/coder/code-server/releases/download/v4.101.2/code-server-4.101.2-linux-amd64.tar.gz
162+
ARG CS_PATH=/opt/code-server
163+
RUN mkdir "${CS_PATH}"
164+
RUN wget -qO- "${CS_URL}" | tar xzvf - -C "${CS_PATH}" --strip-components 1
165+
COPY --chown=root:root jupyter_lab_config.py /etc/jupyter/jupyter_lab_config.py
166+
167+
USER ${NB_UID}
168+
RUN pip install jupyter_server_proxy
169+
```
170+
171+
You may install any other arbitrary server applications this way too, e.g. RStudio.
172+
173+
# Exercise
174+
175+
Why is the rust installation in step 1 of this tutorial problematic in case this notebook is served via JupyterHub?
176+
177+
--> it installs rust in homedir
178+
179+
Build a Customized JupyterLab with an available rust kernel even in JupyterHub szenario.
180+
181+
--> Dockerfile here

topics/teaching/tutorials/jbt-galaxy/tutorial.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,33 @@ contributors:
1919

2020
(WIP)
2121

22+
# Make your Image available
23+
24+
E.g. on Docker Hub, Quay, GitLab or any other public accessible Registry
25+
2226
# Create a new interactive tool definition (xml)
2327

24-
# Include your new interactive tool definition into your galaxy installation
28+
--> You may take the available Jupyter Notebook tool definition as starting point: https://github.com/galaxyproject/galaxy/blob/dev/tools/interactive/interactivetool_jupyter_notebook.xml
29+
30+
--> Tweak it to your needs
31+
32+
--> Adjust the container image to point to your container image on the registry.
33+
34+
# Include your new interactive tool definition into your galaxy installation
35+
36+
Official docs: https://docs.galaxyproject.org/en/master/admin/special_topics/interactivetools.html
37+
38+
--> Include your newly created definition in your `config/tool_conf.xml` like described in the docs:
39+
40+
```xml
41+
...
42+
<toolbox monitor="true">
43+
...
44+
<section id="interactivetools" name="Interactive tools">
45+
...
46+
<tool file="PATH_TO_YOUR_NEWLY_CREATED_TOOL_DEFINITION" />
47+
...
48+
</section>
49+
...
50+
</toolbox>
51+
```

0 commit comments

Comments
 (0)