ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Docker容器化LaTeX编译环境:论文排版自动化完整指南

Docker容器化LaTeX编译环境:论文排版自动化完整指南 又到了写论文的季节。每年这个时候总有人被 LaTeX 环境和宏包折腾到怀疑人生——CTeX 乱码、缺少 sty 文件、版本不一致、在 Windows 上装完 TeX Live 之后发现还要配字体一不小心把系统目录搞得一团糟。我自己的做法是用 Docker 把 TeX Live 环境整个封装起来不管笔记本里装了什么系统、装没装过 LaTeX一条命令就能把论文编译出 PDF。这套方案我已经用了好几个项目从期刊模板到学位论文都在跑稳定省心。这篇文章就把完整的部署思路、实操步骤和踩坑记录整理出来给准备写论文或者做排版自动化的人一个可以直接照抄的方案。1. 为什么要把 LaTeX 编译环境塞进 Docker1.1 那些年我们一起踩过的 LaTeX 环境坑LaTeX 本身只是个宏包系统但实际用起来你面对的是 TeX Live、CTeX、MiKTeX、宏包、字体、编译引擎这一整套东西。最常见的坑有三个。第一个是版本地狱。TeX Live 每个版本对应一套宏包快照2022 年写的模板拿 2025 年的发行版编译可能因为宏包更新而报错反过来新模板在老发行版上又可能缺宏包。很多时候不是你写错了而是环境版本和模板要求不匹配。第二个是依赖不干净。装了完整的 TeX Live full 版本确实省心但体积动辄 7、8 个 GB而且它往系统目录里塞了大量文件。等到你想升级或者卸载的时候一堆残留文件怎么清都清不干净。我之前在 macOS 上手动卸载 TeX Live 就折腾了大半天。第三个是字体和中文字体问题。论文写作绕不开中文而中文排版要用 xelatex 配合 ctex 宏包还需要中文字体。Windows 上字体还好说到了 Linux 服务器上默认连一个中文字体都没有编译出来的 PDF 全是方块。这些问题单独处理都不算难但组合在一起每换一台机器就要重新折腾一遍时间和精力全都耗在环境上了。1.2 容器化到底解决了什么问题Docker 的思路很简单把 TeX Live 环境连同依赖一起打包进一个镜像里编译的时候让容器去跑编译完 PDF 落盘容器随即销毁。宿主机不需要安装任何 TeX 相关的东西。这套方案解决了三个关键问题环境可复制。同一个镜像在 Windows、macOS、Linux 上的行为完全一致。不同项目可以用不同版本的 TeX Live 镜像互不干扰。宿主机干净。容器是隔离的往里面装多少东西都不会污染系统。不用了直接删镜像所有痕迹一起消失。自动化友好。CI/CD 平台里跑 Docker 是天然的能力提交代码后自动编译 PDF 非常自然这也是后面要讲的进阶玩法的基础。对我来说最直接的感受是以前给师弟师妹们搭论文环境要远程指导一晚上现在只需要给他们一份 Dockerfile 和一个启动脚本跑起来就能编译世界清净了很多。1.3 什么人适合这套方案虽然 Docker 有一点学习成本但下面这几类人我强烈建议用学生。论文模板经常要换学校、换期刊每个模板对宏包版本的要求不一容器隔离能让你放心折腾。跨平台用户。白天实验室用 Linux晚上笔记本用 Windows用 Docker 之后不需要在两台机器上分别维护环境。做排版自动化的人。如果你的论文是多人协作、需要自动化出 PDF那 Docker 是标准答案。被 LaTeX 环境折腾怕的人。如果你曾经在一个 LaTeX 环境上耗掉超过两个小时这方案大概率适合你。当然如果你只是偶尔写一页简历那没必要上 Docker直接装个精简版 TeX Live 就好。这套方案适合把 LaTeX 当作严肃生产力工具的场合。2. 方案选型现成镜像还是自己装2.1 直接使用现成的 TeX Live 镜像Docker Hub 上的官方镜像更新不太稳定我目前主力用的是 ghcr.io/texlive/texlive 这个镜像它由 TeX Live 社区维护版本跟随 TeX Live 年度发布地址是ghcr.io/texlive/texlivetag 有2024、2025、latest等。这个镜像的好处是它直接基于 TeX Live 官方安装脚本构建包含完整的系统目录结构用latexmk、tlmgr都比较顺手。缺点是完整版镜像很大拉取的时候要有耐心我在网络好的环境下拉一次也要几分钟。如果是纯英文文档或者对中文没有硬需求也可以用更小的镜像比如结合 Pandoc 生态的pandoc/latex或者自己按需裁剪。但对于写中文论文的用户我建议直接上完整版镜像省得后面缺这个缺那个。提示镜像大不是问题拉取占用的是一次性流量和磁盘空间。真正天天打交道的是编译速度而这个取决于 CPU 和镜像是否在本地缓存和镜像体积关系不大。2.2 自己写 Dockerfile 定制环境现成镜像不满足需求时可以自己写 Dockerfile。比如你只需要 xelatex ctex 常见宏包那用 Ubuntu 基础镜像 精简 TeX Live 包就能得到一个比完整版小得多的环境。下面是我自己用过的精简 DockerfileFROM ubuntu:22.04 ENV DEBIAN_FRONTENDnoninteractive RUN apt-get update apt-get install -y --no-install-recommends \ texlive-latex-base \ texlive-latex-recommended \ texlive-latex-extra \ texlive-fonts-recommended \ texlive-xetex \ texlive-lang-chinese \ fonts-noto-cjk \ latexmk \ lmodern \ rm -rf /var/lib/apt/lists/* WORKDIR /workdir构建命令docker build -t my-texlive:2025 .这里的关键包说明texlive-latex-extra覆盖面很广的宏包集合论文模板里常见的algorithm、listings、enumitem等都在里面。texlive-xetexxelatex 引擎中文论文必须。texlive-lang-chinesectex 宏包和中文支持。fonts-noto-cjk思源黑体的系统字体版本解决容器内找不到中文字体的问题。lmodernLatin Modern 字体很多模板依赖它。我自己在实验室服务器上就是用这个方案镜像体积比完整版小了一半多编译常见论文模板基本不缺东西。2.3 我的推荐与取舍直接给结论新手和追求省心的人用ghcr.io/texlive/texlive:latest完整版想控制镜像体积、或者公司/学校内网拉取镜像不方便的人自己构建精简版。还有一个思路是“完整版镜像 按需安装缺失宏包”。容器的好处是你可以进入容器里用tlmgr install 包名补装然后用docker commit把当前容器保存成新镜像。这个方案适合那种只有一两个宏包缺失的场景比维护一堆 Dockerfile 省事。不过有一点要注意docker commit会产生较多历史层镜像管理起来不够优雅。我更推荐的方式是把需要的宏包写入 Dockerfile用tlmgr安装后重新构建这样镜像的可复现性最好。3. 动手部署从拉取镜像到第一次编译成功3.1 先确认 Docker 环境正常不管你是 Windows、macOS 还是 Linux先确认 Docker 本体能用docker versionWindows 用户要特别注意Docker Desktop 依赖 WSL2 或者 Hyper-V首次安装后大概率会遇到“Docker Desktop failed to start because virtualisation support wasnt detected”之类的报错。这是因为 BIOS 里虚拟化没开或者 Windows 功能里“虚拟机平台”没开启。解决办法稍后在第 6 章详细说这里先保证docker run hello-world能跑通再说下一步。3.2 拉取 TeX Live 镜像确定能跑 Docker 之后先拉镜像docker pull ghcr.io/texlive/texlive:latest网络正常的情况下这个命令会把整套 TeX Live 环境拉下来。如果你的网络非常慢可以配置 Docker 的 registry-mirrors 选项这是 Docker 官方支持的功能配置为你的云服务商或学校提供的镜像地址拉取速度会有明显提升。拉完验证一下docker run --rm ghcr.io/texlive/texlive:latest --version能看到 TeX Live 和版本信息说明环境已经可用了。3.3 编译第一份 PDF现在创建第一个测试工程。新建一个目录写入一个最小 LaTeX 文件\documentclass{article} \begin{document} Hello, Docker LaTeX! \end{document}然后执行编译cd ~/my-tex-project docker run --rm \ -v $(pwd):/workdir \ -w /workdir \ ghcr.io/texlive/texlive:latest \ latexmk -xelatex -interactionnonstopmode main.tex命令的每一个参数都有讲究--rm容器跑完就删不留垃圾容器。-v $(pwd):/workdir把当前目录挂载到容器的 /workdir相当于让容器能看到你的文件。注意左边路径要写宿主机绝对路径所以$(pwd)这个写法在 Linux/macOS 下可以直接用。-w /workdir指定容器内的工作目录为 /workdir这样latexmk就在这个目录里生成文件。-interactionnonstopmode编译遇到错误不弹交互式询问直接报错退出适合脚本调用。Windows 用户注意PowerShell 里$(pwd)是自动变量可以直接写docker run --rm -v ${PWD}:/workdir -w /workdir ghcr.io/texlive/texlive:latest latexmk -xelatex main.tex如果你是 CMD 传统命令行把${PWD}换成%cd%。编译完成后当前目录下会多出main.pdf和一众中间文件aux、log、fls 等。PDF 可以直接打开验证成功。3.4 中文字体最容易踩的坑纯英文文档到这里就结束了但中文论文还有一关——字体。容器里默认没有中文字体直接编译 ctex 文档大概率报错或者输出方块字。我自己处理中文字体的方式有三种按推荐程度排列。推荐做法构建镜像时直接装fonts-noto-cjk像我上面那份 Dockerfile 一样。这样镜像内部自带 Noto CJK 字体到任何机器上都能稳定编译。挂载方案如果你用的是现成镜像不想自己构建那就把宿主机字体目录挂载进去。Linux 下执行docker run --rm \ -v $(pwd):/workdir \ -w /workdir \ -v /usr/share/fonts:/usr/share/fonts:ro \ ghcr.io/texlive/texlive:latest \ latexmk -xelatex main.texWindows 下可以把C:\Windows\Fonts挂载到/usr/share/fontsmacOS 则挂载/System/Library/Fonts和/Library/Fonts。但这个方法有个缺点换一台机器字体可能就不一样了最终编译效果略有差异。把字体放进项目目录在项目里建fonts/目录把需要用到的 ttf/otf 文件放进去然后挂载项目自身-v $(pwd):/workdir -w /workdirLaTeX 侧用fontspec的\setmainfont指定字体路径。这个方案的可复现性比挂载系统字体好但管理字体文件比较繁琐。我的建议是自己构建镜像就装fonts-noto-cjk用现成镜像就挂载系统字体。两条路都验证过编译 ctex 模板都没问题。3.5 日常开发的目录挂载与权限处理上手之后你会发现每次编译都要敲一长串docker run命令很烦。解决方法是写一个build.sh脚本#!/usr/bin/env bash set -e IMAGEghcr.io/texlive/texlive:latest docker run --rm \ -v $(pwd):/workdir \ -w /workdir \ -v /usr/share/fonts:/usr/share/fonts:ro \ $IMAGE \ latexmk -xelatex -interactionnonstopmode $.gitignore里加中间文件*.aux *.log *.out *.fls *.fdb_latexmk *.synctex.gz *.toc *.bbl *.blgLinux 下还要注意文件属主问题。容器内默认是 root 用户挂载目录里生成的文件属主也会变成 root如果你之后用普通用户操作这些文件可能要加 sudo 才能删。解决方式是在docker run里指定用户docker run --rm -u $(id -u):$(id -g) \ -v $(pwd):/workdir \ -w /workdir \ ghcr.io/texlive/texlive:latest \ latexmk -xelatex main.tex这样容器生成的文件属主就是你当前的 uid/gid干净利落。Windows/macOS 用户通常不需要管这个因为文件权限模型和 Linux 不一样。4. 跟 VS Code 搭配本地写论文容器里编译4.1 LaTeX Workshop 与 Docker 的结合方式现在环境准备好了剩下的问题是怎么舒服地写论文。VS Code 加上 LaTeX Workshop 插件是目前最流行的组合。这个插件本身支持配置外部编译工具我们可以把默认的pdflatex、xelatex换成 Docker 命令这样在编辑器里按一下保存PDF 就在容器里编译好了。这个方式最大的好处是编辑器里写代码、预览 PDF、代码补全都是宿主机上的原生体验而真正干活编译的环境是固定的容器。既照顾了 IDE 的便捷又保证了编译环境的一致性。4.2 配置 Docker 作为编译工具打开 VS Code 设置Ctrl, 或 Cmd,点击右上角的“打开设置JSON”写入{ latex-workshop.latex.tools: [ { name: latexmk-docker, command: docker, args: [ run, --rm, -v, %DIR%:/workdir, -w, /workdir, ghcr.io/texlive/texlive:latest, latexmk, -xelatex, -interactionnonstopmode, %DOC_EXT%.tex ] } ], latex-workshop.latex.recipes: [ { name: docker latexmk, tools: [latexmk-docker] } ], latex-workshop.latex.recipe.default: docker latexmk }这里有个变量要特别注意%DIR%是当前 LaTeX 文件所在目录%DOC_EXT%是当前文件名不含扩展名两个变量在 LaTeX Workshop 里都是内置的不需要自己定义。为什么不能用%DOC%因为%DOC%是宿主机上的完整路径比如C:\Users\me\paper\main.tex容器里没有这个路径必须用相对于/workdir的文件名。如果你的编译需要用到 bibtex构建流程就变成“编译一次 → bibtex → 编译两次”对应的 recipe 可以配置多个工具按顺序执行。这里我建议直接在 LaTeX 里使用latexmk它会根据依赖自动调起 bibtex省心得多。配置好之后切回.tex文件左侧的 TeX 侧边栏里能看到“Build LaTeX project”按钮点一下就会调用容器编译。首次编译因为要启动容器会慢一些之后有缓存就会快很多。4.3 如果习惯 TeXstudio 怎么办并不是所有人都用 VS Code你要是习惯 TeXstudio也可以指向 Docker。在 TeXstudio 的“选项 → 命令”里把“XeLaTeX”命令改为docker run --rm -v %.d:/workdir -w /workdir ghcr.io/texlive/texlive:latest latexmk -xelatex -interactionnonstopmode %.texTeXstudio 里的%.d代表当前文件目录%.tex代表当前文件名。设置好后按 F5 就能在容器里编译。不过 TeXstudio 对容器工作目录的变量替换没有 VS Code 那么直观实际操作时以你自己版本里的“命令配置”说明为准。5. 进阶玩法提交代码自动出 PDF5.1 用 GitHub Actions 实现自动编译如果论文是多人协作或者你想在每次修改后自动拿到最新的 PDF可以让 CI 平台来做编译。GitHub Actions 上有现成的 LaTeX action底层就是基于 Docker 的 TeX Live 镜像。在仓库根目录建.github/workflows/build.ymlname: Build LaTeX on: push: paths: - **/*.tex - **/*.bib - **/*.cls - **/*.sty jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: xu-cheng/latex-actionv3 with: root_file: main.tex latex_compiler: latexmk args: -xelatex -interactionnonstopmode - uses: actions/upload-artifactv4 with: name: main-pdf path: main.pdf这个 action 内部会拉取一个 TeX Live 完整环境所以你的仓库里不需要有任何 Dockerfile只要把 root_file 指向主文件即可。编译完成后PDF 会作为 artifact 上传到 Actions 页面点击即可下载。有一点要注意如果仓库里的.bib文件或者自定义.cls文件有变更也需要触发构建所以我在paths里加上了这些扩展名。5.2 用 GitLab CI 实现自动编译如果你在学校/公司的 GitLab 上管理代码流程类似在仓库根目录建.gitlab-ci.ymlimage: ghcr.io/texlive/texlive:latest compile: stage: build script: - latexmk -xelatex -interactionnonstopmode main.tex artifacts: paths: - main.pdf expire_in: 30 days only: changes: - **/*.tex - **/*.bib - **/*.cls - **/*.styGitLab Runner 在对应机器上只需要有 Docker 就能跑每次推代码CI 自动拉镜像、自动编译、自动把 PDF 作为 artifacts 存到流水线页面。5.3 自动编译的意义与局限自动编译的价值不只是“不用手动敲命令”。更实际的意义是多人协作时每次提交都是一个可回溯的版本PDF 和源码严格对应。以前经常出现“我这版能编译你拉下来就不行”的问题本质是本地环境不一致。CI 环境是干净的、固定的编译失败一定是因为代码问题而不是环境玄学。这个方案也有局限CI 默认超时时间一般 30 到 60 分钟大论文第一次编译需要下载字体和宏包时间较长还有就是免费的 CI 资源有限不适合频繁触发。我的做法是只在推送到主干分支时才触发完整编译平时开发用本地容器编译就好。6. 常见问题与排查技巧6.1 Docker Desktop 起不来的两个高频原因Windows 用户最常见的报错就是“Docker Desktop failed to start because virtualisation support wasnt detected”。这个报错的根源几乎都是虚拟化没开。解决办法分两步。第一步确认 BIOS/UEFI 里的虚拟化开关是否开启。Intel 平台叫 Intel VT-xAMD 平台叫 SVM Mode在 BIOS 里搜关键词找到后启用重启 Windows。第二步到“控制面板 → 程序 → 启用或关闭 Windows 功能”里把“适用于 Linux 的 Windows 子系统”和“虚拟机平台”两项勾上然后重启。如果这两项都开了还不行多半是 WSL2 内核没更新到 PowerShell 里执行wsl --update wsl --set-default-version 2再重新打开 Docker Desktop 就可以了。macOS 上如果遇到类似问题大概率是“在设置了安全隐私选项后没有给 Docker 授权”到系统设置里检查虚拟化框架权限即可。6.2 镜像拉取慢 / 拉取失败怎么处理国内网络环境拉取 Docker Hub 或 ghcr.io 镜像经常超时。两种处理方式第一种配置 Docker 的 registry-mirrors。Docker Desktop 里在 Settings → Docker Engine 的 JSON 配置文件中加入{ registry-mirrors: [https://你的镜像地址] }保存重启后生效。镜像地址选择上优先考虑你所在云服务商提供的地址或者学校给校内用户提供的地址不要随便用来路不明的地址。第二种换镜像源。大部分 CI 平台自带的 Docker 环境会预置好镜像加速本地如果拉取困难可以考虑直接借用 CI 的构建产物或者用.tar文件离线导入镜像。提醒一下拉取失败不要反复重试先检查网络连通性和 DNS。我之前遇到过 ghcr.io 超时实际是内网 DNS 解析异常导致的把 DNS 改成公共 DNS 后就正常了。6.3 中文乱码和缺字体xelatex 编译中文出现方块或乱码优先检查两件事第一文档类是不是用的 ctex比如\documentclass{ctexart}第二容器里有没有中文字体。进入容器查字体docker run --rm ghcr.io/texlive/texlive:latest fc-list :langzh如果输出为空说明没有中文字体。按 3.4 里的两种方案处理挂载字体目录或者重新构建一个带fonts-noto-cjk的镜像。另外从 Windows 上传到服务器的源文件要注意编码格式统一用 UTF-8。6.4 缺宏包、版本对不上编译报! LaTeX Error: File xxx.sty not found.最直接的方法是进容器里看这个包是否已经存在docker run --rm ghcr.io/texlive/texlive:latest kpsewhich xxx.sty如果输出为空说明没装。完整版 TeX Live 镜像覆盖了绝大多数情况万一真的缺可以用tlmgr install xxx在容器里现场装然后 commit 成新镜像。但这个方法有风险下次镜像更新时你的自定义层会被覆盖。更推荐的方式是把缺失包记录到 Dockerfile 里用tlmgr install构建。还有一类“版本对不上”问题表现为在 A 电脑上能编译在容器里报错。这时先看.log文件结尾处的错误提示很多是宏包接口变化导致的把相关宏包版本固定下来是最好的解决方式。6.5 BibTeX 报错其实是正常输出很多人在编译带参考文献的论文时会看到类似下面的输出This is BibTeX, Version 0.99d (TeX Live 2022) The top-level auxiliary file: main.aux这个信息看起来像报错其实就是 BibTeX 在正常告诉你“我在读 main.aux准备生成参考文献列表”。真正的问题通常出现在这之后比如I couldnt open database file xxx.bib那才是 bib 文件路径写错了。如果你用的是latexmk -xelatex它会在编译过程中自动调用 BibTeX不需要手动分步执行。如果分步操作记住顺序xelatex → bibtex → xelatex → xelatex少一步参考文献都会对不齐。6.6 LaTeX 高频小问题速查表写论文过程中有些细节点几乎每天都会用到我用一个小表把最常见的几个列出来需求LaTeX 写法换行\\或\newline希腊字母\alpha、\beta、\gamma、\sigma等行内公式$...$比如$a^2b^2c^2$独立公式\[...\]或equation环境插入图片\includegraphics[width0.8\textwidth]{fig.png}需配合graphicx宏包表格tabular环境引用参考文献\cite{key}配合.bib文件生成目录\tableofcontents强调文字\emph{内容}这些语法在容器编译和本地编译上没有任何区别它们只是 LaTeX 宏包的语法问题。一些个人的体会说实话我一开始也不习惯用容器写论文总觉得多绕了一层不如直接装个 TeX Live 来得直接。但用了一段时间之后反而是这种“隔离”让我最安心。不管换了新电脑还是帮别人跑模板不需要再关心对方系统里装了什么东西Docker 镜像拉到哪编译结果就在哪。对我这种经常在几台机器之间切换的人来说这种确定性比省那几分钟环境安装时间重要得多。如果你决定尝试我的建议是从小处开始先拉一个完整版现成镜像参照第 3 章的命令把第一篇论文编译出来再逐步加上字体、VS Code 配置、自动编译。这个过程不会花超过半天但以后写论文时那种“环境又出问题”的焦虑感会彻底消失。
返回列表