more WIP on the meta post

This commit is contained in:
tamsin woo 2024-03-09 01:42:20 -08:00
parent e0722d1b49
commit b10ee995ca
19 changed files with 2969 additions and 36 deletions

View File

@ -4,3 +4,38 @@ title: |md
shape: text
near: top-center
}
my laptop -> GitHub.repo: git push
my laptop {
icon: https://icons.terrastruct.com/tech%2Flaptop.svg
near: center-left
}
GitHub {
icon: https://icons.terrastruct.com/social%2F039-github.svg
runner {
build job
deploy job
}
repo <- runner.build job: pull
events api <- runner: long poll
image registry {
"estradiol-cloud:latest"
}
runner.build job -> "image registry"."estradiol-cloud:latest": push
}
GitHub.runner.deploy job -> "kubernetes": kubectl apply
kubernetes {
icon: https://icons.terrastruct.com/azure%2F_Companies%2FKubernetes.svg
nginx pod
}
kubernetes.nginx pod -> GitHub."image registry"."estradiol-cloud:latest": pull

30
.d2/hugo-helm-setup.d2 Normal file
View File

@ -0,0 +1,30 @@
title: |md
# deploy w/ helm & bitnami/nginx
| {
shape: text
near: top-center
}
my laptop -> repo: git push
my laptop -> kubernetes: `kubectl apply`
kubernetes {
icon: https://icons.terrastruct.com/azure%2F_Companies%2FKubernetes.svg
ingress -> service
service -> pod(s)
pod(s) {
git-pull -> emptyDir: mounts
nginx -> emptyDir: mounts
emptyDir { icon: https://icons.terrastruct.com/tech%2Fdiskette.svg }
}
pod(s).nginx -> configMap: mounts
}
kubernetes.pod(s).git-pull -> repo: pull
web {
icon: https://icons.terrastruct.com/essentials%2F140-internet.svg
}
web -> kubernetes.ingress

View File

@ -0,0 +1,22 @@
title: |md
# deploy w/ kubectl apply
| {
shape: text
near: top-center
}
my laptop -> repo: git push
my laptop -> kubernetes: `kubectl apply`
kubernetes {
icon: https://icons.terrastruct.com/azure%2F_Companies%2FKubernetes.svg
pod {
git-pull -> emptyDir: mounts
nginx -> emptyDir: mounts
emptyDir { icon: https://icons.terrastruct.com/tech%2Fdiskette.svg }
}
pod.nginx -> configMap: mounts
}
kubernetes.pod.git-pull -> repo: pull

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 146 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 151 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 136 KiB

View File

@ -9,9 +9,9 @@ toc = true
+++
i decided to make a website. a static one. this one. with [Hugo][hugo]. the
main reason i have for this is 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.
main reason i have for needing a website is as a vanity project, because i need
some stuff to host in a [Kubernetes][k8s] cluster i'm running. the k8s cluster
is also 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.
@ -27,13 +27,14 @@ and then i picked a ridiculous theme
submodule add https://github.com/joeroe/risotto.git themes/risotto; echo "theme
= 'risotto'" >> hugo.toml`.[^1]
[^1]: i appreciate the culinary theme.
[^1]: i appreciate the culinary branding.
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.
`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:
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
@ -46,15 +47,15 @@ about deployment, the guide's _[Basic Usage][hugo-deploy]_ page has this to offe
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 compiled site. i definitely
already need Hugo installed on my workstation if i'm going to post anything.[^2]
so now i'm running Hugo in two places. there's surely going to be other complex
nonsense like webhooks involved.
this approach also involves a build system somewhere that can run Hugo to
build and push the compiled code and assets onto my cluster. i definitely
already need Hugo installed on my workstation if i'm going to post
anything.[^2] so now i'm running Hugo in two places. there's surely
going to be other complex nonsense like webhooks involved.
[^2]: unlikely.
![diagram: deploy w/ GitHub pages & actions](/images/hugo-github-pages.svg)
![diagram: deploy w/ GitHub Pages & Actions](images/hugo-github-pages.svg)
----
@ -68,11 +69,10 @@ _actual content_ into version control? couldn't be me.
## Getting Static
suppose i instead checked my content into git exactly as i intend to serve it?
suppose i instead check my content into git exactly as i intend to serve it?
then i could shell into my server box, pull the site, and _nifty-galifty!_ isn't
this the way it has [always been done][worm-love]?
my problem is that i don't have a server box. i have a _container orchestration
system_. there are several upsides to this[^3] but it means that _somehow_ my
generated content needs to end up in a container. because [Pods][k8s-pods] are
@ -87,7 +87,7 @@ 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: deploy w/ container build](/images/hugo-container-build.svg)
![diagram: deploy w/ container build](images/hugo-container-build.svg)
i don't want any of this. i just want to put some HTML and static assets behind a
web server.
@ -106,10 +106,11 @@ a minimal setup to achieve this might look like:
- an `emptyDir` volume to share between the containers.
- a `ConfigMap` to store the nginx config.
![diagram: minimal pod/configmap setup](images/hugo-minimal-pod-setup.svg)
![diagram: minimal pod/configmap setup](/images/hugo-minimal-pod-setup.svg)
i use `git sparse-checkout` to avoid pulling repository contents i don't want
when a new pod comes up, the `initContainer` mounts the
[`emptyDir`][k8s-emptydir] and clones the repository into `/www`. i use
`git sparse-checkout` to avoid pulling repository contents i don't want
to serve out:
```bash
@ -123,7 +124,7 @@ shopt -s dotglob
mv /tmp/www/* /www
```
script up my `git pull` loop:
for the sidecar, i script up my `git pull` loop:
```bash
# git-pull command
@ -133,7 +134,9 @@ while true; do
done
```
and configure `nginx` to use `public/` as root:
and i create a [ConfigMap][k8s-configmap] with a server block to configure
`nginx` to use Hugo's `public/` as root:
```txt
# ConfigMap; data: default.conf
@ -208,7 +211,7 @@ spec:
shopt -s dotglob
git clone https://code.estradiol.cloud/tamsin/estradiol.cloud.git --no-checkout --branch trunk /tmp/www;
cd /tmp/www;
p git sparse-checkout init --cone;
git sparse-checkout init --cone;
git sparse-checkout set public;
git checkout;
mv /tmp/www/* /www
@ -231,26 +234,132 @@ my Hugo workflow now looks like:
1. run `hugo --gc --minify`;[^7]
1. commit & push.
the only active process from this point is my little control loop running `git pull`.
my `git pull` control loop takes things over from here and i'm on easy street.
[^7]: i added `disableHTML = true` and `disableXML = true` to `[minify]`
configuration in `hugo.toml` to keep HTML and RSS diffs readable.
[^7]: i added `disableHTML = true` to `[minify]` configuration in `hugo.toml`
to keep HTML diffs readable.
## Getting Web
my Pod is running. everything is great. if i want to browse to my website i
just need to setup a [port-forward][k8s-port]
this is going great! my Pod is running. it's serving out my code. i get
continuous deployment™ for the low price of 11 lines `bash`. i mean...
no one can actually browse to my website[^8] but that will be an easy fix,
right?
TK: YAML counts as software.
[^8]: i can check that its working, at least, with a [port-forward][k8s-port].
conveniently, [Bitnami][bitnami] maintains a [Helm][helm] Chart that
first, i need a [`Service`][k8s-svc]. this gives me a proxy with service
discovery. TK: what is this really?
![diagram: helm setup](/images/hugo-helm-setup.svg)
{{< code-details summary="kubectl apply -f service.yaml" lang="yaml" details=`
# service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/instance: estradiol-cloud
app.kubernetes.io/name: nginx
name: nginx
spec:
type: ClusterIP
selector:
app.kubernetes.io/instance: estradiol-cloud
app.kubernetes.io/name: nginx
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
` >}}
and i need an [`Ingress`][k8s-ingress] to handle traffic inbound to the cluster
and direct it to the `Service`:
{{< code-details summary="kubectl apply -f ingress.yaml" lang="yaml" details=`
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
labels:
app.kubernetes.io/instance: estradiol-cloud
app.kubernetes.io/name: nginx
name: nginx
spec:
rules:
- host: estradiol.cloud
http:
paths:
- backend:
service:
name: nginx
port:
name: http
path: /
pathType: Prefix
` >}}
TK: wtf? Ingress controller
---
as this has come together, i've gotten increasinly anxious about how much
YAML i've had to write. this is a problem because YAML is software and, as
we've established, i'm hoping not to have much of that. it's also annoying
that most of this YAML really is boilerplate.
conveniently, [Bitnami][bitnami] maintains a [Helm][helm] Chart that hides all
the boilerplate and does exactly what we've just been doing manually.[^9]
[^9]: what incredible luck! (obviously, until now i've been working backward from this chart)
TK: install helm
TK: pull bitnami chart
TK: helm values
{{< code-details summary="`helm upgrade --install --create-namespace --namespace estradiol-cloud -f values.yaml`" lang="yaml" details=`
# values.yaml
cloneStaticSiteFromGit:
enabled: true
repository: "https://code.estradiol.cloud/tamsin/estradiol.cloud.git"
branch: trunk
gitClone:
command:
- /bin/bash
- -ec
- |
[[ -f "/opt/bitnami/scripts/git/entrypoint.sh" ]] && source "/opt/bitnami/scripts/git/entrypoint.sh"
git clone {{ .Values.cloneStaticSiteFromGit.repository }} --no-checkout --branch {{ .Values.cloneStaticSiteFromGit.branch }} /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/
ingress:
enabled: true
hostname: estradiol.cloud
ingressClassName: nginx
tls: true
annotations: {
cert-manager.io/cluster-issuer: letsencrypt-prod
}
serverBlock: |-
server {
listen 8080;
root /app/public;
index index.html;
}
service:
type: ClusterIP
`>}}
![diagram: helm setup](images/hugo-helm-setup.svg)
## Getting Flux'd
by this point i'm pretty `git push`-pilled and i'm thinking i don't much like
having this `helm` client software installed on my laptop.
having this `helm` client software installed on my laptop. plus, i still have
some YAML and it's not really great that i'm storing it in flat files and
pushing it to my cluster manually. i love automation. i might love automation
more than i disdain software. i feel prepared to get some software if it
will get this yaml out of my shell history and into a git repo.
```yaml
@ -311,9 +420,7 @@ spec:
type: ClusterIP
`>}}
{{ with .Resources.GetMatch "hugo-flux-seq.svg" }}
<img src="data:{{ .MediaType.Type }};base64,{{ .Content | base64Encode }}">
{{ end }}
![diagram: flux git push/deploy sequence](images/flux-seq.svg)
## A Note About Software
@ -324,8 +431,7 @@ setting aside the stuff that provisions and scales my cluster nodes, i have:
- `git` & `bash` (running from a stock image);
- a remote git server (i'm running `gitea`[^8], but github dot com is fine here);
- Kubernetes (oops!);
- `fluxcd`;
- especially `kustomize-controller` and `helm-controller`;
- `fluxcd`, especially `kustomize-controller` and `helm-controller`;
- `nginx-ingress` controller;
- the `bitnami/nginx` Helm chart;
@ -343,14 +449,18 @@ _fin_
[bitnami]: https://bitnami.com/
[cert-mgr]: https://cert-manager.io/docs/tutorials/acme/nginx-ingress/
[helm]: https://helm.sh
[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-emptydir]: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir
[k8s-init]: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
[k8s-ingress]: https://kubernetes.io/docs/concepts/services-networking/ingress/
[k8s-pods]: https://kubernetes.io/docs/concepts/workloads/pods/
[k8s-port]: https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/
[k8s-pv]: https://kubernetes.io/docs/concepts/storage/persistent-volumes/
[k8s-svc]: https://kubernetes.io/docs/concepts/services-networking/service/
[risotto]: https://github.com/joeroe/risotto
[worm-love]: https://www.mikecurato.com/worm-loves-worm

View File

@ -0,0 +1,90 @@
apiVersion: v1
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/instance: estradiol-cloud
app.kubernetes.io/name: nginx
name: nginx-server-block
data:
default.conf: |-
server {
listen 80;
location / {
root /www/public;
index index.html;
}
}
---
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/instance: estradiol-cloud
app.kubernetes.io/name: nginx
spec:
containers:
- name: nginx
image: nginx:1.25.4
ports:
- containerPort: 80
name: http
volumeMounts:
- mountPath: /www
name: www
- mountPath: /etc/nginx/conf.d
name: nginx-server-block
- name: git-pull
image: bitnami/git
command:
- /bin/bash
- -ec
- |
while true; do
cd /www && git -c safe.directory=/www pull origin trunk
sleep 60
done
volumeMounts:
- mountPath: /www
name: www
initContainers:
- name: git-clone
image: bitnami/git
command:
- /bin/bash
- -c
- |
shopt -s dotglob
git clone https://code.estradiol.cloud/tamsin/estradiol.cloud.git --no-checkout --branch trunk /tmp/www;
cd /tmp/www;
git sparse-checkout init --cone;
git sparse-checkout set public;
git checkout;
mv /tmp/www/* /www
volumeMounts:
- mountPath: /www
name: www
volumes:
- name: www
emptyDir: {}
- name: nginx-server-block
configMap:
name: nginx-server-block
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/instance: estradiol-cloud
app.kubernetes.io/name: nginx
name: nginx
spec:
type: ClusterIP
selector:
app.kubernetes.io/instance: estradiol-cloud
app.kubernetes.io/name: nginx
ports:
- name: http
port: 80
protocol: TCP
targetPort: http

View File

@ -1,4 +1,6 @@
<p>
<details>
<summary>{{ .Get "summary" | markdownify }}</summary>
{{ printf "```%s%s```" (.Get "lang") (.Get "details") | markdownify}}
</details>
</p>

View File

@ -19,6 +19,8 @@
<link rel="stylesheet" href="https://estradiol.cloud/css/risotto.css">
<link rel="stylesheet" href="https://estradiol.cloud/css/custom.css">
<link rel="alternate" type="application/rss+xml" title="estradiol.cloud Feed" href="index.xml" />

View File

@ -19,6 +19,8 @@
<link rel="stylesheet" href="https://estradiol.cloud/css/risotto.css">
<link rel="stylesheet" href="https://estradiol.cloud/css/custom.css">
<link rel="alternate" type="application/rss+xml" title="estradiol.cloud Feed" href="index.xml" />

View File

@ -20,6 +20,8 @@
<link rel="stylesheet" href="https://estradiol.cloud/css/risotto.css">
<link rel="stylesheet" href="https://estradiol.cloud/css/custom.css">
<link rel="alternate" type="application/rss+xml" title="estradiol.cloud Feed" href="index.xml" />

View File

@ -19,6 +19,8 @@
<link rel="stylesheet" href="https://estradiol.cloud/css/risotto.css">
<link rel="stylesheet" href="https://estradiol.cloud/css/custom.css">
<link rel="alternate" type="application/rss+xml" title="estradiol.cloud Feed" href="index.xml" />

View File

@ -19,6 +19,8 @@
<link rel="stylesheet" href="https://estradiol.cloud/css/risotto.css">
<link rel="stylesheet" href="https://estradiol.cloud/css/custom.css">
<link rel="alternate" type="application/rss+xml" title="estradiol.cloud Feed" href="index.xml" />
@ -69,6 +71,7 @@ bitnami chart), but using it in the existing chart required:
</ul>
</li>
</ol>
<p>
<details>
<summary><code>values.yaml</code></summary>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">ingress</span>:
@ -97,6 +100,7 @@ bitnami chart), but using it in the existing chart required:
</span></span><span style="display:flex;"><span> <span style="color:#f92672">size</span>: <span style="color:#ae81ff">10Gi</span>
</span></span></code></pre></div>
</details>
</p>
</div>

View File

@ -19,6 +19,8 @@
<link rel="stylesheet" href="https://estradiol.cloud/css/risotto.css">
<link rel="stylesheet" href="https://estradiol.cloud/css/custom.css">
<link rel="alternate" type="application/rss+xml" title="estradiol.cloud Feed" href="index.xml" />

View File

@ -19,6 +19,8 @@
<link rel="stylesheet" href="https://estradiol.cloud/css/risotto.css">
<link rel="stylesheet" href="https://estradiol.cloud/css/custom.css">
<link rel="alternate" type="application/rss+xml" title="estradiol.cloud Feed" href="index.xml" />

View File

@ -19,6 +19,8 @@
<link rel="stylesheet" href="https://estradiol.cloud/css/risotto.css">
<link rel="stylesheet" href="https://estradiol.cloud/css/custom.css">
<link rel="alternate" type="application/rss+xml" title="estradiol.cloud Feed" href="index.xml" />

View File

@ -19,6 +19,8 @@
<link rel="stylesheet" href="https://estradiol.cloud/css/risotto.css">
<link rel="stylesheet" href="https://estradiol.cloud/css/custom.css">
<link rel="alternate" type="application/rss+xml" title="estradiol.cloud Feed" href="index.xml" />

View File

@ -19,6 +19,8 @@
<link rel="stylesheet" href="https://estradiol.cloud/css/risotto.css">
<link rel="stylesheet" href="https://estradiol.cloud/css/custom.css">
<link rel="alternate" type="application/rss+xml" title="estradiol.cloud Feed" href="index.xml" />