Docker を使い始めて間もない Docker 初心者の感想ですが,Docker を使えば,普段使いの TeX Live 環境とは別に古い TeX 環境を保管しておいたり,あるいは逆に先端の開発中ブランチを試しに導入できたりと,色々便利そうですね。
というわけで今回は,Docker の練習がてらに TeX Live 2019 + 原ノ味フォント + llmk でコンパイルできる Docker コンテナを作ってみました。
目標
- モダンな TeX Live 環境を一発で用意できる Docker のコンテナイメージを作りたい。
- pdfLaTeX / LuaLaTeX / XeLaTeX / (u)pLaTeX, dvips / dvipdfmx の全てを使えるようにする。
- Adobe の源ノ明朝/源ノ角ゴシックを Adobe-Japan1 準拠に組み直して作られた高品質なオープンソース和文フォントである原ノ味フォントを,和文標準フォントとして使えるように準備・設定しておく。
【参考】 - ビルドシステムとしては latexmk に代わる新世代ビルドシステム llmk を標準で使えるようにし,デフォルトとする。
【参考】
とりあえず完成品を使うには
イメージの pull
完成したイメージは Docker Hub に doratex/texlive2019ja-haranoaji としてアップロードしてあるので,
$ docker pull doratex/texlive2019ja-haranoaji
とすれば pull できます。(TeX Live 2019 がフルに入っているのでサイズが大きいです🙇)
使い方
コンテナ内では /workdir
が作業ディレクトリとなるので,それをカレントディレクトリと bind マウントして使うのを想定しています。
alias dockertl="docker run --rm \
--mount type=bind,src=\"\$(pwd)\",dst=/workdir \
--mount type=volume,src=ltfontcache,dst=/usr/local/texlive/2019/texmf-var/luatex-cache/generic/fonts/otl \
doratex/texlive2019ja-haranoaji"
などとエイリアスを設定しておくと楽でしょう。(--mount type=volume,...
の部分は,LuaTeX のフォントキャッシュを ltfontcache
というボリューム(名前は任意です)に保存し永続化させるための設定です。詳細は後述。)このエイリアスが設定されている下で
$ dockertl
とすれば,デフォルトで llmk が起動し,カレントディレクトリの llmk.toml
に基づきビルドしようとします。
$ dockertl llmk hoge.tex
のようにして特定のファイルをターゲットにすることもできます。従来の latexmk もインストールされているので
$ dockertl latexmk hoge.tex
も使えます。
またもちろん,llmk や latexmk のようなビルドシステムを用いずに,
$ dockertl lualatex fuga.tex
$ dockertl ptex2pdf -l piyo.tex
などと普通にコンパイルすることも可能です。
(u)pLaTeX + dvips/dvipdfmx においては,デフォルトで原ノ味フォントを埋め込む設定になっています。
テスト用サンプルコード
GitHub レポジトリにテスト用サンプルコード群を置いてあります。
- (u)pLaTeX + dvips
- (u)pLaTeX + dvipdfmx
- LuaLaTeX
- XeLaTeX
のそれぞれについて,原ノ味フォントが埋め込まれるサンプルコードとなっています。test_all.sh
を起動すれば llmk による各テストファイルのビルドが走ります。また,docker-compose
を用いるサンプルも入れてあります。
Dockerfile の作り方
以下,この Docker イメージのビルドに用いる Dockerfile の作り方を述べます。
参考文献
@yyu さんがLaTeXで年賀状を作る際に製作された Dockerfile を大いに参考にさせていただきました。
迷ったこと
Alpine ベースか Ubuntu ベースか?
イメージのサイズ削減のためには,Alpine ベースでいきたいところです。が,実際にやってみたところ,大半はうまくいったのですが,XeTeX に動的リンクされる fontconfig が(apk add fontconfig-dev
してあっても)うまく呼び出せず,XeTeX を起動することができませんでした。
割り切って「XeTeX は諦めて Alpine ベースにする」という手も考えられます。実際にイメージを作って比較してみたところ,
- Ubuntu ベース(XeTeX 使用可):3.63 GB
- Alpine ベース(XeTeX 使用不可):3.52 GB
となりました。TeX Live の scheme-full の容量が圧倒的で,もはや Ubuntu と Alpine のサイズの違いは誤差みたいなものとなっていました。それなら XeTeX が使えた方がいいだろうと考え,今回は Ubuntu ベースでイメージ構築することにしました。
TeX Live は scheme-full でいくか scheme-basic + collection-langjapanese でいくか?
イメージのサイズ削減のためには scheme-basic
+ collection-langjapanese
の方がよいでしょう。が,LuaLaTeX / XeLaTeX / (u)pLaTeX で一通りの組版をできるようにするためにどのパッケージを追加すべきかを考えるのが面倒だし,「モダンな TeX Live 環境が丸ごと整う」ことが目標なので,今回はサイズは気にせずに scheme-full
でいっちゃうことにしました。(ただしサイズ削減のために option_doc
と option_src
は外す。)
原ノ味フォントへの対応方法
LuaLaTeX
TeX Live 2019 の最新レポジトリでは,luatexja-preset パッケージが haranoaji
プリセットに対応しているのでそのままで大丈夫です。
(u)pLaTeX, dvips, dvipdfmx
pxchfon パッケージ
TeX Live 2019 の最新レポジトリで haranoaji
プリセットに対応済みです。
ptex-fontmaps, cjk-gs-integrate
GitHub のレポジトリ上では原ノ味フォント対応が済んでいますが,CTAN への収録はまだです。
➡ そこで,ptex-fontmaps と cjk-gs-integrate の GitHub 上の最新版を取得して TEXMFDIST
内のファイルを差し替えて対応します。
XeLaTeX
ZXjafont パッケージ に haranoaji
プリセットがまだ用意されていなかったので,fork して付け加えました。とりあえずこれを取得して TEXMFDIST
内のファイルを差し替えて対応します。
Dockerfile でやること
Dockerfile によるイメージのビルドにおいては,大まかに次のことを行います。
- TeX Live 2019 の最新版をネットワークインストール。
- 原ノ味フォントを GitHub レポジトリから取得して
TEXMFLOCAL
内にインストール。 - 原ノ味フォントに対応した最新版
ptex-fontmaps
を GitHub レポジトリから取得してTEXMFDIST
内に配置。 - 原ノ味フォントに対応した最新版
cjk-gs-integrate
を GitHub レポジトリから取得してTEXMFDIST
内に配置。 - 原ノ味フォントに対応したフォーク版の
zxjafont
を GitHub レポジトリから取得してTEXMFDIST
内に配置。 -
mktexlsr
して原ノ味フォントを TeX システムに認識させる。 -
cjk-gs-integrate
を走らせて Ghostscript の原ノ味フォント対応。 -
kanji-config-updmap-sys
で (u)pLaTeX の既定の和文フォントを原ノ味フォントにする。 - 最新版の llmk を GitHub レポジトリから取得して
/usr/local/bin
に配置。
課題の解決
XeTeX に TEXMF ツリー内のフォントを認識させる
Linux の場合,XeTeX は fontconfig を利用してフォントを見つけていますが,上記手順では原ノ味フォントをTEXMFLOCAL
内に配置しましたので,fontconfig がそれを見つけられません。そこで,次のような内容を記載した XML ファイルを /etc/fonts/local.conf
として保存しておきます。こうすることで TEXMFDIST
,TEXMFLOCAL
内のフォントを XeTeX が見つけられるようになります。
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<dir>/usr/local/texlive/texmf-dist/fonts/opentype</dir>
<dir>/usr/local/texlive/texmf-dist/fonts/truetype</dir>
<dir>/usr/local/texlive/texmf-local/fonts/opentype</dir>
<dir>/usr/local/texlive/texmf-local/fonts/truetype</dir>
</fontconfig>
その上で fc-cache -r
することで fontconfig のキャッシュを更新しておきます。
参考: fontspec が呼び出すフォント検索エンジン
エンジン | Windows | Mac | Linux/UNIX |
---|---|---|---|
XeTeX | fontconfig | AAT | fontconfig |
LuaTeX | luaotfload | luaotfload | luaotfload |
⬆ Mac 上の TeXLive の luaotfload で「クレー」などのフォントを使えるようにする - ルギア君の戯言より。
LuaTeX の初回フォントキャッシュ作成が遅い問題
LuaTeX の使用においては,フォントを初使用したときのコンパイルが遅いという点が問題となります。
luaotfload-tool -u -f
しておくことで,TEXMFLOCAL/texmf-var/luatex-cache/generic/names
内のフォントのデータベースは事前に作成しておくできます。ただし,それとは別に,フォントの初使用時に TEXMFLOCAL/texmf-var/luatex-cache/generic/fonts/otl
にフォントキャッシュが作成されるため,各フォントの初回使用時のコンパイルが遅くなります。2回目からは速くなりますが,Docker イメージからのコンテナ生成ではこれが問題になります。イメージから毎回使い捨てのコンテナを生成して使う場合,毎回が「初回起動」になるため,起動のたびに毎回フォントキャッシュ作成が入って無用に時間がかかってしまいます。
これを防ぐ方法の一案としては,次のようにして「Docker イメージ作成時に全てのフォントを1回ずつ使って全フォントのキャッシュを作成しておく」方法があります。
for x in $(luaotfload-tool --list=* --fields=fullpath); do \
/bin/echo "\\relax\\input luaotfload.sty \\font\\x[$x]\\bye" | luatex > /dev/null; \
done
しかし,このようにしてキャッシュを事前に全作成をすると,Docker イメージのサイズが 1GB 以上も増えてしまいます。そこで,キャッシュが保存されるコンテナ内のディレクトリ TEXMFLOCAL/texmf-var/luatex-cache/generic/fonts/otl
を,Docker コンテナ起動時に名前付きボリュームとしてマウントし,ホスト内に保存することで永続化させましょう。先ほどのエイリアスにはその設定を仕込んであります。
完成品
こうしてできあがった Dockerfile が以下の通りです。
Dockerfile
FROM ubuntu:19.10
LABEL maintainer="doraTeX <taylorkgb [at] gmail.com>"
ENV TL_PATH /usr/local/texlive
ENV FONT_PATH ${TL_PATH}/texmf-local/fonts
ENV TEXMF_DIST_PATH ${TL_PATH}/texmf-dist
ENV PATH ${TL_PATH}/bin/x86_64-linux:/bin:${PATH}
WORKDIR /tmp
# Install required packages
RUN apt update && \
apt upgrade -y && \
apt install -y \
# Basic tools
wget unzip git ghostscript \
# for tlmgr
perl-modules-5.28 \
# for XeTeX
fontconfig && \
# Clean caches
apt clean && \
apt autoclean && \
apt autoremove -y && \
rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/*
# Install TeX Live
RUN mkdir install-tl-unx && \
wget -qO- http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz | \
tar -xz -C ./install-tl-unx --strip-components=1 && \
printf "%s\n" \
"TEXDIR ${TL_PATH}" \
"selected_scheme scheme-full" \
"option_doc 0" \
"option_src 0" \
> ./install-tl-unx/texlive.profile && \
./install-tl-unx/install-tl \
-profile ./install-tl-unx/texlive.profile && \
rm -rf *
# Setup fonts and llmk
RUN \
# Install HaranoAji fonts
git clone https://github.com/trueroad/HaranoAjiFonts.git && \
mkdir -p "${FONT_PATH}/opentype/haranoaji" && \
cp -p ./HaranoAjiFonts/*.otf "${FONT_PATH}/opentype/haranoaji/" && \
rm -rf ./HaranoAjiFonts && \
# Update ptex-fontmaps
git clone https://github.com/texjporg/jfontmaps.git && \
cp -p ./jfontmaps/database/ptex-fontmaps-data.dat "${TEXMF_DIST_PATH}/fonts/misc/ptex-fontmaps/" && \
cp -pr ./jfontmaps/maps/haranoaji "${TEXMF_DIST_PATH}/fonts/map/dvipdfmx/ptex-fontmaps/" && \
cp -p ./jfontmaps/script/*.pl "${TEXMF_DIST_PATH}/scripts/ptex-fontmaps/" && \
rm -rf ./jfontmaps && \
# Update cjk-gs-integrate
git clone https://github.com/texjporg/cjk-gs-support.git && \
cp -p ./cjk-gs-support/cjk-gs-integrate.pl "${TEXMF_DIST_PATH}/scripts/cjk-gs-integrate/" && \
cp -p ./cjk-gs-support/database/cjkgs-haranoaji.dat "${TEXMF_DIST_PATH}/fonts/misc/cjk-gs-integrate/" && \
rm -rf ./cjk-gs-support && \
# Update zxjafont
wget -q -O "${TEXMF_DIST_PATH}/tex/latex/zxjafont/zxjafont.sty" https://raw.githubusercontent.com/doraTeX/ZXjafont/master/zxjafont.sty && \
# Apply new font settings
mktexlsr && \
cjk-gs-integrate --cleanup --force && \
cjk-gs-integrate --force && \
kanji-config-updmap-sys --jis2004 haranoaji && \
# Re-index font database
luaotfload-tool -u -f && \
# Enable XeTeX to find fonts in TEXMFDIST and TEXMFLOCAL using fontconfig
printf "%s\n" \
"<?xml version=\"1.0\"?>" \
"<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">" \
"<fontconfig>" \
"<dir>${TEXMF_DIST_PATH}/fonts/opentype</dir>" \
"<dir>${TEXMF_DIST_PATH}/fonts/truetype</dir>" \
"<dir>${FONT_PATH}/opentype</dir>" \
"<dir>${FONT_PATH}/truetype</dir>" \
"</fontconfig>" \
> /etc/fonts/local.conf && \
fc-cache -r && \
# Install llmk
wget -q -O /usr/local/bin/llmk https://raw.githubusercontent.com/wtsnjp/llmk/master/llmk.lua && \
chmod +x /usr/local/bin/llmk
VOLUME ["/usr/local/texlive/2019/texmf-var/luatex-cache/generic/fonts/otl"]
WORKDIR /workdir
CMD ["llmk"]
イメージのビルド
$ docker build --no-cache=true -t doratex/texlive2019ja-haranoaji .
Docker Hub へのアップ
$ docker login
$ docker push doratex/texlive2019ja-haranoaji