Generate your Hugo asciidoc website using docker
We previously saw how to generate a blog with Hugo and Asciidoc. This article explains how to do it using a docker container.
Why?
To generate the site content, we need some tools:
-
Ruby gems (Asciidoctor, Rouge)
-
Hugo
That may not be much but those tools have dependencies, that may lead to installing a lot of packages on our system.
And what about those dependencies when they change and begin to cause compatibility problems with other programs? What if they require more and more dependencies?
Using docker frees us from those dependencies, docker being the only one remaining.
A container is also perfect for a development environment. We will use the container for both generating the website static files and acting as a development server.
How?
Docker should already be installed, otherwise just follow the installation procedure.
Building the image
I was once more inspired by René Gielen’s article but I chose a less complex solution:
-
I based my image on Ruby on which I installed rouge and Hugo
-
I chose not to install some things, that were no use to me at this stage
-
I changed the entrypoint since I wanted to be able to launch other commands from the container than
hugo
(e.g:asciidoctor
)
Here’s how to do it:
In a hugo-asciidoc-builder
subdirectory, create the following files:
#!/bin/bash
set -e
exec "$@"
# Greatly inspired from https://rgielen.net/posts/2019/creating-a-dockerized-hugo-asciidoctor-toolchain/#_creating_a_hugoasciidoc_toolchain_image
FROM ruby:2.7
ARG HUGO_VERSION=0.64.1 (1)
RUN gem install asciidoctor rouge
ADD https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz /tmp/hugo.tgz
RUN tar -xzf /tmp/hugo.tgz -C /usr/local/bin/ && rm /tmp/hugo.tgz
COPY ./docker-entrypoint.sh /
ENTRYPOINT [ "/docker-entrypoint.sh" ]
CMD [ "hugo", "--help" ]
1 | Don’t forget to use an up-to-date version. I rather fix the version to make sure that I am able to reproduce the same result each time I rebuild the image. |
Then, from the same subdirectory, build the image (do not forget the trailing dot .
):
docker build -t hugo-asciidoc-builder .
We should now have a hugo-asciidoc-builder
image available when we run docker images
:
REPOSITORY TAG IMAGE ID CREATED SIZE
hugo-asciidoc-builder latest 01dc064eb95f 8 days ago 901MB
We can see the image is quite large, we could greatly reduce it by using ruby:2.7-alpine as our base image instead of ruby:2.7 which is based on Ubuntu.
|
Running the image
We can now put our new image to work.
From the hugo project root:
docker run \
--rm \ (1)
-v $(pwd):/source \ (2)
-p 127.0.0.1:1313:1313 \ (3)
hugo-asciidoc-builder \
hugo serve -D -s /source --bind "0.0.0.0" (4)
1 | We want the container to be deleted after the execution |
2 | We mount the current directory in a source directory in the container root |
3 | To replicate the default behaviour of the server mode of hugo, we publish the 1313 port of our container on the localhost interface of our host.
If we wanted to make it available to other hosts of our network, we would rather use -p 1313:1313 |
4 | Several comments here:
|
docker run \
--user $(id -u):$(id -g) \ (1)
--rm \
-v $(pwd):/source \
hugo-asciidoc-builder \
hugo -s /source -b https://mydomain.tld (2)
1 | We make the container use an account with the same user and group id as the person running it. Now all the files are going to be created with the correct ownership. Otherwise they would have belonged to root, requiring admin rights to be modified. |
2 | Hugo needs to know the URL of the website being built in order to generate the correct links. Note that we don’t need to publish any port, neither do we need to set the listening interface for hugo since we are not running the server mode anymore. |
All that’s left to do is to transfer the content of the public
directory to the root of our web server.
Docker compose
OK, now we can do everything we need but did not have to install anything on our computer except docker. That’s nice but it’s a little cumbersome to have to set multiple options each time we want to run our development server or build our site.
Let’s create two little scripts:
#!/bin/bash
docker run \
--rm \
-v $(pwd):/source \
-p 127.0.0.1:1313:1313 \
hugo-asciidoc-builder \
hugo serve -D -s /source --bind "0.0.0.0"
#!/bin/bash
docker run \
--user $(id -u):$(id -g) \
--rm \
-v $(pwd):/source \
hugo-asciidoc-builder \
hugo -s /source -b https://mydomain.tld
Make them executable chmod +x launch-web-server.sh generate-web-site.sh
then run them:
-
./launch-web-server.sh
-
./generate-web-site.sh
Normaly I would use a docker-compose file but since we only need to run a simple container that’s good enough. Furthermore it saves us from installing an additional dependency.
Okay, while we’re at it, let’s see the docker-compose way:
-
Create a
docker-compose.yml
file--- version: '3' services: hugo-asciidoc-builder: build: hugo-asciidoc-builder working_dir: /source command: hugo serve -D --disableFastRender --bind "0.0.0.0" (1) ports: - "127.0.0.1:1313:1313" volumes: - ".:/source"
1 I added the --disableFastRender
option to make sure the site is entirely rebuilt on every change. Right now I don’t have lots of content so the generation does not take much time but it will probably change later.
Note that I don’t use the UID and GID variables. Since the server mode does not generate any file in the current directory it would be useless.
To run the server: docker-compose up