构建多用户隔离的 Jupyter Lab 单服务器原生环境
我们需要:
GPU
服务器上,建立一个用户隔离的 Jupyter 远程 Web 环境我们目前拥有 NVIDIA 1080 TI GPU 的图形卡,为了方便的使用该 GPU 硬件,和相关驱动、加速程序,以及依赖这些程序的库、框架、应用,我们做出了如下选择:
9.0
;TensorFlow 的预编译包同样也只支持 CUDA 9.0
。考虑到9.0
版本的 CUDA 的预编译包仅支持 Ubuntu 1604
与 1704
,最终选择的是支持时间更长的 Ubuntu 1604
x86_64bit
, 且安装其默认图形界面(桌面版)。主要硬件/软件环境:
装配好硬件和操作系统之后,按照以下的记录安装/配置步骤,进行操作。期间须保证该计算机可以畅通地连接到互联网:
在终端执行:
sudo apt update
sudo apt upgrade --auto-remove
重启
NVidia 官方驱动的安装比较繁琐,涉及到 Linux
的 modprobe
与 initramfs
的修改,本文不予记载。
建议采用 Graphics Drivers
软件仓库提供的驱动:
在终端执行:
sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt-get update
通过图形界面的"系统设置"指定系统要使用的驱动:
NVIDIA Corporation
下最新的长期支持版驱动版本(访问 https://www.nvidia.com/object/unix.html 查看 Unix
驱动的版本信息)9.0
访问 https://developer.nvidia.com/cuda-90-download-archive ,根据具体环境选择安装方式,并按照说明进行操作。
建议的选择:
Operating System | Architecture | Distribution | Version | Installer Type |
---|---|---|---|---|
Linux | x86_64 | Ubuntu | 16.04 | deb (network) |
按照建议选择下载安装文件后的安装步骤:
sudo dpkg -i cuda-repo-ubuntu1704_9.0.176-1_amd64.deb
sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1704/x86_64/7fa2af80.pub
sudo apt update
sudo apt install -y cuda-9-0
⚠ 警告:
要固定 CUDA 版本,避免意料之外的升级,我们可以这样操作:
sudo apt-mark hold cuda-repo-ubuntu1604
访问 cuDNN 下载页面 ,根据具体环境选择安装方式,并按照说明进行安装。
我们的环境需要的版本是:
要下载和安装的软件包有:
访问 NCCL 下载页面 ,根据具体环境选择安装方式,并按照说明进行安装。
我们的环境需要的版本是:
建议下载和安装该软件包的离线版:
Jupyter 是 Python 程序,需要的版本是 3.4
及以上。
我们有三种选择可用于安装 Python 3
:
1604
默认软件仓库提供的 Python 3.5
。3.6
。目前不推荐使用 3.7
,因为 TensorFlow 目前没有此版本的官方支持。其中,1, 2 两种方式是将 Python 安装到系统全局,而 3 是用户级的安装。
具体的安装方法是:
apt 安装:
安装操作系统默认软件仓库提供的 Python 3
:
sudo apt install -y python3 python3-setuptools python3-pip python3-dev build-essential
源码安装:
以 Python 3.6
为例:
在操作系统上安装编译构建工具和相关依赖软件的开发包:
sudo apt install -y build-essential libssl-dev zlib1g-dev libbz2-dev liblzma-dev libsqlite3-dev libdb-dev libgdbm-dev libncurses5-dev libreadline-dev libexpat1-dev tk-dev
从 https://python.org/ 下载最新的 Python3.6
源代码压缩包(此处以3.6.6
为例),解压、构建、安装:
wget https://www.python.org/ftp/python/3.6.6/Python-3.6.6.tgz
tar -xf Python-3.6.6
cd Python-3.6.6
./configure --enable-optimizations
make
sudo make altinstall
⚠ 警告:
一定 要使用
make altinstall
命令安装,而 不是make install
,否则可能破环操作系统。
检查 Python 3.6
是否安装成功:
$ which python3.6
/usr/local/bin/python3.6
$ python3.6 --version
Python 3.6.6
确保安装了 pip 模块:
sudo -H python3.6 -m ensurepip
这是推荐的方式。与以上两种方式不同的是,Conda 将 Python 安装到用户环境中,而不是整个操作系统的全局环境。
所以,应选定一个已有的操作系统账户、或者新建一个专门的账户,专门用于安装这些软件包。假定我们使用名为 jupyterhub
的账户,如果它还不存在,可以这样新建:
sudo adduser jupyterhub
设置好这个用户的密码后,切换到该账户或者以该账户登录:
$ su jupyterhub
Password:
安装 Conda (以 Anaconda3 5.2.0
为例,这是目前最新的 Python 3.6
版本):
$ wget https://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh
./Anaconda3-5.2.0-Linux-x86_64.sh
按照提示,使用默认值进行安装即可。
当安装程序询问
>>> Do you wish the intaller to pretend the Anaconda3 install location to PATH in your /home/jupyterhub/.bashrc ? [yes|no]
的时候,输入 yes
安装完毕后,执行:
source ~/.bashrc
此时,该用户(jupyterhub
)的 Python 执行文件路径应是:
$ which python
/home/jupyterhub/anaconda3/bin/python
ℹ 说明:
下文中,我们将用
$PYTHON
代表以上步骤中安装的 Python 的可执行文件。小心多个python
并存的情况。具体以实际情况为准。就上面几种不同的安装方式而言:
- apt 安装:
$PYTHON
绝对路径是:/usr/bin/python3
- 源码安装:
$PYTHON
绝对路径是:/usr/lobal/bin/python3.6
- Conda:
$PYTHON
绝对路径是:/home/jupyter/anaconda3/bin/python
Conda 是推荐的方式
如果 Python 是全局安装的:
使用 Pip 安装这些软件到系统全局环境:
sudo -H $PYTHON -m pip install jupyter jupyterlab jupyterhub
⚠ 警告:
强烈建议使用
sudo
以超级用户执行安装,不要pip install --user
,否则以超级用户的身份运行 Jupyterhub 的时候,会找不到包 (当然可以修改PYTHONPATH
,以及各种 Hack 方法解决这个问题,但不推荐)。
Conda 已经带有 Jupyter 和 Jupyterlab,故直接安装 Jupyterhub 到该用户的 Base
环境:
conda install -c conda-forge jupyterhub
安装之后,我们还需要安装程序 configurable-http-proxy
到操作系统全局环境。之所以需要系统级全局安装,是因为我们将要以 root
身份,以后台服务的形式运行 Jupyterhub ,且 Jupyterhub 在自动启动 configurable-http-proxy
时不具备指定路径的能力。
configurable-http-proxy
是一个 Node.js 程序,它需要的 Node.js 版本大于 Ubuntu 1604
默认仓库提供的。所以我们首先需要这样安装 Node.js 的较高版本。
如果采用全局 Python:
应使用 apt 安装 Node.js 最新稳定版(目前是 v10.x
):
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt update
sudo apt install -y nodejs
验证 Node.js 的路径和版本:
$which node
/usr/bin/node
$node --version
v10.15.0
然后通过 npm 全局安装 configurable-http-proxy
:
sudo npm install -g configurable-http-proxy
如果使用 Conda:
上个步骤中,Conda 在安装 Jupyterhub 的时候,已经自动安装了它所需要的 Node.js 以及 configurable-http-proxy
到 Base
环境。
这与我们以 root
在后台运行的目标相悖;且 Jupyterhub 以 root
执行时,无法找到 jupyterhub
用户目录中的 configurable-http-proxy
执行文件,根本无法启动。
要解决这个问题,我们可以为 jupyterhub
用户目录中的 configurable-http-proxy
在操作系统的可执行文件目录建立一个软链接:
sudo ln -s /home/jupyterhub/anaconda3/bin/configurable-http-proxy /usr/local/bin/configurable-http-proxy
这个插件提供了额外的 Jupyterlab 和 Jupyterhub 集成功能。这是一个可选功能。
如果使用的是全局安装的 Python,执行安装命令:
sudo -H $PYTHON -m jupyter labextension install @jupyterlab/hub-extension
如果使用的是 Conda ,注意首先切换到安装 Conda 的用户(之前步骤中新建的用户jupyterhub
):
$ su jupyterhub
Password:
执行安装命令:
$PYTHON -m jupyter labextension install @jupyterlab/hub-extension
生成默认配置文件
将配置文件放到系统目录 /etc
中,之后我们将在启动命令行中指定这个路径。
$ jupyterhub --generate-config
Writing default config to: jupyterhub_config.py
$ sudo mkdir -p /etc/jupyterhub
$ sudo mv -a jupyterhub_config.py /etc/jupyterhub
修改配置文件
修改 c.LocalProcessSpawner.shell_cmd
,默认以 Bash
“登录”方式启动 sing-user
子进程:
c.LocalProcessSpawner.shell_cmd = ['bash', '-l', '-c']
修改 c.Spawner.cmd
,以支持 jupyterlab-hub
插件。
c.Spawner.cmd = ['jupyter-labhub']
ℹ 说明:
该步骤是可选的。如果不使用
jupyterlab-hub
插件,就不要修改这个配置。
现在,我们尝试运行 Jupyterhub 。我们将以超级用户的身份执行,按照上个步骤的配置文件,在全部IP地址监听:
sudo $PYTHON -m jupyterhub -f /etc/jupyterhub/jupyterhub_config.py --ip "0.0.0.0"
其中:
-f /etc/jupyterhub/jupyterhub_config.py
: 指定配置文件--ip "0.0.0.0"
: 表示在所有的 IPv4 地址上监听8000
ℹ 说明:
如果 Python 执行文件来自 Conda 的非系统全局安装,例子中的
$PYTHON
应提供完整的绝对路径,如/home/jupyterhub/anaconda3/bin/python
可以用 Systemd, Initd 等将这个程序设置成后台服务。此处,我们选用 Supervisor。
首先安装 Supervisor:
sudo apt install -y supervisor
然后为 Jupyterhub 新建服务配置文件 /etc/supervisor/conf.d/jupyterhub.conf
:
echo_supervisord_conf | sudo tee /etc/supervisor/conf.d/jupyterhub.conf
修改配置文件 —— 针对上文提到的不同的 Python 安装方式,配置文件的 program
段和command
属性值分别是:
[program:jupyterhub]
command=python3 -m jupyterhub -f /etc/jupyterhub/jupyterhub_config.py --ip 0.0.0.0
从源代码安装的 Python 3.6
:
[program:jupyterhub]
command=python3.6 -m jupyterhub -f /etc/jupyterhub/jupyterhub_config.py --ip 0.0.0.0
[program:jupyterhub]
command=/home/jupyterhub/anaconda3/bin/python -m jupyterhub -f /etc/jupyterhub/jupyterhub_config.py --ip 0.0.0.0
ℹ 说明:
- 可以直接使用
jupyterhub
命令,不一定要通过python -m jupyter
启动。注意执行文件的路径和所属用户。- 各参数可以按照实际需求进行修改
最后重加载 supervisor 配置,并使之生效:
sudo supervisorctl reread
sudo supervisorctl update jupyterhub
要查看服务的运行情况,可以执行:
sudo supervisorctl status
现在,Jupyterhub 已经作为服务程序,以超级用户的身份在运行了。
但我们还是无法正常访问——因为我们还没有给 Jupyterhub 添加用户。
我们采用 Jupyterhub 默认的 single-user
模式,其登录用户就是操作系统账户。
要新建 Jupyterhub 用户,我们首先需要新建一个操作系统账户,假定其用户名为 newuser
:
sudo adduser newuser
设置好用户密码等信息后,切换到这个用户:
$ su newuser
Password:
我们的目标是为每个用户提供独立的机器学习环境,故不宜使用操作系统全局 Python 。
为了避免互相干扰,我们的选择有:
jupyter-lab
或者 jupyter-labhub
命令启动用户环境。启动后,让每个用户使用 pip 以用户模式(pip install --user <pacakge>
)安装软件包。Base
环境下的 jupyter-lab
或者 jupyter-labhub
命令启动用户环境。启动后,使用 Conda 直接在 Base
环境下安装软件包,或者使用 Conda Base
环境下的 pip 安装软件包。考虑到 Conda 可以支持 pip,而反之不可,我们选用第二种方法。
以 Anaconda3 5.2.0
为例:
wget https://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh
./Anaconda3-5.2.0-Linux-x86_64.sh
按照提示,使用默认值进行安装。
当安装程序询问
>>> Do you wish the intaller to pretend the Anaconda3 install location to PATH in your /home/newuser/.bashrc ? [yes|no]
的时候,输入 yes
安装完毕后,执行:
source ~/.bashrc
此时,该用户(newuser
)的 Python 执行文件路径应是:
$ which python
/home/newuser/anaconda3/bin/python
下面,十分重要的一步:我们还需要修改这个用户 ~/.profile
,将 Conda
的Base
环境可执行目录附加到PATH
环境变量,以便 Jupyterhub 以该账户启动子进程时可以找到 jupyter-lab
或 jupyter-labhub
可执行文件:
echo "PATH=\"/home/newuser/anaconda3/bin:$PATH\"" >> ~/.profile
Conda 已经带有 Jupyter 和 Jupyterlab,直接在这个用户的Conda Base
环境安装 Jupyterhub 即可:
conda install -c conda-forge jupyterhub
jupyter labextension install @jupyterlab/hub-extension
如果要使用登录账户白名单,在 jupyterhub_config.py
配置文件中,将用户名加入c.Authenticator.whitelist
集合:
c.Authenticator.whitelist = {'newuser'}
如果要将该用户设置为管理员,在 jupyterhub_config.py
配置文件中,将用户名加入c.Authenticator.admin_users
集合:
c.Authenticator.admin_users = {'newuser'}
ℹ 说明:
- 注意将
newuser
换成实际的值。- 如果安装了
jupyterlab-hub
插件,登录后在图形界面的hub
菜单中有额外选项。
现在,通过浏览器访问 Jupyterhub 的 Web 界面,如 http://localhost:8000/,使用操作系统账户 newuser
的账户密码登录,就可以直接使用 Jupyterlab 的全部功能了
直接删除操作系统账户即可
此处的“内核”指的是Jupyter的kernel
。
到目前为止,我们已经让一个新用户在全局 Python 以及 Conda 的 Base
环境中运行了 Jupyterlab。此时,如果登录系统,所有的笔记将默认以这个Python环境的内核运行。如果需要多个不同Python版本/环境,或者其它语言的运行时,我们就得为这个用户安装多个Jupyter内核。
要让该用户的 Jupyterlab 使用另一个新的 Conda 环境,我们需要:
新建一个 Conda 环境。例如,新建一个名为 mypy36env
, Python 版本为 3.5
的环境:
conda create --name mypy35env python=3.5
在新的环境中安装 ipykernel
conda activate mypy35env
conda install pip ipykernel
python -m ipykernel install --user --name mypy35env --display-name "Python 3.5(conda:mypy35env)"
现在,刷新 Jupyterlab 页面,可以看到新的 kernel
。
要删除这个 Jupyter Kernel,执行:
jupyter kernelspec uninstall mypy35env
如果要连同 Conda 运行环境一同删除,执行:
conda deactivate
conda env remove -n mypy35env
用户通过 Jupyterlab 的笔记或者终端,使用 Conda 或 pip 安装。注意不要搞错 Conda、 venv 环境。
由于各个用户的 Jupyterlab 环境是隔离的,所以可以自行安装,不会相互干扰。
用户和系统的 Jupyter 可以分别升级, Conda 和 pip 都可以。当然,前提是系统的 Jupyterhub 与用户的 jupyterlab 能够兼容。
理论上,用户可以通过 Jupyterlab 终端,做权限允许的任何事情,安装任何软件,包括 Jupyter Kernel。
但是考虑到我们一般不为 Jupyterhub 用户配置系统级的安装权限,用户应优先考虑使用 Conda ,在本用户范围之内安装所需软件。
如果通过其它途径的安装软件,也应尽量考虑让该方案在用户权限范围之内可行。