最近我把自己的nas硬盘全格式化了,然后重新弄了一个unraid系统来跑docker。装了一些影音自动化的镜像后感觉非常不错,然后通过家里了另一台极空间实现了内网的穿透,我就想既然可以随时随地访问到自己家的电脑了,为什么不给它搞一个jupyterlab进去呢,现在每天几乎离不开它,于是就有了本文。
找一个jupyterlab的镜像
经过搜索,发现Jupyter确实弄了一些off-the-shelf的镜像,托管在github上
相关文档地址:jupyter-docker-stacks.readthedocs.io/
通过文档我们知道它有非常多的版本,如下图所示:
其中docker-stacks-foundation是一个只有conda环境没有jupyter环境的包,base-notebook则在docker-stacks-foundation的基础上,增加了jupyterlab环境,minimal-notebook则是在base-notebook基础上增加了一些curl、git、unzip等命令,到base-notebook为止,基本的环境就已经搞定了。再剩下的全是在base-notebook的基础上,再添加了新的东西。比如r-notebook是base-notebook上添加了R语言,pytorch-notebook是添加了pytorch库等等。
由于我的unraid上只有一个可怜的核显,而且CPU也是一个8代的老家伙了,所以我就不搞这些深度学习的库了,但是机器学习还是可以玩一下的,所以我选择了scipy-notebook。
但是我建议大家选择base-notebook,因为镜像里面本身就有conda环境,而这些预置的库都给装到了默认的base环境中,在实际应用中几乎不会直接使用base,整个就是一个浪费硬盘。
部署镜像
想要快速的开始在docker上运行jupyterlab非常简单,直接docker run 并且把端口8888映射出来就可以了。这里就不细说了,不过有一个要注意的地方就是初始会生成一个token用来访问jupyterlab,你应该在日志中查看。
配置镜像
运行进来简单,配置起来难,接下来就来到了重头戏了。
1. 配置目录的寻找
由于默认只映射一个端口就能跑,你自己安装的所有的东西都不会保存到物理机上,重新部署一下镜像就全都没了。(有的人可以没有我这种强迫症,我是镜像有更新就要用最新的,每次一更新,重新部署就全没了)
我使用过程中,在镜像中使用conda创建了很多虚拟环境,例如我弄一个langchain框架的
conda create -n langchain python=3.12
然后我进入到这个虚拟环境,安装一些包,最后将它添加到jupyter的内核列表中,就可以直接在jupyterlab中使用了
conda activate langchain
pip install langchain langchain_openai python-dotenv # 等等
pip install ipykernel # 安装jupyter要用的内核
python -m ipykernel install --user --name langchain --display-name "LangChain" # 将当前环境安装到jupyterlab内核列表
在这个过程中,通过观察我找到了一些路径
conda的环境路径
/opt/conda/envs # conda 环境目录1
/home/jovyan/.conda/envs # 这是镜像默认的用户名下的目录,通常是1不可用的时候才会用
conda包缓存路径
/opt/conda/pkgs
/home/jovyan/.conda/pkgs # 和环境一样有两个,上面的默认用的,下面的备用
jupyter内核配置路径
/home/jovyan/.local/share/jupyter
jupyter本身配置路径
/home/jovyan/.jupyter
jupyter工作目录
/home/jovyan/
通过上面的观察我们基本上可以确定要映射哪些目录了。
2. 配置目录映射
列一下我的映射目录
主机/appdata/docker/jupyter/envs 镜像/opt/conda/envs
主机/appdata/docker/jupyter/workspace 镜像/home/jovyan/workspace
主机/appdata/docker/jupyter/pkgs 镜像 /opt/conda/pkgs
主机/appdata/docker/jupyter/.jupyter 镜像/home/jovyan/.jupyter
主机/appdata/docker/jupyter/.local 镜像/home/jovyan/.local
主机/appdata/docker/jupyter/.conda 镜像/home/jovyan/.conda
3. 配置目录的权限问题
本来以为映射了目录就万事大吉了,谁知道竟然提示没有目录的写权限,虽然我挂载的时候写了是使用rw模式,并且我docker中其它镜像也是使用的/appdata/docker/xxxx这里的目录,他们就没有权限问题。
经过我的分析发现:
正常的镜像是使用的root用户,基本上所有的root用户的uid和gid都是一样的,它们就可以直接无缝的使用宿主机的文件(不管是在用户下的还是在root下的,root用户都可以访问)
而jupyter镜像使用的是一个jovyan用户,它不仅不能访问到own是root的文件,它也不能访问到own是别的用户的文件,它所能访问的,只有它自己。
有两个方案可以解决这个问题:
1. jupyter镜像有两个环境变量,NB_UID和NB_GID,将他们全设置成0,然后在启动docker时添加--root参数,才能正确的切换jovyan的id,这样就可以无缝使用宿主机的目录和文件了。
2. 修改目录的own:由于unraid启动docker镜像不能添加--root参数,我只能使用这个方法。通过日志我知道了jupyter镜像默认的uid和gid分别是1000和100,于是我在宿主机上对着上面6个目录就是一顿chown
chown -R 1000:100 /appdata/docker/jupyter/envs
chown -R 1000:100 /appdata/docker/jupyter/workspace
chown -R 1000:100 /appdata/docker/jupyter/pkgs
chown -R 1000:100 /appdata/docker/jupyter/.jupyter
chown -R 1000:100 /appdata/docker/jupyter/.local
chown -R 1000:100 /appdata/docker/jupyter/.conda
重启后发现成功了,在conda中创建的虚拟环境,添加的jupyter内核,修改的Jupyter密码,都不会在重新部署后丢失了。
4. 配置中文
最后一个问题就是中文环境的问题了,jupyter切换中文环境需要先安装一个包
pip install jupyterlab-language-pack-zh-CN
然后在Settings-Languages里面切换就可以了,因为我们已经将jupyter的配置映射出来所以修改一次后就不用再切换了。但是这个包我们是安装的,重新部署后这个语言包就被删除了,这个问题需要解决。
通过对jupyter镜像文档的查看,我们了解到它有两个Hook目录
我们可以在镜像启动之前和之后插入一些自己的脚本。这里我们选择after hook
这又是一个新的配置目录,我们添加一个新的目录映射
主机/appdata/docker/jupyter/hooks 镜像/usr/local/bin/before-notebook.d/
别忘了给它chown
chown -R 1000:100 /appdata/docker/jupyter/hooks
然后在里面添加安装语言包的指令
echo '/opt/conda/bin/python -m pip install jupyterlab-language-pack-zh-CN' > /appdata/docker/jupyter/hooks/chinese_pack.sh
然后重新部署镜像,查看日志我们可以看到它执行了包安装指令,启动成功后我们打开jupyterlab,仍然是中文,配置保留成功!
现在你可以尽情的升级、转移你的jupyterlab了。