Cet article décrit comment configurer Jupyter derrière le proxy inverse Nginx, car une telle configuration n'est pas très évidente pour beaucoup de gens. Il existe de nombreux problèmes et points essentiels sur GitHub, et il est difficile de choisir la bonne solution à ce problème. En outre, vous pouvez trouver de nombreux articles différents décrivant comment le faire, mais la plupart d'entre eux sont obsolètes et ne couvrent pas bien la configuration CORS.
Le sujet étant toujours d'actualité, j'ai décidé de renouveler l'article et de simplifier la configuration.
Merci pour vos commentaires ci-dessous, Andrew Barker . Consultez la version mise à jour de l'article.
Configuration Docker
Dans cette section de l'article, nous aborderons le cas où vous pourriez avoir besoin de lancer Jupyter ou JupyterHub dans un environnement Docker standard.
Configuration de JupyterHub
Commençons par créer un dossier dans lequel nous placerons tous nos fichiers de configuration.
Voici notre structure finale :
mkdir docker
tree docker
docker
├── docker-compose.yaml
├── jupyter_notebook_config.py
└── nginx.conf
Docker Compose
Pour simplifier le tout, j'ai créé docker-compose.yaml
, qui décrit nos services :
version: "3.7"
services:
nginx:
image: nginx:alpine
volumes:
- "./nginx.conf:/etc/nginx/nginx.conf:ro"
ports:
- 8080:8080
links:
- "jupyterhub"
jupyterhub:
image: jupyterhub/jupyterhub
container_name: jupyterhub
volumes:
- "./jupyter_notebook_config.py:/root/.jupyter/jupyter_notebook_config.py:ro"
La configuration est simple :un simple petit conteneur Nginx Docker devant Jupyterhub.
Les deux ont été lancés à partir de leurs dernières versions.
Configuration Nginx
Nginx est assis sur le port 8080 et écoute sur le port 8080 aussi.
TRÈS IMPORTANT : nginx.conf
contient la configuration du proxy inverse.
Si votre Nginx est installé sur un port autre que 80 ou 443 , vous devez utiliser la directive de configuration suivante :
proxy_set_header Host $host:$server_port;
Pour Nginx, qui se trouve sur les ports par défaut, utilisez default
configuration :
proxy_set_header Host $host;
Si vous faites une erreur ici, vous commencerez à recevoir Blocking Cross Origin API request for /api/contents
messages d'erreur.
Encore une fois, la principale raison de ces messages n'est pas l'égalité des ports pour la liaison de service et l'exportation pour les conteneurs Nginx.
Voici mon nginx.conf
pour écouter sur le port 8080
:
worker_processes 1;
events { worker_connections 1024; }
http {
sendfile on;
upstream ml {
server jupyterhub:8000;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 8080;
location / {
proxy_pass http://ml;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# websocket headers
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
}
Configuration Jupyter
Pour la configuration de JupyterHub, nous utiliserons la configuration suivante placée dans /root/.jupyter/jupyter_notebook_config.py
:
# get the config object
c = get_config()
# JupyterHub listen address
c.JupyterHub.hub_ip = '0.0.0.0'
# JupyterHub connect hostname.
# In our case it's 'jupyterhub' by the name of the service from docker-compose.yaml
c.JupyterHub.hub_connect_ip = 'jupyterhub'
# Location for users notebooks
c.Spawner.notebook_dir = '~/'
Lancement de Jupyrter derrière le proxy Nginx
Je n'ai pas eu beaucoup de temps pour créer un nouveau conteneur et/ou jouer avec les paramètres d'authentification des utilisateurs. L'objectif principal est de fournir une solution pour Bloquer les requêtes d'API Cross-Origin pour /api/contents problèmes.
Alors, voici comment vous pouvez lancer cette configuration :
docker-compose up -d
Connectez-vous aux conteneurs qui viennent d'être lancés, créez un utilisateur et installez le notebook paquet :
docker exec -it jupyterhub /bin/bash
adduser
pip install notebook
Vous pouvez maintenant vous connecter à JupterHub et utiliser votre nom d'utilisateur et votre mot de passe créés comme identifiants de connexion.
Configuration Docker Swarm
Dans cette section de l'article, nous aborderons le cas où vous pourriez avoir besoin de lancer Jupyter ou JupyterHub en mode Docker Swarm.
Modifions légèrement notre dossier de projet :
.
├── .env
├── docker-compose.yaml
├── jupyterhub
│ ├── Dockerfile
│ ├── jupyterhub_config.py
└── nginx
└── nginx.conf
3 directories, 5 files
Docker Compose (essaim)
Voici comment notre docker-compose.yaml
le fichier ressemblera à :
version: "3.7"
services:
# Configuration for reverse proxy
nginx:
image: nginx:alpine
volumes:
- "./nginx/nginx.conf:/etc/nginx/nginx.conf:ro"
ports:
- 8080:8080
networks:
default:
jupyterhub_network:
aliases:
- nginx
# Configuration for Hub+Proxy
jupyterhub:
env_file: .env
build: jupyterhub
image: jupyterhub_customized
hostname: jupyterhub
volumes:
- "./jupyterhub/jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py:ro"
- "/var/run/docker.sock:/var/run/docker.sock"
ports:
- 8000:8000
networks:
default:
jupyterhub_network:
aliases:
- jupyterhub
environment:
# Name of the Docker image for the single-user servers
DOCKER_JUPYTER_IMAGE: ${DOCKER_JUPYTER_IMAGE}
# The name of the Docker network used by the services
DOCKER_NETWORK_NAME: ${COMPOSE_PROJECT_NAME}_jupyterhub_network
# The IP address of the Hub service within the docker network
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
# Configuration for the single-user servers
jupyterlab:
image: ${DOCKER_JUPYTER_IMAGE}
command: echo
networks:
jupyterhub_network:
driver: overlay
volumes:
jupyterhub_data:
Les variables d'environnement Docker-compose sont définies dans .env
fichier :
# Name of our Docker Compose project
COMPOSE_PROJECT_NAME="jupyterhub"
DOCKER_JUPYTER_IMAGE="jupyterhub/singleuser:2.2"
Configuration JupyterHub (essaim)
Nous devons créer notre propre image personnalisée de JupyterHub pour inclure automatiquement dockerspawner, dummyauthenticator et tout autre module dont vous pourriez avoir besoin (par exemple, pour prendre en charge différentes méthodes d'authentification).
# Do not forget to pin down the version
FROM jupyterhub/jupyterhub
# Install dependencies (for advanced authentication and spawning)
RUN pip install \
dockerspawner \
jupyterhub-dummyauthenticator
Nous devons également fournir la configuration correcte pour JupyterHub :
import os
NETWORK_NAME = os.environ['DOCKER_NETWORK_NAME']
DOCKER_JUPYTER_IMAGE = os.environ['DOCKER_JUPYTER_IMAGE']
# get the config object
c = get_config()
c.ConfigurableHTTPProxy.should_start = True
c.JupyterHub.authenticator_class = 'dummyauthenticator.DummyAuthenticator'
c.JupyterHub.hub_ip = '0.0.0.0'
c.JupyterHub.hub_connect_ip = 'jupyterhub'
c.JupyterHub.spawner_class = 'dockerspawner.SwarmSpawner'
c.JupyterHub.tornado_settings = {'slow_spawn_timeout': 30}
c.SwarmSpawner.image = DOCKER_JUPYTER_IMAGE
c.SwarmSpawner.network_name = NETWORK_NAME
c.SwarmSpawner.remove_containers = True
c.Spawner.cmd = ["jupyter", "labhub"]
c.Spawner.args = ['--allow-root']
c.Spawner.notebook_dir = '~/'
c.Spawner.debug = True
c.SwarmSpawner.debug = True
c.SwarmSpawner.host_ip = '0.0.0.0'
c.SwarmSpawner.http_timeout = 300
c.SwarmSpawner.start_timeout = 300
#c.JupyterHub.log_level = 00
#c.ConfigurableHTTPProxy.debug = True
Pour plus d'informations, je vous recommande vivement de consulter les liens suivants :
- Utilisation de SwarmSpawner (exemple officiel)
- Documentation officielle de SwarmSpawner (JupyterHub)
- Déployer un serveur JupyterHub conteneurisé avec Docker (article)
- Comment exécuter JupyterHub dans un environnement docker swarm à l'aide de swarmSpawner (article)
Configuration Nginx (essaim)
La configuration de Nginx restera inchangée, mais plaçons-la ici pour que l'exemple soit complet :
worker_processes 1;
events { worker_connections 1024; }
http {
sendfile on;
upstream ml {
server jupyterhub:8000;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 8080;
location / {
proxy_pass http://ml;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# websocket headers
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
}
Exemple de démonstration
Pour lancer la démo fournie, exécutez la commande suivante :
docker-compose build
docker-compose up
Dès le démarrage du service, connectez-vous à l'adresse IP externe de votre serveur sur le port 8080 :
Vous devriez voir la sortie de console suivante :
Dans le navigateur, vous devriez voir la page suivante :
Utilisez n'importe quel nom d'utilisateur et ne fournissez aucun mot de passe. Cliquez sur Connexion et vous serez redirigé vers l'environnement de laboratoire utilisateur :
Résumé
J'espère que ce petit mot vous aidera à gagner du temps. Si vous l'avez trouvé utile, s'il vous plaît, aidez-le à le diffuser dans le monde !
Restez à l'écoute !