0%

集群上构建外网可访问的jupyter notebook

预备知识

由PBS系统所管理的集群,一般由一个管理节点mu01和多个计算节点gpu01gpu02gpu02等构成。

通常用户在使用集群进行计算时,一般有两种方案:

  1. 利用qsub提交.sh脚本作为任务,调度任务在某个计算节点运行

执行qsub run.sh

run.sh

1
2
3
4
5
6
7
#!/bin/bash
#PBS -N Notebook
#PBS -W x=GRES:gpu@1
#PBS -l nodes=gpu01:ppn=1
#PBS -l walltime=8:00:00
#PBS -q gpuq
...

其中,以#PBS开头的注释行,将会被qsub读取后作为PBS启动参数,影响到创建的工作空间

  1. 利用qsub启动交互式终端,直接进入计算节点进行操作
1
qsub -I -N Notebook -W x=GRES:gpu@1 -l nodes=gpu01:ppn=1,walltime=8:00:00 -q gpuq

其中,-I指定qsub启动交互式终端而不是提交任务

这两种方法的PBS指令基本相同,从前到后可以依次理解为

graph LR;
A[将任务命名为Notebook] --> B[申请1个GPU环境];
B[申请1个GPU环境] --> C[限制使用gpu01计算节点];
C[限制使用gpu01计算节点] --> D[限制最大时限为8小时];
D[限制最大时限为8小时] --> E[任务提交给gpuq队列];
E[任务提交给gpuq调度器] -->|1| F[执行脚本];
E[任务提交给gpuq调度器] -->|2| G[启动交互式终端];

工作环境

通常情况下,管理节点mu01有外网权限,但没有可用的计算资源,计算节点gpu01有计算资源,但是没有外网权限。

尽管管理节点和计算节点共享相同的计算环境如conda,因为jupyter涉及到从外网访问计算资源,单纯在两者上开启jupyter都不可行。如果在管理节点上直接开启jupyterconda环境将无法访问到显卡。而如果在计算节点上直接开启jupyterconda环境将只能从计算节点被访问。

解决方案

显然,唯一可行的方法就是在计算节点上启动jupyter,然后从管理节点进行访问,通过端口转发,保证外网对于管理节点的http请求,通过管理节点被转发给计算节点上的jupyter服务。

我们利用

ssh -N -f -R $ADMINPORT:localhost:$NOTEBOOKPORT $PBS_O_HOST

创建一条从计算节点到管理节点的反向隧道

其中参数解释如下

参数 说明 备注 需要自定义
-N 不启动终端shell 只创建隧道
-f ssh启动后进入后台
-R 隧道为反向隧道 -L相对
$ADMINPORT 远程端口 实际是管理节点的端口
localhost 本地地址 实际是计算节点的地址
$NOTEBOOKPORT 本地jupyter服务端口 实际是计算节点的端口
$PBS_O_HOST 远程地址 实际是管理节点的地址

在此之后,我们确保管理节点上向$ADMINPORT发出的请求,可以转发到计算节点上的$NOTEBOOKPORT,在计算节点上启动jupyter之后,利用wget http://localhost:$ADMINPORT进行测试(这里的$ADMINPORT填入实际值)。

只要结果不是failed: Connection refused,除某些特殊情况(见备注)以外,一般可以认为端口转发成功。

工作流

构建如下脚本,根据实际情况酌情修改

run_jupyter.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
#PBS -N Notebook
#PBS -W x=GRES:gpu@1
#PBS -l nodes=gpu01:ppn=1
#PBS -q gpuq

cd $PBS_O_WORKDIR
LOCALPORT=8083
NOTEBOOKPORT=8082
NOTEBOOK_LOGFILE=jupyterlog.out

ssh -N -f -R $LOCALPORT:localhost:$NOTEBOOKPORT $PBS_O_HOST

PYTHONPATH="/home/xxx/.conda/envs/jupyter"
$PYTHONPATH/bin/jupyter notebook --port=$NOTEBOOKPORT >> ${NOTEBOOK_LOGFILE} 2>&1

根据实际情况,修改LOCALPORTNOTEBOOKPORTPYTHONPATHNOTEBOOK_LOGFILE等参数后,利用qsub run_jupyter.sh提交任务

备注

  • 为什么不用从管理节点到计算节点的正向隧道?

并非绝对不行,但一方面,建立正向隧道需要在管理节点额外执行脚本,需要更多工作量。另一方面,从管理节点访问计算节点,并无如$PBS_O_HOST这样简单的变量可以指向目标地址。因此,整体工作量会复杂很多。

  • 某些特殊情况是指什么?

比如说,机器上还有其他服务开启了某些端口。解决方案,首先设置端口时,就应当尽量避开常见的服务所在端口,避免冲突。如果怀疑端口被其他服务占用,可以关闭jupyter后再次检查端口是否开启.

  • 我记不住ip地址的话,能不能不用服务器ip访问jupyter服务?

可以,只要在本地机器上,用类似的方案开一条正向隧道,将本地端口port指向管理节点的服务端口,然后即可用https://127.0.0.1:port或https://localhost:port访问到`jupyter`服务。