270 lines
8.8 KiB
Markdown
270 lines
8.8 KiB
Markdown
+++
|
|
title = 'Hugo on Kubernetes & NGINX'
|
|
date = 2024-02-28T15:35:46-08:00
|
|
draft = true
|
|
series = ['wtf']
|
|
categories = ['Tech']
|
|
tags = ['meta', 'k8s']
|
|
+++
|
|
|
|
i decided to make a website. a static one. this one. with [Hugo][hugo]. this
|
|
is basically as a vanity project so i have some stuff to host in a
|
|
[Kubernetes][k8s] cluster i'm running. the k8s cluster is also as a vanity
|
|
project.
|
|
|
|
because i don't like software, i wanted a way to deploy my site that
|
|
doesn't involve much of it. this post is about that.
|
|
|
|
## Getting Started
|
|
|
|
i built my site by following the straight-forward _[Getting Started][hugo-started]_
|
|
guide in the Hugo documentation.
|
|
|
|
i did `hugo new site estradiol.cloud`. and then `cd estradiol.cloud; git init`. and
|
|
then i picked a ridiculous theme ["inspired by terminal ricing aesthetics"][risotto],
|
|
installing it like `git submodule add https://github.com/joeroe/risotto.git themes/risotto; echo "theme = 'risotto'" >> hugo.toml`. i appreciate the culinary naming choice.
|
|
|
|
at this point, my website is basically finished (i also changed the title in `hugo.toml`).
|
|
i probably won't be putting anything on it, so there's no point fiddling with other
|
|
details.
|
|
|
|
about deployment, the guide's _[Basic Usage][hugo-deploy]_ page has this to offer:
|
|
|
|
> Most of our users deploy their sites using a CI/CD workflow, where a push{{< sup "1" >}}
|
|
> to their GitHub or GitLab repository triggers a build and deployment. Popular
|
|
> providers include AWS Amplify, CloudCannon, Cloudflare Pages, GitHub Pages,
|
|
> GitLab Pages, and Netlify.
|
|
>
|
|
> 1. The Git repository contains the entire project directory, typically excluding the
|
|
> public directory because the site is built _after_ the push.
|
|
|
|
importantly, you can't make a post about deploying this way. _everyone_ deploys
|
|
this way. if _i_ deploy this way, this site will have no content.
|
|
|
|
it also involves some system somewhere that can run Hugo to build the site and push
|
|
it to some remote system where my cluster can reach the `public/` output. i definitely
|
|
already need Hugo installed on my workstation if i'm going to post anything here
|
|
(unlikely), so now i'm running Hugo in two places. there's surely going to be
|
|
other complex nonsense like webhooks involved.
|
|
|
|
<!-- diagram ?? -->
|
|
|
|
----
|
|
|
|
and hang on. let's look at this again:
|
|
|
|
> 1. The Git repository contains the entire project directory, typically excluding the
|
|
> public directory because the site is built _after_ the push.
|
|
|
|
you're telling me i'm going to build a nice static site and not check the
|
|
_actual content_ into version control? couldn't be me.
|
|
|
|
## Getting Static
|
|
|
|
what if instead i pushed my site to a git repository exactly as i intend to serve it?
|
|
then i could shell into my web server, pull the site, and _nifty-galifty!_ isn't this
|
|
the way it has [always been done][worm]?
|
|
|
|
one problem is that i don't have a web server, i have a _container orchestration
|
|
system_. there are several upsides to this (few of which are relevant for my project)
|
|
but it also means that _somehow_ my content needs to end up in a container, and i
|
|
don't want that container to need to retain state across restarts or replicas.
|
|
|
|
i _could_ run a little pipeline that builds a container wrapping my static site,
|
|
pushes it to a registry somewhere my deployments can pull it. all ready to go.
|
|
but now i've got _software_ again: build stages and webhooks and to make matters
|
|
worse, now i'm hosting and versioning container images.
|
|
|
|
<!-- diagram ?? -->
|
|
|
|
i don't want any of this.
|
|
|
|
---
|
|
|
|
instead, i'd like to deploy a popular stock container from a public registry and
|
|
deliver my content to it continuously.
|
|
|
|
as a minimal version of this, i could do:
|
|
|
|
```yaml
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: nginx
|
|
namespace: ec
|
|
labels:
|
|
app.kubernetes.io/instance: estradiol-cloud
|
|
app.kubernetes.io/name: nginx
|
|
spec:
|
|
containers:
|
|
- name: nginx
|
|
image: nginx:1.25.4
|
|
ports:
|
|
- containerPort: 80
|
|
volumeMounts:
|
|
- mountPath: /app
|
|
name: staticsite
|
|
- name: git-pull
|
|
image: bitnami/git
|
|
command:
|
|
- /bin/bash
|
|
- -ec
|
|
- |
|
|
while true; do
|
|
cd /app && git -c safe.directory=/app pull origin trunk
|
|
sleep 60
|
|
done
|
|
volumeMounts:
|
|
- mountPath: /app
|
|
name: staticsite
|
|
initContainers:
|
|
- name: git-clone
|
|
image: bitnami/git
|
|
command:
|
|
- /bin/bash
|
|
- -ec
|
|
- |
|
|
git clone https://code.estradiol.cloud/tamsin/estradiol.cloud.git --no-checkout --branch trunk /tmp/app
|
|
cd /tmp/app && git sparse-checkout init --cone
|
|
git sparse-checkout set public && git checkout
|
|
rm -rf /app && mv /tmp/app /app
|
|
volumeMounts:
|
|
- mountPath: /app
|
|
name: staticsite
|
|
volumes:
|
|
- emptyDir: {}
|
|
name: staticsite
|
|
|
|
---
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
labels:
|
|
app.kubernetes.io/instance: estradiol-cloud
|
|
app.kubernetes.io/name: nginx
|
|
name: nginx-server-block
|
|
namespace: ec
|
|
data:
|
|
server-block.conf: |-
|
|
server {
|
|
listen 8080;
|
|
root /app/public;
|
|
index index.html;
|
|
}
|
|
```
|
|
|
|
|
|
<!-- ```yaml -->
|
|
<!-- apiVersion: apps/v1 -->
|
|
<!-- kind: Deployment -->
|
|
<!-- metadata: -->
|
|
<!-- labels: -->
|
|
<!-- app.kubernetes.io/instance: estradiol-cloud -->
|
|
<!-- app.kubernetes.io/name: nginx -->
|
|
<!-- name: web-nginx -->
|
|
<!-- namespace: estradiol-cloud -->
|
|
<!-- spec: -->
|
|
<!-- replicas: 1 -->
|
|
<!-- selector: -->
|
|
<!-- matchLabels: -->
|
|
<!-- app.kubernetes.io/instance: estradiol-cloud -->
|
|
<!-- app.kubernetes.io/name: nginx -->
|
|
<!-- template: -->
|
|
<!-- metadata: -->
|
|
<!-- labels: -->
|
|
<!-- app.kubernetes.io/instance: estradiol-cloud -->
|
|
<!-- app.kubernetes.io/name: nginx -->
|
|
<!-- spec: -->
|
|
<!-- containers: -->
|
|
<!-- - name: git-repo-syncer -->
|
|
<!-- image: docker.io/bitnami/git:2.43.2-debian-12-r2 -->
|
|
<!-- imagePullPolicy: IfNotPresent -->
|
|
<!-- command: -->
|
|
<!-- - /bin/bash -->
|
|
<!-- - -ec -->
|
|
<!-- - | -->
|
|
<!-- while true; do -->
|
|
<!-- cd /app && git -c safe.directory=/app pull origin trunk -->
|
|
<!-- sleep 60 -->
|
|
<!-- done -->
|
|
<!-- volumeMounts: -->
|
|
<!-- - mountPath: /app -->
|
|
<!-- name: staticsite -->
|
|
<!-- - name: nginx -->
|
|
<!-- image: docker.io/bitnami/nginx:1.25.4-debian-12-r2 -->
|
|
<!-- imagePullPolicy: IfNotPresent -->
|
|
<!-- env: -->
|
|
<!-- - name: NGINX_HTTP_PORT_NUMBER -->
|
|
<!-- value: "8080" -->
|
|
<!-- livenessProbe: -->
|
|
<!-- tcpSocket: -->
|
|
<!-- port: http -->
|
|
<!-- readinessProbe: -->
|
|
<!-- tcpSocket: -->
|
|
<!-- port: http -->
|
|
<!-- ports: -->
|
|
<!-- - containerPort: 8080 -->
|
|
<!-- name: http -->
|
|
<!-- protocol: TCP -->
|
|
<!-- volumeMounts: -->
|
|
<!-- - mountPath: /opt/bitnami/nginx/conf/server_blocks -->
|
|
<!-- name: nginx-server-block -->
|
|
<!-- - mountPath: /app -->
|
|
<!-- name: staticsite -->
|
|
<!-- initContainers: -->
|
|
<!-- - name: git-clone-repository -->
|
|
<!-- image: docker.io/bitnami/git:2.43.2-debian-12-r2 -->
|
|
<!-- imagePullPolicy: IfNotPresent -->
|
|
<!-- command: -->
|
|
<!-- - /bin/bash -->
|
|
<!-- - -ec -->
|
|
<!-- - | -->
|
|
<!-- [[ -f "/opt/bitnami/scripts/git/entrypoint.sh" ]] && source "/opt/bitnami/scripts/git/entrypoint.sh" -->
|
|
<!-- git clone https://code.estradiol.cloud/tamsin/estradiol.cloud.git --no-checkout --branch trunk /tmp/app -->
|
|
<!-- [[ "$?" -eq 0 ]] && cd /tmp/app && git sparse-checkout init --cone && git sparse-checkout set public && git checkout && shopt -s dotglob && rm -rf /app/* && mv /tmp/app/* /app/ -->
|
|
<!-- volumeMounts: -->
|
|
<!-- - mountPath: /app -->
|
|
<!-- name: staticsite -->
|
|
<!-- restartPolicy: Always -->
|
|
<!-- terminationGracePeriodSeconds: 30 -->
|
|
<!-- volumes: -->
|
|
<!-- - configMap: -->
|
|
<!-- defaultMode: 420 -->
|
|
<!-- name: web-nginx-server-block -->
|
|
<!-- name: nginx-server-block -->
|
|
<!-- - emptyDir: {} -->
|
|
<!-- name: staticsite -->
|
|
<!-- ``` -->
|
|
|
|
## Getting Flux'd
|
|
|
|
```yaml
|
|
apiVersion: source.toolkit.fluxcd.io/v1beta2
|
|
kind: HelmRepository
|
|
metadata:
|
|
name: bitnami
|
|
namespace: default
|
|
spec:
|
|
url: https://charts.bitnami.com/bitnami
|
|
```
|
|
|
|
```yaml
|
|
apiVersion: source.toolkit.fluxcd.io/v1beta2
|
|
kind: HelmRepository
|
|
metadata:
|
|
name: bitnami
|
|
namespace: default
|
|
spec:
|
|
url: https://charts.bitnami.com/bitnami
|
|
```
|
|
|
|
|
|
[hugo]: https://gohugo.io
|
|
[hugo-deploy]: https://gohugo.io/getting-started/usage/#deploy-your-site
|
|
[hugo-started]: https://gohugo.io/getting-started
|
|
[k8s]: https://kubernetes.io
|
|
[k8s-init]: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
|
|
[k8s-pv]: https://kubernetes.io/docs/concepts/storage/persistent-volumes/
|
|
[risotto]: https://github.com/joeroe/risotto
|
|
[worm]: https://www.mikecurato.com/worm-loves-worm
|