Hosting Zola from Kube
Static Site Generators offer a great means of easily authoring content without needing to worry about the pain of some kind runtime. Given that the target hosting location for such sites in today's cloud world are blob stores exposed as websites or other cheap hosting options if they come with any kind of hosting option it is likely aimed at development and author time.
So what then is the best way to host a site generated by one of these static site generators in Kubernetes?
Kubernetes is all about container orchestration - which is great if you can have all of the content / runtime for a site bundled up in a container for hosting. So hosting the output of an SSG in Kubernetes could be done in a strait forward manor by extending the Nginx container and copying the static site content into it.
The drawback of this approach is that you now have a container that is really only useful for one thing, and then only for as long as the content remains current. Now we could just publish only the one tag for the container, but this continues to feel at odds to the container ethos to me.
To this end I wanted built a Helm chart sets up a Kubernetes deployment that pulls a Git repository, runs Zola to generate the static site content then hosts the static content using Nginx.
Updating the site content is then as easy as pushing the change to the Git repository, and then restarting the deployment.
This is done through use of initContainers and emptyDir temporary storage.
The basic process is we define an emptyDir that will be the "scratch" space - a bit of
filesystem that is accessible to each of the initContainers as well as the main nginx
container.
spec:
template:
spec:
volumes:
- name: scratch
emptyDir: {}
initContainers are executed one by one in the order they are defined, so by we can
leverage this to pull in some basic containers for executing our fetch and build tasks
First the fetch container, where you can see we just clone the git repository. Since
Zola templates are often just git repositories, I was first using a git submodules to
install the template I was using - hence the --recurse-submodules flag. --depth=
and --shallow-submodules both improve the clone speed by only pulling a limited
history state. --branch here could be either a branch or tag name. You can see that
the scratch volume is mounted into this init container, and that we instruct git to
clone onto that volume.
- name: fetch
image: "{{ .Values.image.git.repository }}:{{ .Values.image.git.tag }}"
imagePullPolicy: {{ .Values.image.git.pullPolicy }}
args:
- clone
- --depth=1
- --recurse-submodules
- --shallow-submodules
- --branch={{ .Values.repository.branch }}
- {{ .Values.repository.url }}
- /scratch
volumeMounts:
- mountPath: /scratch
name: scratch
Next up is the build container. Since we do not need to pass any arguments to zola build
this one is much simple. Again we mount the scratch volume. We also set that volume as
the working directory for the container, since zola build expects the current working
directory to contain the site to be build.
- name: build
image: "{{ .Values.image.zola.repository }}:{{ .Values.image.zola.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.zola.pullPolicy }}
workingDir: /scratch
args:
- build
volumeMounts:
- mountPath: /scratch
name: scratch
Last up is the actual nginx container that does the actual hosting. This is pretty much
left intact from the helm create process. The main things to note are again, mounting
scratch volume.
Well that is mostly a brain dump on how I setup hosing a Zola generated site in Kubernetes. If you stumble across this, I hope you find it useful.