Hugo が動く最小構成の Docker イメージを作る

Hugo や Hugo extended が動作する Docker image の作成方法について知見をまとめます。


## Hugo の Docker image

**現在 Hugo 公式 (gohugoio) が提供する Docker image はありません。**

Docker Hub に gohugoio のアカウントがありますが、あれは GoHugoIO が管理しているものではありません。

手っ取り早く Hugo の Docker image が欲しい方は私が管理しているものを良かったら使ってください。新しいリリースがあればその日のうちに更新するようにしています。

CircleCI や GitLab CI/CD で使いたい場合は以下のイメージをどうぞ。

- [peaceiris/hugo-extended-docker: Docker image of Hugo (Hugo extended and Hugo Modules)](https://github.com/peaceiris/hugo-extended-docker)

以下のリポジトリも色々なイメージを取り揃えていて便利です。

- [klakegg/hugo - Docker Hub](https://hub.docker.com/r/klakegg/hugo/)

GitHub Actions は以下をどうぞ。

- [peaceiris/actions-hugo: GitHub Actions for Hugo extended and Modules](https://github.com/peaceiris/actions-hugo)

## Dockerfile の例

以下に Hugo extended が動作する最小構成の Dockerfile を示します。最新のものは [hugo-extended-docker/Dockerfile](https://github.com/peaceiris/hugo-extended-docker/blob/master/Dockerfile) を確認してください。

```Dockerfile
FROM alpine:3.10

ENV HUGO_VERSION='0.59.0'
ENV HUGO_NAME="hugo_extended_${HUGO_VERSION}_Linux-64bit"
ENV HUGO_BASE_URL="https://github.com/gohugoio/hugo/releases/download"
ENV HUGO_URL="${HUGO_BASE_URL}/v${HUGO_VERSION}/${HUGO_NAME}.tar.gz"
ENV HUGO_CHECKSUM_URL="${HUGO_BASE_URL}/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_checksums.txt"

WORKDIR /hugo
SHELL ["/bin/ash", "-eo", "pipefail", "-c"]
RUN apk add --no-cache --virtual .build-deps wget && \
    apk add --no-cache \
    git \
    ca-certificates \
    libc6-compat \
    libstdc++ && \
    wget --quiet "${HUGO_URL}" && \
    wget --quiet "${HUGO_CHECKSUM_URL}" && \
    grep "${HUGO_NAME}.tar.gz" "./hugo_${HUGO_VERSION}_checksums.txt" | sha256sum -c - && \
    tar -zxvf "${HUGO_NAME}.tar.gz" && \
    mv ./hugo /usr/bin/hugo && \
    apk del .build-deps && \
    rm -rf /hugo

WORKDIR /src
ENTRYPOINT [ "/usr/bin/hugo" ]
```

`docker build` して `docker image ls` で image size を確認すると 64MB だと分かります。

extended を実行するために `libc6-compat` と `libstdc++` が必要です。

Hugo Modules の機能を利用したい場合は base image を `golang:1.13-alpine3.10` に変更してください。

このイメージの使い方を以下に示します。

```sh
# Pull Docker image
docker pull peaceiris/hugo:v0.59.0

# Run `hugo version`
docker run --rm -i -t hugo:v0.59.0 version

# Build site
docker run --rm -i -t -v ${PWD}:/src peaceiris/hugo:v0.59.0

# Run `hugo server`
docker run --rm -i -t -v ${PWD}:/src -p 1313:1313 peaceiris/hugo:v0.59.0 server --bind=0.0.0.0
```

あとは `docker-compose.yml` や `Makefile` で上記を扱いやすくすると良いでしょう。Docker compose の例はリポジトリで紹介しているので参考にしてください。



## なるべく Docker を避ける

ローカル環境で動作させる Hugo はなるべくバイナリのものを使うべきです。[Install Hugo | Hugo](https://gohugo.io/getting-started/installing/) を参考にして

- macOS なら Homebrew
- Linux なら Snap や Linuxbrew
- Windows なら Chocolatey や Scoop

を使ってバイナリをダウンロードして使いましょう。もしくは [Releases · gohugoio/hugo](https://github.com/gohugoio/hugo/releases) から直接ダウンロードもできます。

CI/CD でも手元のPCでも Hugo はバイナリのものが良いです。理由は以下の通りです。

### イメージサイズが大きい

ただの Hugo を alpine 上で動かすのであれば 64MB くらいには収まります。ですが  `v0.56` から導入された Hugo Modules を使いたい場合には Golang が必要になり、たちまちイメージサイズが膨れ上がります。Hugo のすべての機能が使えるイメージを作ると 417MB くらいになります。

この記事で言うところのイメージサイズは `docker images` や `docker image ls` で確認できる容量のことです。



## Hugo on Docker の使いどころ

バイナリ Hugo をオススメしましたが、

- Version を固定したい
- チームで同じ Version を共有したい
- 複数 Version を共存させたい

のような場面では Docker が便利だと思います。



## Hugo の依存

最近の Hugo は連携できる外部ツールも増えて、すべての機能を利用する場合にはイメージサイズを小さくすることが難しくなりました。

### Git

[Lastmod](https://gohugo.io/variables/git/#lastmod) などを使ってコミットから情報を得るには Git がインストールされている必要があります。まぁ Git くらいならサイズは気にならないでしょう。

### glibc

Hugo には SASS/SCSS のトランスコンパイルができる Hugo extended version が存在します。その Hugo extended が動作する alpine ベースの Docker image を作るには `glibc` を含める必要があります。

### Hugo Modules

- [Hugo v0.56 新機能 Modules と deploy - Qiita](https://qiita.com/peaceiris/items/fa71db25080756e9a9bf)

`v0.56` から導入された Hugo Modules は Go Modules と Git に依存しています。従って Hugo Modules が利用できる Docker image にはGo言語の環境を含めなければなりません。この時点でイメージサイズは alpine 系でも 417MB 近くになります。

### Node.js

autoprefixer, postcss-cli, babel などと連携させるには必要になります。

### Ruby

asciidoctor と連携したい場合に必要になります。