テクノロジの無駄づかい

日々の「ステュディオス」を求めて遠回りしがちなエンジニアの記録

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を動かすためにJavaVMの起動から始まるのが遅い原因だと思われる。

そこで、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/