为了让jupyterhub 开机启动,或者以服务的方式启动,折腾了好久。
环境
ubuntu 16.04
anaconda >= 4.5
python35
jupyterhub 0.9.4
node 6.14.4
背景
- jupyterhub 安装在 conda的虚拟环境中 只有进入该虚拟环境中才能执行jupyterhub命令
- 建立的脚本可以启动jupyterhub
#!/bin/bash -l
conda activate python35
cd /etc/jupyterhub
jupyterhub -f /etc/jupyterhub/jupyterhub_config.py >> /etc/jupyterhub/jupyter.log
bash 一定要加-l
目的是以login shell
的方式登录,否则系统可能无法识别conda
命令,因为conda
4.4后的版本将命令的配置放到了/etc/profile.d/conda.sh
中,只有login shell
登录的时候才会执行该文件,系统才会识别到conda
命令。大家可能会比较疑惑,为什么用conda activate
而不用source activate
这样是不行的,因为我们要放到开机启动项或者服务启动项中,这两种方法识别到的source 是linux系统的source
,就是用来更新文件状态的那个命令,通常我们更改系统的配置文件比如/etc/profile /etc/bash.bashrc
后用source
命令更新,所以在开机启动或者启动服务的时候bash 将source
识别成这个更新文件的命令,导致出错
问题
- 每次启动的上面的脚本时需要用
./name.sh
或者bash name.sh
来执行,且当我们关掉自己的命令行时jupyterhub
服务也就会关掉,也就是没办法后台运行。
解决方案
- 将上面的脚本文件作为开机启动项,让其开机自起(只有重启机器才会生效)
- 将上面的脚本作为服务(类似于 ssh server),可以通过
service
或systemctl
等服务管理命令控制(不必重启机器,灵活,可控)
加入到开机启动项中
参考链接原理比较详细的链接 只要脚本没问题,即可执行,但问题是脚本一旦有问题,服务就不会被启动,且我们也不知道出错在哪。比如说,我们不知道该脚本执行的顺序是在加载用户配置之前还是之后执行,如果在用户配置PATH
等配置之前就执行,那么用户的某些命令就无法执行比如conda, node configurable-http-proxy
这三个命令都和jupyterhub
相关,如果我们写的脚本在加载用户配置之前就执行,肯定是不行的,所以我们尽量不采用这种方法
写到服务中
我们的机器是ubuntu 16.04
可以中systemctl
管理服务
- 在
/etc/systemd/system/
下建立一个名为jupyterhub.service
的服务配置文件,名字是jupyterhub
后缀是.service
,名字可以自己随便命名,该名字就是以后用systemctl
或service
配置的服务名
- 在
jupyterhub.service
文件中写入下面的命令
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
[Unit]
Description=jupyterhub (随便起个名字)
After=syslog.target network.target (在网络服务启动后启动该脚本)
[Service]
User=root
ExecStart=/etc/jupyterhub/jupyterhub.sh (脚本地址)
[Install]
WantedBy=default.target
上面的配置是系统服务配置文件最简单的写法改一下就可以了。
- 在终端中执行
systemctl start jupyterhub
启动服务
- 查看服务运行状态
systemctl status jupyterhub
- 通常会出错
如果提示node configurable-http-proxy
错误,找不到文件等等,那原因就是服务的优先级在系统配置之前,也就是我们配置的node
的PATH
没有被识别,所以我最终将node
的PATH
配置放到了/etc/profile
中成功了,之前放到了/etc/bash.bashrc
中并不能识别
- 服务可以成功启动,执行
systemctl enable jupyterhub
允许开机自启动
以上就是走过的坑,希望大家在和我一样的环境下能避免这些坑。
更新
根据jupyterhub 官网的教程我们重新对这个进行了修改,其中我们按照官网修改的内容把服务进行更改,更改的内容如下:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
[Unit]
Description=jupyterhub
After=syslog.target network.target
[Service]
User=root
Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/local/node6.14.4/bin:/usr/bin:/opt/anaconda3/envs/python35/bin"
ExecStart=/opt/anaconda3/envs/python35/bin/jupyterhub -f /etc/jupyterhub/jupyterhub_config.py
[Install]
WantedBy=multi-user.target
其中Description=jupyterhub
这一行表示你对这个服务起的名字
[Service]
下面是重要的信息
添加Environment
一行Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/local/node6.14.4/bin:/usr/bin:/opt/anaconda3/envs/python35/bin"
这一行的意思是,我们运行需要的脚本需要哪些可执行文件,需要把对应的PATH
放到这里,需要强调的是configurable-http-proxy
这个软件是用node
安装的,我们的node
是从官网下载的二进制文件,安装到了/usr/local/node6.14.4
这里,所以,在上面的路径中,我们添加了相应的bin
目录到PATH
里,只要是运行的内容所需要的可执行文件,都需要加入到这个Environment
中,其中,我们这个例子里最终要的是node
和虚拟环境中的jupyterhub
查看虚拟环境的地址
- conda activate python35 进入该虚拟环境
- which jupyterhub 查看jupyterhub 在哪个路径下,然后加入到上面的路径中
ExecStart
这一行,也简化了,因为采用写bash
脚本的方式需要加载conda
,可能是程序运行优先级的问题,有时候配置的时候会提示我们conda
命名找不到,为了避免这种情况,我们直接用绝对路径去执行,不需要事先进入conda
虚拟环境,相应的,我们的可执行代码变成了下面这样的
ExecStart=/opt/anaconda3/envs/python35/bin/jupyterhub -f /etc/jupyterhub/jupyterhub_config.py
这样就完美解决了,多多点赞支持