TeX Live 2019 + 原ノ味フォント + llmk の Docker コンテナを作る

Docker を使い始めて間もない Docker 初心者の感想ですが,Docker を使えば,普段使いの TeX Live 環境とは別に古い TeX 環境を保管しておいたり,あるいは逆に先端の開発中ブランチを試しに導入できたりと,色々便利そうですね。

というわけで今回は,Docker の練習がてらに TeX Live 2019 + 原ノ味フォント + llmk でコンパイルできる Docker コンテナを作ってみました。

目標

とりあえず完成品を使うには

イメージの 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_docoption_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-fontmapscjk-gs-integrate の GitHub 上の最新版を取得して TEXMFDIST 内のファイルを差し替えて対応します。

XeLaTeX

ZXjafont パッケージharanoaji プリセットがまだ用意されていなかったので,fork して付け加えました。とりあえずこれを取得して TEXMFDIST 内のファイルを差し替えて対応します。

Dockerfile でやること

Dockerfile によるイメージのビルドにおいては,大まかに次のことを行います。

  1. TeX Live 2019 の最新版をネットワークインストール。
  2. 原ノ味フォントを GitHub レポジトリから取得して TEXMFLOCAL 内にインストール。
  3. 原ノ味フォントに対応した最新版 ptex-fontmaps を GitHub レポジトリから取得して TEXMFDIST 内に配置。
  4. 原ノ味フォントに対応した最新版 cjk-gs-integrate を GitHub レポジトリから取得して TEXMFDIST 内に配置。
  5. 原ノ味フォントに対応したフォーク版の zxjafont を GitHub レポジトリから取得して TEXMFDIST 内に配置。
  6. mktexlsr して原ノ味フォントを TeX システムに認識させる。
  7. cjk-gs-integrate を走らせて Ghostscript の原ノ味フォント対応。
  8. kanji-config-updmap-sys で (u)pLaTeX の既定の和文フォントを原ノ味フォントにする。
  9. 最新版の llmk を GitHub レポジトリから取得して /usr/local/bin に配置。

課題の解決

XeTeX に TEXMF ツリー内のフォントを認識させる

Linux の場合,XeTeX は fontconfig を利用してフォントを見つけていますが,上記手順では原ノ味フォントをTEXMFLOCAL 内に配置しましたので,fontconfig がそれを見つけられません。そこで,次のような内容を記載した XML ファイルを /etc/fonts/local.conf として保存しておきます。こうすることで TEXMFDISTTEXMFLOCAL 内のフォントを XeTeX が見つけられるようになります。

local.conf
<?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

Dockerfile
FROM ubuntu:19.10

LABEL maintainer="doraTeX &lt;taylorkgb [at] gmail.com&gt;"

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
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account