科学地部署自己的 Overleaf 服务

 

最近发现 Overleaf 在 GitHub 上开源了自己的服务端实现,仔细一看其实就是合并之前 ShareLaTeX 开源的版本的新版,甚至在 DockerHub 上面的名字都还是 sharelatex/sharelatex。刚好某组织有搭建一个版本用于测试的需求,因为我以前自己搭过 ShareLaTeX,所以就帮忙一起配了一下。

实际上的过程非常简单:上面的仓库里面提供了一个 docker-compose.yml,直接 pull 下来然后 docker-compose up 基本就结束了。官方提供的 教程 指出,镜像里面的 TeX Live 是不完整的。于是我在跑起来之后 docker exec 进容器中,安装了完整版的 TeX Live,放进去了中文字体,测试也一切正常。就在准备 commit 镜像之前,我想起来了一件事情:

以后镜像升级怎么办?

是的,官方把自己的服务和 TeX Live 直接打包了一个镜像里面,因此如果镜像有升级的话,用户做的任何改动必须重新来过(docker 有直接把一个 layer 覆盖在任意 layer 上的操作吗?有的话或许倒是可以弄一些黑魔法)。这显然会让我很不爽。思考了一下以后,我把镜像里面的这些目录复制了出来:

  • /usr/local/texlive
  • /usr/share/fonts
  • /var/cache/fontconfig

然后修改了一下 docker-compose 的配置,把它们加进了 sharelatex 容器的 data volume(也就是 bind mount)进去。这样,我们不用对原来的容器进行任何改动,就能够任意升级 TeX Live 版本、增加字体(别忘了跑一下 fc-cache)了。

然而,又浮现出了一个新的问题:minted 宏包用不了。这是因为:

  1. minted 宏包需要启用 shell-escape,而 TeX Live 默认没有启用;
  2. minted 宏包需要 Pygments Python 包的支持,并且需要 pygmentize 脚本。

对于第一个问题,修改 Overlay 的 /usr/local/texlive/,加入 shell_escape = t 即可。对于第二个问题,很幸运地,Pygments 宏包并没有什么依赖,因此我直接从 PyPI 下载了这个包,解压并将代码(pygments 目录)映射进容器的 /usr/lib/python3.6/ 目录中,pygmentize 可执行文件映射进 /usr/bin 中。经过测试,minted 已经能够正常地运行了。

经过上面的魔改,一个比较科学的 Overleaf 服务就搭起来了。