Background
Jupyter Lab is an open source web-based IDE for notebooks with Python and R support, geared towards the data science crowd. It’s a powerful, mature application with a potentially complex configuration. Our requirement was to deliver Jupyter Lab to users so that each user would have their own isolated “instance .” There is an off-the-shelf solution for this called Jupyter Hub that probably makes the most sense for your organization. This example will be a proof of concept on how you could roll your solution.
Step 1–Jupyter Lab Docker
If you aren’t familiar with Docker, we’re going to be using it a lot here, so check out some guides
Our first step will be getting Jupyter Lab up and running in a container. There are many Docker images available on (Docker hub)[https://hub.docker.com/] for Jupyter Lab, but since we’re rolling everything ourselves, we might as well make our own image. It also gives us more control over our code–it’s also a pretty simple Dockerfile.
FROM ubuntu:20.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
python3-pip \
python3-dev \
&& python3 -m pip install jupyterlab
EXPOSE 8888
ENTRYPOINT ["jupyter", "lab", "--ip=0.0.0.0", "--port", "8888", "--allow-root"]
There are probably some good arguments for why you should use alpine or something else as the base image here, but I’m a sucker for ubuntu. Since this isn’t a Docker tutorial, I’m not going to go into great detail here about what each line in this Dockerfile does, but assume that it installs Jupyter Lab and configures it to run at port 8888. We’ll expand on the Jupyter Lab config (and make some changes) later, but for now, this works fine.
We’re going to use Docker compose to run this. Our compose file looks like
version: "3"
services:
jupyter:
build:
context: .
dockerfile: Dockerfile
image: jupyter
container_name: jupyter
ports:
- 8888:8888
We can run this with docker compose up
This will start our Jupyter Lab container and make it available at http://127.0.0.1:8888/lab/
Awesome! We’re part of the way there!
Next, we need to put together an Nginx docker file.
While we could use the official Nginx image, in keeping with the theme, we’re going to create our own Nginx image (and it’s also really simple)
FROM ubuntu:20.04
RUN apt-get update && apt-get -y install nginx
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 8000
ENTRYPOINT ["/usr/sbin/nginx"]
Pretty straightforward. Our config file is also pretty simple. We’re going to use port 8000, and we’re going to simply forward all requests directly to Jupyter lab.
daemon off;
error_log /dev/stdout info;
events {}
http {
access_log /dev/stdout;
upstream upstream_jupyter {
server jupyter:8888;
keepalive 32;
}
server {
listen 8000;
server_name localhost;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_hide_header "X-Frame-Options";
proxy_pass http://upstream_jupyter;
}
}
}
The final piece that will tie these together is our docker-compose file. Our docker-compose is pretty simple as well.
By using Docker compose, the networking between the containers is handled for us, and we can point the jupyter
as the service
name in our nginx.conf
version: "3"
services:
jupyter:
build:
context: .
dockerfile: Dockerfile
image: jupyter
container_name: jupyter
ports:
- 8888:8888
nginx:
build:
context: .
dockerfile: nginx.Dockerfile
image: jupyter-nginx
container_name: nginx
ports:
- 8000:8000
volumes:
- nginx.conf:/etc/nginx/nginx.conf
Now, let’s head to http://127.0.0.1:8000, and…
Awesome! We’re being proxied to Jupyter Lab. But, we see a page requiring token auth. This is because Jupyter is currently configured to enforce this. In the next post, we’ll deal with this and some other things regarding permissions, creating a user, and making a task definition for deploying this configuration to ECS.