Python在现代的编程语言中占据了很大的比重,在数据分析领域,python是最常用的语言。根据tiobe指数, Python已经攀升至第一。如果我们有Python环境需求,在本地我们可以使用ipython等工具,但是如果我们需要在团队中使用, JupyterHub就派上用场了。

JupyterHub是一个开源的多用户Jupyter Notebook服务器,它可以让你在一个地方管理多个用户的Jupyter Notebook。关于Jupyter Notebook, JupyterLab 以及 JupyterHub的差异,可以参考官方的介绍,简言之, Jupyter Notebook是经典的交互形式,JupyterLab是新的交互形式,JupyterHub则用在服务端管理多用户的Notebook。

环境准备

本次我们使用Ubuntu 22.04版本作为服务器,使用pyenv 作为Python版本管理工具。参考官方README文档,JupyterHub还依赖configurable-http-proxy, 我们还需要nodejs环境,我们使用nvm 进行安装。

通过SSH登录到系统,使用命令cat /etc/os-release查看系统版本信息。运行curl https://pyenv.run | bash安装pyenv。该命令会下载pyenv的安装脚本,并执行安装。最终安装在用户目录.pyenv中。

安装之后我们需要在shell中添加pyenv的环境变量。

bash 可以使用如下命令:

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc

zsh 可以使用如下命令:

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc

通过exec "$SHELL"使配置生效。我们可以使用pyenv --version来检测安装是否成功。

最后我们使用pyenv install 3.10安装Python环境,然后通过pyenv versions查看当前的Python环境。

pyenv versions
  system
  3.9.10
* 3.10.13 (set by /home/ubuntu/.python-version)

接下来我们安装nvm,运行curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash。同样我们运行exec "$SHELL"使配置生效。通过下面的命令安装nodejs版本18,然后安装configurable-http-proxy

nvm install 18
nvm use 18
npm install -g configurable-http-proxy

通过which configurable-http-proxy找到其安装的位置,最后在配置systemd服务的时候需要用上。这里我们拿到的路径是/home/ubuntu/.nvm/versions/node/v18.19.0/bin/configurable-http-proxy

至此我们完成了初步的环境搭建。

安装JupyterHub

运行下面的命令安装JupyterHub,同时安装jupyterlab与jupyter。

pip install jupyterhub
pip install --upgrade jupyterlab jupyter

运行命令jupyterhub可以尝试环境是否安装正常,可以看到如下日志输出。

[I 2023-12-25 14:06:11.122 JupyterHub app:2859] Running JupyterHub version 4.0.2
[I 2023-12-25 14:06:11.122 JupyterHub app:2889] Using Authenticator: jupyterhub.auth.PAMAuthenticator-4.0.2
[I 2023-12-25 14:06:11.122 JupyterHub app:2889] Using Spawner: jupyterhub.spawner.LocalProcessSpawner-4.0.2
[I 2023-12-25 14:06:11.122 JupyterHub app:2889] Using Proxy: jupyterhub.proxy.ConfigurableHTTPProxy-4.0.2
[I 2023-12-25 14:06:11.128 JupyterHub app:1664] Loading cookie_secret from /home/ubuntu/jupyterhub_cookie_secret
[I 2023-12-25 14:06:11.191 JupyterHub proxy:556] Generating new CONFIGPROXY_AUTH_TOKEN
[I 2023-12-25 14:06:11.200 JupyterHub app:1984] Not using allowed_users. Any authenticated user will be allowed.
[I 2023-12-25 14:06:11.220 JupyterHub app:2928] Initialized 0 spawners in 0.002 seconds
[I 2023-12-25 14:06:11.228 JupyterHub metrics:278] Found 0 active users in the last ActiveUserPeriods.twenty_four_hours
[I 2023-12-25 14:06:11.228 JupyterHub metrics:278] Found 0 active users in the last ActiveUserPeriods.seven_days
[I 2023-12-25 14:06:11.229 JupyterHub metrics:278] Found 0 active users in the last ActiveUserPeriods.thirty_days
[W 2023-12-25 14:06:11.230 JupyterHub proxy:746] Running JupyterHub without SSL.  I hope there is SSL termination happening somewhere else...

配置及服务

在上述的安装过程中,我们已经安装了jupyterhub,但是我们还需要配置jupyterhub来使其更符合服务需求。我们将相关配置文件放在/etc/jupyterhub/目录下,包括jupyterhub_config.pyjupyterhub_cookie_secret等文件。

首先使用如下命令生成默认配置文件:

jupyterhub --generate-config

然后使用命令替换其中的配置:

# inline replace
sed -i "s#.*c.Authenticator.allowed_users.*#c.Authenticator.allowed_users = {'`whoami`'}#" jupyterhub_config.py
sed -i "s#.*c.Authenticator.admin_users.*#c.Authenticator.admin_users = {'`whoami`'}#" jupyterhub_config.py
sed -i "s#.*c.JupyterHub.cookie_secret_file.*#c.JupyterHub.cookie_secret_file = '/etc/jupyterhub/jupyterhub_cookie_secret'#" jupyterhub_config.py
sed -i "s#.*c.JupyterHub.db_url.*#c.JupyterHub.db_url = 'sqlite:////etc/jupyterhub/jupyterhub.sqlite'#" jupyterhub_config.py

# append line for c.ConfigurableHTTPProxy.pid_file
sed -i "\#.*c.JupyterHub.pid_file.*#a c.ConfigurableHTTPProxy.pid_file = '/tmp/jupyterhub-proxy.pid'" jupyterhub_config.py

其中whoami是当前用户的用户名,如果是多人团队,可以动态调整该列表。

然后创建/etc/jupyterhub目录并将该配置文件移动至该目录:

sudo mkdir /etc/jupyterhub/
sudo chown -R $USER:$USER /etc/jupyterhub/
mv jupyterhub_config.py /etc/jupyterhub/

最后使用如下命令创建systemctl服务,并启动

sudo tee /etc/systemd/system/jupyterhub.service << END
[Unit]
Description=JupyterHub
After=syslog.target network.target

[Service]
User=ubuntu
Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/home/ubuntu/.nvm/versions/node/v18.19.0/bin:/home/ubuntu/.pyenv/versions/3.10.13/bin"
ExecStart=/home/ubuntu/.pyenv/versions/3.10.13/bin/jupyterhub -f /etc/jupyterhub/jupyterhub_config.py

[Install]
WantedBy=multi-user.target
END

sudo systemctl daemon-reload
sudo systemctl start jupyterhub
sudo systemctl enable jupyterhub

其中User是服务运行的用户,Environment是环境变量,我们将nvm安装的nodejs的bin目录配置到环境变量中,这样jupyterhub就能找到之前通过npm安装的工具configurable-http-proxy

大部分时候虚拟云主机都是通过SSH进行登录,没有默认的密码,此时我们需要使用sudo passwd命令设置当前用户的默认密码。

最后我们将申请域名指向服务器地址,同时使用Caddy作为反向代理,将其配置在/etc/caddy/Caddyfile中,如下

hub.example.com {
    reverse_proxy localhost:8000
}

访问域名,按提示输入用户密码,我们就能够登录到JupyterHub中了。

jupyterhub ui