たゆたふ。

定まる所なく揺れ動き、いろいろやってみたメモ。など

Gitbook の環境を Dockerで作った

しばらくきちんとしたドキュメント作成から遠ざかっていたのだけど、仕様書なるものを書く事になった。

基本的に文章を書くのは Markdown 形式に寄せていくようにしているので Gitbook を使うことにした。最終的に PDF にすることも簡単であろうと。

しかし、PDF 出力でハマった。その記録。

要件

目的はシステムの仕様書を書くということを踏まえ次の要件で環境を作ることにした。

  1. Markdown で記述できること
  2. UML も記載したい
    • 最低でも、クラス図、シーケンス図は書きたい
  3. PDF で出力できること

実現方法の検討

1. Markdownで記述できること

「1. Markdown で記述できること」は Gitbook を採用した時点で満たせる。
最初から Gitbook を使うつもりだったので、検討するまでもない。 ただ、ドキュメントの量が大きくなってくるとビルドに時間がかかりそうなのが気がかりだったので代替プロダクトを一応探してみた。
mdBookという Rust 製の Gitbook クローンを見つけたのだけど、mdBook 自体も言語から発展途上感が強かったので、今回は見送った。

で、当初の方針通り Gitbook を採用して進めることとした。

2. UMLも記載したい

これについては Gitbook のプラグインで解決できそうなので、どれを使うかということで探した。

mermaidを利用したものがお手軽で良さそうだったのだけど、クラス図をサポートできるものが見つからなかったので PlantUMLを利用したもので検討した。

PlantUML を利用するプラグインはいくつもある。ググってすぐ出てきたのは、plantumlなのだけど、それを改良したっぽい umlを使って見ることにした。

動作はするのだけど、gitbook serve で使っていると、UML の出力が遅くて快適に使えない。PlantUML で UMLレンダリングする際に Java でできた PlantUML を動かすために JVM の起動から始まるのが遅い原因だと思われる。

そこで、PlantUML サーバをつかって UMLレンダリングするタイプのplantuml-cloudを使ってみることにした。狙い通り UMLレンダリングは速くなった。 速度改善と同時に PlantUML に必要な graphvizのインストールも不要になった。 オフライン時も使えるようにしたいのでローカルで PlantUML のサーバである plantuml-serviceを動かすことにした。Docker イメージも提供されているので、次の Docker コンテナを動かす Docker Compose ファイルを作った。

  • plantuml-service
  • nginx
  • Giitbook

nginx は plantuml-service をリバースプロキシするために入れている。というのも plantuml-service の待受ポート番号(1608)と plantuml-cloud の接続ポート番号(80) が一致しておらず、変更もできなかったのだ。それで仕方なくリバプロして Gitbook からのリクエストを受けられるようにした。

docker-compose.yml は次の通り。

version: "2.2"
services:
  plantuml:
    image: 'bitjourney/plantuml-service:1.3.3'

  nginx:
    image: nginx:alpine
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - plantuml

  gitbook:
    image: hero/docker-gitbook:latest
    volumes:
      - ./gitbook:/gitbook
      - ./dest:/gitbook_dest
    ports:
      - 4000:4000
    depends_on:
      - nginx
    command: 'serve'

2018/11/08追記 plantuml-cloudに送っていたプルリクがマージされ、ポート番号が指定できるようになった。これに伴い nginx によるリバプロは不要になり、次の docker-compose.yml のように plantuml と gitbook だけでよくなった。

version: "2.2"
services:
  plantuml:
    image: 'bitjourney/plantuml-service:1.3.3'

  gitbook:
    image: hero/docker-gitbook:latest
    volumes:
      - ./gitbook:/gitbook
      - ./dest:/gitbook_dest
    ports:
      - 4000:4000
    depends_on:
      - plantuml
    command: 'serve'

この環境でplantuml-cloudを使うには次のように book.json で plantuml-cloud を設定する。

{
    "plugins": ["plantuml-cloud"],
    "pluginsConfig": {
      "plantuml-cloud": {
        "protocol": "http",
        "host": "plantuml",
        "port": 1608
      }
    }
}

3. PDFで出力できること

Gitbook の PDF 出力は calibreに依存している。 calibre をインストールしている他の Docker イメージを参考にしながら次のような Dcokerfile を作った。

FROM node:10.12.0-alpine
LABEL maintainer="HeRoMo"

ENV GLIBC_VERSION 2.28-r0
RUN apk add --update curl && \
    curl -Lo /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \
    curl -Lo glibc.apk "https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-${GLIBC_VERSION}.apk" && \
    curl -Lo glibc-bin.apk "https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-bin-${GLIBC_VERSION}.apk" && \
    apk add glibc-bin.apk glibc.apk && \
    /usr/glibc-compat/sbin/ldconfig /lib /usr/glibc-compat/lib && \
    echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf && \
    apk del curl && \
    rm -rf glibc.apk glibc-bin.apk /var/cache/apk/*

ENV LD_LIBRARY_PATH $LD_LIBRARY_PATH:/opt/calibre/lib
ENV PATH $PATH:/opt/calibre/bin
ENV CALIBRE_INSTALLER_SOURCE_CODE_URL https://raw.githubusercontent.com/kovidgoyal/calibre/master/setup/linux-installer.py
RUN apk update && \
    apk add --no-cache --upgrade \
    bash \
    ca-certificates \
    gcc \
    mesa-gl \
    python \
    qt5-qtbase-x11 \
    wget \
    xdg-utils \
    libxcomposite \
    xz && \
    wget -O- ${CALIBRE_INSTALLER_SOURCE_CODE_URL} | python -c "import sys; main=lambda:sys.stderr.write('Download failed\n'); exec(sys.stdin.read()); main(install_dir='/opt', isolated=True)" && \
    rm -rf /tmp/calibre-installer-cache

RUN yarn global add gitbook-cli svgexport

COPY ./start.sh /usr/bin/
RUN chmod 755 /usr/bin/start.sh

ENTRYPOINT ["start.sh"]

さて、このイメージを使って PDF を作って見ると、PDF はできるにはできるが、UML の図が表示できない。

plantuml-service では SVGUMLレンダリングしているので、PNG ならどうだろうかと試そうにも plantuml-service は SVG のみサポートなので使えない。PDF 作成時のみローカルで PlantUML を動作するようにして試してみたがダメだった。

イメージを小さくしようと alpine ベースのイメージをベースにしていたが、そのかわり calibre やそれが依存している glibc を自前でビルドするようにしていたらそこに何らかの不足があるようだ。

試しに Debian ベースのイメージをベースに作り直した。それでは calibre もパッケージマネージャでインストールできる。UML を含む PDF の出力も問題なく出力できる。

最終的に gitbook の Dockerfile は次のようになった。

FROM node:10.13.0-slim
LABEL maintainer="HeRoMo"

# install apt packages
RUN apt-get update -y && \
    apt-get install -y \
      bzip2 \
      calibre && \
    apt-get autoremove -y && \
    apt-get clean && \
    rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/*

RUN yarn global add gitbook-cli svgexport

COPY ./start.sh /usr/bin/
RUN chmod 755 /usr/bin/start.sh

ENTRYPOINT ["start.sh"]

シンプルになった。イメージのサイズは約 900MB と少々大きくなったけど。

リポジトリは次の通り。

github.com

Dockerhub はこちら。

https://hub.docker.com/r/hero/gitbook/