こんにちは。(ほ)です。

 

前回、GitbookのプロジェクトをCodePipeline, CodeBuildを使用してビルドをする方法について記載しました。
しかし、PDFのビルドについては触れていませんでしたので、今回はPDFを作成したいと思います。

GitbookのPDF作成で発生するエラーと対処

GitbookでPDFを作成する場合は下記のようなコマンドを使用します。

# HTML作成
$ gitbook build
# PDF作成
$ gitbook pdf

しかし、CodeBuildで実行すると下記の4つのエラーが発生するため対処が必要です。

1. ebook-convertが未インストール

GitbookでPDFを作成するにはcalibreというebook-converterが必要です。
未インストールの場合は下記のようなエラーが出力されます。

InstallRequiredError: "ebook-convert" is not installed.
Install it from Calibre: https://calibre-ebook.com

下記のコマンドでcalibreをインストールすることで対処できます。

apt-get update
apt-get install calibre

2. X server がない

GitbookでPDFを作成するにはディスプレイバッファが必要なのですが、CodeBuildなどのヘッドレス環境では存在しないため下記のようなエラーが出力されます。

Traceback (most recent call last):
File "/usr/bin/ebook-convert", line 20, in <module>
sys.exit(main())
File "/usr/lib/calibre/calibre/ebooks/conversion/cli.py", line 359, in main
plumber.run()
File "/usr/lib/calibre/calibre/ebooks/conversion/plumber.py", line 1189, in run
self.opts, self.log)
File "/usr/lib/calibre/calibre/ebooks/conversion/plugins/pdf_output.py", line 123, in convert
must_use_qt()
File "/usr/lib/calibre/calibre/gui2/__init__.py", line 1041, in must_use_qt
raise RuntimeError('X server required. If you are running on a'
RuntimeError: X server required. If you are running on a headless machine, use xvfb

これはエラーメッセージにも出力されているとおり “xvfb” を使用することで対処できます。

apt-get update
apt-get install xvfb
xvfb-run gitbook pdf

3. 日本語が文字化けする

CodeBuildの環境には日本語フォントが含まれていないため文字化けしてしまいます。

下記のようにフォントをインストールすることで対処できます。

apt-get update
apt-get install fonts-ipafont-gothic fonts-ipafont-mincho

4. Apple iTunes interface プラグインの初期化エラー

Calibreのプラグインの初期化時にエラーが発生します。

[0;31mEbookError: Error during ebook generation: Failed to initialize plugin: Apple iTunes interface (1, 1, 1)
Failed to initialize plugin: <class 'calibre.devices.apple.driver.ITUNES'>
Traceback (most recent call last):
File "/usr/bin/ebook-convert", line 20, in <module>
sys.exit(main())
File "/usr/lib/calibre/calibre/ebooks/conversion/cli.py", line 341, in main
parser, plumber = create_option_parser(args, log)
File "/usr/lib/calibre/calibre/ebooks/conversion/cli.py", line 294, in create_option_parser
from calibre.ebooks.conversion.plumber import Plumber
File "/usr/lib/calibre/calibre/ebooks/conversion/plumber.py", line 16, in <module>
from calibre.utils.date import parse_date
File "/usr/lib/calibre/calibre/utils/date.py", line 13, in <module>
from dateutil.tz import tzlocal, tzutc, EPOCHORDINAL
File "/usr/local/lib/python2.7/dist-packages/dateutil/tz/__init__.py", line 1, in <module>
from .tz import *
File "/usr/local/lib/python2.7/dist-packages/dateutil/tz/tz.py", line 23, in <module>
from ._common import tzname_in_python2, _tzinfo, _total_seconds
File "/usr/local/lib/python2.7/dist-packages/dateutil/tz/_common.py", line 2, in <module>
from six.moves import _thread
ImportError: cannot import name _thread

ログを見ると “_thread” が import出来なくて発生しているようです。

別件ですが、同様のエラーが下記でも報告されています。

どうも、python-dateutilの2.6.0以降で発生するようですので、下記のように古いバージョンをインストールすることで回避できます。

pip uninstall -y python-dateutil
pip install python-dateutil==2.5.3

buildspec.yml

上記の4つのエラーに対処すると、下記のようなbuildspec.ymlが出来上がります。

version: 0.2
phases:
install:
commands:
- apt-get update
- apt-get install -y calibre xvfb fonts-ipafont-gothic fonts-ipafont-mincho
- pip uninstall -y python-dateutil
- pip install python-dateutil==2.5.3
- npm install -g gitbook-cli
pre_build:
commands:
- gitbook install
build:
commands:
- xvfb-run gitbook pdf
post_build:
commands:
- ls -la
artifacts:
files:
- book.pdf

このbuildspec.ymlを使用することで日本語を含むPDFを作成することが出来たのですが、HTMLのビルドに比べてinstall phaseに時間がかかってしまいます。
(当然、それに合わせて使用料も上がります。一番安い環境で $0.005/分)

そこで、CodeBuildで用意されている標準の環境イメージではなく、PDF作成用のイメージを作成してみたいと思います。

Docker Imageの作成

Docker Imageを作成する方法はいくつかあるのですが、CodeBuildで使用する必要があるため、下記で公開されているCodeBuildの標準イメージのDockerfileを参考にするのが良いと思います。

Dockerfile

私の場合はnodejs:7.0.0環境をベースに下記のようなDockerfileを作成しました。
(&などがエスケープされています)

FROM ubuntu:14.04.5
# Building git from source code:
# Ubuntu's default git package is built with broken gnutls. Rebuild git with openssl.
##########################################################################
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
wget python python2.7-dev fakeroot ca-certificates tar gzip zip \
autoconf automake bzip2 file g++ gcc imagemagick libbz2-dev libc6-dev libcurl4-openssl-dev \
libdb-dev libevent-dev libffi-dev libgeoip-dev libglib2.0-dev libjpeg-dev libkrb5-dev \
liblzma-dev libmagickcore-dev libmagickwand-dev libmysqlclient-dev libncurses-dev libpng-dev \
libpq-dev libreadline-dev libsqlite3-dev libssl-dev libtool libwebp-dev libxml2-dev libxslt-dev \
libyaml-dev make patch xz-utils zlib1g-dev unzip curl calibre xvfb fonts-ipafont-gothic fonts-ipafont-mincho \
&& apt-get -qy build-dep git \
&& apt-get -qy install libcurl4-openssl-dev git-man liberror-perl \
&& mkdir -p /usr/src/git-openssl \
&& cd /usr/src/git-openssl \
&& apt-get source git \
&& cd $(find -mindepth 1 -maxdepth 1 -type d -name "git-*") \
&& sed -i -- 's/libcurl4-gnutls-dev/libcurl4-openssl-dev/' ./debian/control \
&& sed -i -- '/TEST\s*=\s*test/d' ./debian/rules \
&& dpkg-buildpackage -rfakeroot -b \
&& find .. -type f -name "git_*ubuntu*.deb" -exec dpkg -i \{\} \; \
&& rm -rf /usr/src/git-openssl \
# Install dependencies by all python images equivalent to buildpack-deps:jessie
# on the public repos.
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
RUN wget "https://bootstrap.pypa.io/get-pip.py" -O /tmp/get-pip.py \
&& python /tmp/get-pip.py \
&& pip install awscli==1.11.25 \
&& pip uninstall -y python-dateutil \
&& pip install python-dateutil==2.2 \
&& rm -fr /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENV NODE_VERSION="7.0.0"
RUN set -ex \
&& for key in \
9554F04D7259F04124DE6B476D5A82AC7E37093B \
94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \
0034A06D9D9B0064CE8ADF6BF1747F4AD2306D93 \
FD3A5288F042B6850C66B31F09FE44734EB7990E \
71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \
DD8F2338BAE7501E3DD5AC78C273792F7D83545D \
B9AE9905FFD7803F25714661B63B535A4C206CA9 \
C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
; do \
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \
done
RUN wget "https://nodejs.org/download/release/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" -O node-v$NODE_VERSION-linux-x64.tar.gz \
&& wget "https://nodejs.org/download/release/v$NODE_VERSION/SHASUMS256.txt.asc" -O SHASUMS256.txt.asc \
&& gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
&& grep " node-v$NODE_VERSION-linux-x64.tar.gz\$" SHASUMS256.txt | sha256sum -c - \
&& tar -xzf "node-v$NODE_VERSION-linux-x64.tar.gz" -C /usr/local --strip-components=1 \
&& rm "node-v$NODE_VERSION-linux-x64.tar.gz" SHASUMS256.txt.asc SHASUMS256.txt \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs \
&& rm -fr /var/lib/apt/lists/* /tmp/* /var/tmp/*
CMD [ "node" ]
RUN npm install -g gitbook-cli svgexport

作成したDocker Imageは、DockerHubで公開したり、Amazon EC2 Container Registryに登録することでCodeBuildから使用することができます。

CodeBuildの設定

CodeBuildの「環境: ビルド方法」を下記のように変更します。

  • 環境イメージ : Docker イメージの指定
  • 環境タイプ : Linux
  • カスタムイメージタイプ : Other(DockerHub) or Amazon ECR(Container Registry)
  • カスタムイメージ ID : repo-name/image-name:tag

カスタムイメージ ID の tag は latest の場合は不要ですが、その他の場合は必須です。

まとめ

Docker ImageをCodeBuildで使用すると、buildspec.ymlの時よりも install phase分を短くすることができます。

buildspec.yml(3分28秒)

Docker Image(1分34秒)

install phaseに時間がかかっている場合は、Docker Imageを使用することを考えてみてください。