583 lines
47 KiB
HTML
583 lines
47 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
|
||
<head><title>Hugo on Kubernetes & NGINX – estradiol.cloud</title>
|
||
<meta name="description" content="> [the regrown limb can be monstrous, duplicated, potent. We have all been injured, profoundly.](https://doi.org/10.5749/minnesota/9780816650477.003.0001)
|
||
|
||
----
|
||
|
||
Ь 887 | 2
|
||
">
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta charset="UTF-8"/>
|
||
|
||
|
||
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||
|
||
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/academicons/1.9.4/css/academicons.min.css" integrity="sha512-IW0nhlW5MgNydsXJO40En2EoCkTTjZhI3yuODrZIc8cQ4h1XcF53PsqDHa09NqnkXuIe0Oiyyj171BqZFwISBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||
|
||
|
||
<link rel="stylesheet" href="https://estradiol.cloud/css/palettes/material.css">
|
||
<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" />
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
</head>
|
||
|
||
<body>
|
||
<div class="page">
|
||
|
||
<header class="page__header"><nav class="page__nav main-nav">
|
||
<ul>
|
||
<li class="nomarker"><h1 class="page__logo"><a href="https://estradiol.cloud/" class="page__logo-inner">estradiol.cloud</a></h1></li><li class="main-nav__item"><a class="nav-main-item active" href="https://estradiol.cloud/posts/" title="">Posts</a></li></ul>
|
||
</nav>
|
||
</header>
|
||
|
||
<section class="page__body"><header class="content__header">
|
||
<h1>Hugo on Kubernetes & NGINX</h1>
|
||
</header>
|
||
<div class="content__body">
|
||
<p>i decided to make a website. a static one. this one. with <a href="https://gohugo.io">Hugo</a>. the
|
||
main reason i have for needing a website is as a vanity project, so i have some
|
||
stuff to host in a <a href="https://kubernetes.io">Kubernetes</a> cluster i’m running. the k8s cluster is
|
||
also a vanity project.</p>
|
||
<p>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.</p>
|
||
<h2 id="getting-started">Getting Started</h2>
|
||
<p>i built my site by following the straight-forward
|
||
<em><a href="https://gohugo.io/getting-started">Getting Started</a></em> guide in the Hugo documentation.</p>
|
||
<p>i did <code>hugo new site estradiol.cloud</code>. and then <code>cd estradiol.cloud; git init</code>.
|
||
and then i picked a ridiculous theme
|
||
<a href="https://github.com/joeroe/risotto">“inspired by terminal ricing aesthetics”</a>, installing it like <code>git submodule add https://github.com/joeroe/risotto.git themes/risotto; echo "theme = 'risotto'" >> hugo.toml</code>.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
|
||
<p>at this point, my website is basically finished (i also changed the title in
|
||
<code>hugo.toml</code>). i probably won’t be putting anything on it, so there’s no point
|
||
fiddling with other details.</p>
|
||
<p>about deployment, the Hugo guide’s <em><a href="https://gohugo.io/getting-started/usage/#deploy-your-site">Basic Usage</a></em> page has this
|
||
to offer:</p>
|
||
<blockquote>
|
||
<p>Most of our users deploy their sites using a CI/CD workflow, where a push<sup>1</sup>
|
||
|
||
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.</p>
|
||
<ol>
|
||
<li>The Git repository contains the entire project directory, typically excluding the
|
||
public directory because the site is built <em>after</em> the push.</li>
|
||
</ol>
|
||
</blockquote>
|
||
<p>importantly, you can’t make a post about deploying this way. <em>everyone</em> deploys
|
||
this way. if <em>i</em> deploy this way, this site will have no content.</p>
|
||
<p>this approach also involves a build system somewhere that can run Hugo to
|
||
compile the code and assets and push them onto my host. i definitely
|
||
already need Hugo installed on my laptop if i’m going to post anything.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>
|
||
so now i’m running Hugo in two places. there’s surely going to be other
|
||
complex nonsense like webhooks involved.</p>
|
||
<p><img src="images/hugo-github-pages.svg" alt="diagram: deploy w/ GitHub Pages & Actions"></p>
|
||
<hr>
|
||
<p>and hang on. let’s look at this again:</p>
|
||
<blockquote>
|
||
<ol>
|
||
<li>The Git repository contains the entire project directory, typically excluding the
|
||
public directory because the site is built <em>after</em> the push.</li>
|
||
</ol>
|
||
</blockquote>
|
||
<p>you’re telling me i’m going to build a nice static site and not check the
|
||
<em>actual content</em> into version control? couldn’t be me.</p>
|
||
<h2 id="getting-static">Getting Static</h2>
|
||
<p>suppose i instead check my content in exactly as i intend to serve it?
|
||
then i could shell into my server box, pull the site, and <em>nifty-galifty!</em> isn’t
|
||
this the way it has <a href="https://www.mikecurato.com/worm-loves-worm">always been done</a>?</p>
|
||
<p>my problem is that i don’t have a server box. i have a <em>container orchestration
|
||
system</em>. there are several upsides to this<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> but it means that <em>somehow</em> my
|
||
generated content needs to end up in a container. because <a href="https://kubernetes.io/docs/concepts/workloads/pods/">Pods</a> are
|
||
ephemeral and i’d like to run my site with horizontal scalability<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>, i don’t
|
||
want my container to retain runtime state across restarts or replicas.</p>
|
||
<p>i <em>could</em> run a little pipeline that builds a container image wrapping my
|
||
content and pushes it to a registry. when i deploy, the cluster pulls the
|
||
image, content and all. all ready to go. but now i’ve got <em>software</em> again:
|
||
build stages and webhooks and, to make matters worse, now i’m hosting
|
||
and versioning container images.</p>
|
||
<p><img src="images/hugo-container-build.svg" alt="diagram: deploy w/ container build"></p>
|
||
<p>i don’t want any of this. i just want to put some HTML and static assets behind a
|
||
web server.</p>
|
||
<hr>
|
||
<p>instead, i’d like to deploy a popular container image from a public registry
|
||
and deliver my content to it continuously.</p>
|
||
<p>a minimal setup to achieve this might look like:</p>
|
||
<ul>
|
||
<li>a <code>Pod</code> with:
|
||
<ul>
|
||
<li>an <code>nginx</code> container to serve the content;</li>
|
||
<li>a <code>git-pull</code> sidecar that loops, pulling the content;</li>
|
||
<li>an <code>initContainer</code> to do the initial checkout;</li>
|
||
<li>an <code>emptyDir</code> volume to share between the containers.</li>
|
||
</ul>
|
||
</li>
|
||
<li>a <code>ConfigMap</code> to store the nginx config.</li>
|
||
</ul>
|
||
<p><img src="images/hugo-minimal-pod-setup.svg" alt="diagram: minimal pod/configmap setup"></p>
|
||
<p>when a new <code>Pod</code> comes up, the <code>initContainer</code> mounts the
|
||
<a href="https://kubernetes.io/docs/concepts/storage/volumes/#emptydir"><code>emptyDir</code></a> at <code>/www</code> and clones the repository into it. i use
|
||
<code>git sparse-checkout</code> to avoid pulling repository contents i don’t want to serve
|
||
out:</p>
|
||
<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-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># git-clone command</span>
|
||
</span></span><span style="display:flex;"><span>git clone https://code.estradiol.cloud/tamsin/estradiol.cloud.git --no-checkout --branch trunk /tmp/www;
|
||
</span></span><span style="display:flex;"><span>cd /tmp/www;
|
||
</span></span><span style="display:flex;"><span>git sparse-checkout init --cone;
|
||
</span></span><span style="display:flex;"><span>git sparse-checkout set public;
|
||
</span></span><span style="display:flex;"><span>git checkout;
|
||
</span></span><span style="display:flex;"><span>shopt -s dotglob
|
||
</span></span><span style="display:flex;"><span>mv /tmp/www/* /www
|
||
</span></span></code></pre></div><p>for the sidecar, i script up a <code>git pull</code> loop:</p>
|
||
<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-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># git-pull command</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> true; <span style="color:#66d9ef">do</span>
|
||
</span></span><span style="display:flex;"><span> cd /www <span style="color:#f92672">&&</span> git -c safe.directory<span style="color:#f92672">=</span>/www pull origin trunk
|
||
</span></span><span style="display:flex;"><span> sleep <span style="color:#ae81ff">60</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
|
||
</span></span></code></pre></div><p>and i create a <a href="https://kubernetes.io/docs/concepts/configuration/configmap/">ConfigMap</a> with a server block to configure
|
||
<code>nginx</code> to use Hugo’s <code>public/</code> as root:</p>
|
||
<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-txt" data-lang="txt"><span style="display:flex;"><span># ConfigMap; data: default.conf
|
||
</span></span><span style="display:flex;"><span>server {
|
||
</span></span><span style="display:flex;"><span> listen 80;
|
||
</span></span><span style="display:flex;"><span> location / {
|
||
</span></span><span style="display:flex;"><span> root /www/public;
|
||
</span></span><span style="display:flex;"><span> index index.html;
|
||
</span></span><span style="display:flex;"><span> }
|
||
</span></span><span style="display:flex;"><span>}
|
||
</span></span></code></pre></div><p>the rest of this is pretty much boilerplate:</p>
|
||
<p>
|
||
<details>
|
||
<summary><code>kubectl apply -f https://estradiol.cloud/posts/hugo-on-k8s/site.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:#75715e"># estradiol-cloud.yaml</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">ConfigMap</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">app.kubernetes.io/instance</span>: <span style="color:#ae81ff">estradiol-cloud</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">app.kubernetes.io/name</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx-server-block</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">data</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">default.conf</span>: |-<span style="color:#e6db74">
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> server {
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> listen 80;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> location / {
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> root /www/public;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> index index.html;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> }
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> }</span>
|
||
</span></span><span style="display:flex;"><span>---
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Pod</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">app.kubernetes.io/instance</span>: <span style="color:#ae81ff">estradiol-cloud</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">app.kubernetes.io/name</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">containers</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx:1.25.4</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">containerPort</span>: <span style="color:#ae81ff">80</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/www</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">www</span>
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/etc/nginx/conf.d</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx-server-block</span>
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">git-pull</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">bitnami/git</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/bash</span>
|
||
</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">ec</span>
|
||
</span></span><span style="display:flex;"><span> - |<span style="color:#e6db74">
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> while true; do
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> cd /www && git -c safe.directory=/www pull origin trunk
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> sleep 60
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> done</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/www</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">www</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">initContainers</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">git-clone</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">image</span>: <span style="color:#ae81ff">bitnami/git</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/bash</span>
|
||
</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">c</span>
|
||
</span></span><span style="display:flex;"><span> - |<span style="color:#e6db74">
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> shopt -s dotglob
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git clone https://code.estradiol.cloud/tamsin/estradiol.cloud.git --no-checkout --branch trunk /tmp/www;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> cd /tmp/www;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git sparse-checkout init --cone;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git sparse-checkout set public;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git checkout;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> mv /tmp/www/* /www</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumeMounts</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">mountPath</span>: <span style="color:#ae81ff">/www</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">www</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">volumes</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">www</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">emptyDir</span>: {}
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx-server-block</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">configMap</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx-server-block</span>
|
||
</span></span></code></pre></div></details>
|
||
</p>
|
||
|
||
<hr>
|
||
<p>my Hugo workflow now looks like:</p>
|
||
<ol>
|
||
<li>make changes to source;</li>
|
||
<li>run <code>hugo --gc --minify</code>;<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></li>
|
||
<li><code>git</code> commit & push.</li>
|
||
</ol>
|
||
<p>my <code>git pull</code> control loop takes things over from here and i’m on easy street.</p>
|
||
<h2 id="getting-web">Getting Web</h2>
|
||
<p>this is going great! my <code>Pod</code> is running. it’s serving out my code. i get
|
||
Continuous Deployment™ for the low price of 11 lines <code>bash</code>. i mean…
|
||
no one can actually browse to my website<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> but that will be an easy fix,
|
||
right? yes. networking is always the easy part.</p>
|
||
<p>first, i need a <a href="https://kubernetes.io/docs/concepts/services-networking/service/"><code>Service</code></a>. this gives me a proxy to my several
|
||
replicas<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> and in-cluster service discovery.</p>
|
||
<p>
|
||
<details>
|
||
<summary><code>kubectl apply -f https://estradiol.cloud/posts/hugo-on-k8s-nginx/service.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:#75715e"># service.yaml</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">v1</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Service</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">app.kubernetes.io/instance</span>: <span style="color:#ae81ff">estradiol-cloud</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">app.kubernetes.io/name</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">ClusterIP</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">selector</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">app.kubernetes.io/instance</span>: <span style="color:#ae81ff">estradiol-cloud</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">app.kubernetes.io/name</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">ports</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">http</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>: <span style="color:#ae81ff">80</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">protocol</span>: <span style="color:#ae81ff">TCP</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">targetPort</span>: <span style="color:#ae81ff">http</span>
|
||
</span></span></code></pre></div></details>
|
||
</p>
|
||
|
||
<p>next, i need an <a href="https://kubernetes.io/docs/concepts/services-networking/ingress/"><code>Ingress</code></a> to handle traffic inbound to the cluster
|
||
and direct it to the <code>Service</code>:</p>
|
||
<p>
|
||
<details>
|
||
<summary><code>kubectl apply -f https://estradiol.cloud/posts/hugo-on-k8s-nginx/ingress.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:#75715e"># ingress.yaml</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">networking.k8s.io/v1</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">Ingress</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">labels</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">app.kubernetes.io/instance</span>: <span style="color:#ae81ff">estradiol-cloud</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">app.kubernetes.io/name</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">rules</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">host</span>: <span style="color:#ae81ff">estradiol.cloud</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">http</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">paths</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#f92672">backend</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">service</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">port</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">http</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">path</span>: <span style="color:#ae81ff">/</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">pathType</span>: <span style="color:#ae81ff">Prefix</span>
|
||
</span></span></code></pre></div></details>
|
||
</p>
|
||
|
||
<p>this part expresses a routing rule: traffic reaching the cluster via
|
||
<code>estradiol.cloud</code> should go to my <code>Service</code>, and then to one of its backend <code>Pod</code>s.
|
||
to actually apply this rule, i need an ingress controller. mine is
|
||
<a href="https://kubernetes.github.io/ingress-nginx/">ingress-nginx</a>.</p>
|
||
<p>when i deployed controller in my cluster, it created <em>some more</em> <code>nginx</code> <code>Pod</code>s.
|
||
these update their configuration dynamically based on the rules
|
||
in my <code>Ingress</code> resource(s). the controller also creates a <code>Service</code> of
|
||
type <code>LoadBalancer</code>, which <a href="https://docs.digitalocean.com/products/kubernetes/how-to/add-load-balancers/">magically</a> creates a load balancer appliance
|
||
in my cloud provider. off-screen, i can point DNS to <em>that</em> appliance to finish
|
||
the setup.</p>
|
||
<p><a href="https://kubernetes.io/docs/concepts/services-networking/ingress/#what-is-ingress"><img src="https://kubernetes.io/docs/images/ingress.svg" alt="diagram: kubernetes ingress"></a></p>
|
||
<p>you can tell it’s working by looking at your browser bar.</p>
|
||
<hr>
|
||
<p>as this has come together, i’ve gotten increasingly anxious about how much
|
||
YAML i’ve had to write. this is a problem because YAML is software and, as
|
||
established, i’m hoping not to have much of that. it’s also annoying that most
|
||
of this YAML really is just boilerplate.</p>
|
||
<p>conveniently, <a href="https://bitnami.com/">Bitnami</a> maintains a <a href="https://helm.sh">Helm</a> Chart that templates
|
||
out all the boilerplate and does exactly what i’ve just been doing.<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup> i can
|
||
replace all my YAML with a call out to this chart and a few lines of
|
||
configuration, assuming i have <a href="https://helm.sh/docs/intro/install/">helm client installed</a>:</p>
|
||
<p>
|
||
<details>
|
||
<summary><code>helm upgrade --install --create-namespace --namespace estradiol-cloud -f https://estradiol.cloud/posts/hugo-on-k8s-nginx/values.yaml oci://registry-1.docker.io/bitnamicharts/nginx</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:#75715e"># values.yaml</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">cloneStaticSiteFromGit</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">repository</span>: <span style="color:#e6db74">"https://code.estradiol.cloud/tamsin/estradiol.cloud.git"</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">branch</span>: <span style="color:#ae81ff">trunk</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">gitClone</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/bash</span>
|
||
</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">ec</span>
|
||
</span></span><span style="display:flex;"><span> - |<span style="color:#e6db74">
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [[ -f "/opt/bitnami/scripts/git/entrypoint.sh" ]] && source "/opt/bitnami/scripts/git/entrypoint.sh"
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git clone {{ .Values.cloneStaticSiteFromGit.repository }} --no-checkout --branch {{ .Values.cloneStaticSiteFromGit.branch }} /tmp/app
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [[ "$?" -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/</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">ingress</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">hostname</span>: <span style="color:#ae81ff">estradiol.cloud</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">ingressClassName</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">tls</span>: <span style="color:#66d9ef">true</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: {
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">cert-manager.io/cluster-issuer</span>: <span style="color:#ae81ff">letsencrypt-prod</span>
|
||
</span></span><span style="display:flex;"><span> }
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">serverBlock</span>: |-<span style="color:#e6db74">
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> server {
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> listen 8080;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> root /app/public;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> index index.html;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> }</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">service</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">ClusterIP</span>
|
||
</span></span></code></pre></div></details>
|
||
</p>
|
||
|
||
<p><img src="images/hugo-helm-setup.svg" alt="diagram: helm setup"></p>
|
||
<p>configuration for the <code>git-clone</code> script and our custom server block are added
|
||
via <code>values.yaml</code>. the <code>git-pull</code> loop configured by the chart works as-is.
|
||
by using the chart, we get a few other nicities. for instance,
|
||
my <code>Pod</code>s are now managed by a <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/"><code>Deployment</code></a>.<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> this will make my
|
||
grand scale-out plans a breeze.</p>
|
||
<h2 id="getting-fluxd">Getting Flux’d</h2>
|
||
<p>by now, i’m riding high. my whole setup is my static site code and <30 lines of
|
||
YAML.</p>
|
||
<p>i <em>do</em> have a bunch of stuff deployed into my cluster, and none of this is very
|
||
reproducible without all of that. my workflow has also expanded to:</p>
|
||
<ol>
|
||
<li>for routine site deploys:
|
||
<ol>
|
||
<li>make changes to source;</li>
|
||
<li>run <code>hugo --gc --minify</code>;<sup id="fnref1:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></li>
|
||
<li><code>git</code> commit & push.</li>
|
||
</ol>
|
||
</li>
|
||
<li>to update <code>nginx</code>, the chart version, or change config:
|
||
<ol>
|
||
<li>make changes to <code>values.yaml</code></li>
|
||
<li><code>helm upgrade</code></li>
|
||
</ol>
|
||
</li>
|
||
</ol>
|
||
<p>i could do without the extra <code>helm</code> client dependency on my laptop. i’m also
|
||
pretty <code>git push</code>-pilled, and i really want the solution to all my problems
|
||
to take the now familiar shape: put a control loop in my cluster and push
|
||
to a <code>git</code> repository.</p>
|
||
<p>enter <a href="https://fluxcd.io/"><code>flux</code></a>.</p>
|
||
<p>with <code>flux</code>, i decide on a repository (and maybe a path within it) to act as
|
||
a source for my Kubernetes YAML. i go through a short <a href="https://fluxcd.io/flux/installation/bootstrap/">bootstrap</a>
|
||
process which installs the <code>flux</code> controllers and add them to repository. to
|
||
make a change to a resource in my cluster, i edit the YAML and push to the
|
||
repository. <code>flux</code> listens and applies the changes.</p>
|
||
<p><code>flux</code> supports Helm deploys, so i can get that <code>helm</code> client off my laptop.
|
||
i can also use it to manage my ingress controller, <code>cert-manager</code>, <code>flux</code>
|
||
itself and whatever other infrastructural junk i may end up needing.</p>
|
||
<p>to move my web stack into <code>flux</code>, i create a <code>HelmRepository</code> resource for
|
||
the <code>bitnami</code> Helm charts:</p>
|
||
<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:#75715e"># bitnami-helm.yaml</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">apiVersion</span>: <span style="color:#ae81ff">source.toolkit.fluxcd.io/v1beta2</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">HelmRepository</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">bitnami</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">default</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">url</span>: <span style="color:#ae81ff">https://charts.bitnami.com/bitnami</span>
|
||
</span></span></code></pre></div><p>and add a <code>HelmRelease</code> pointing to the repository/chart version and containing
|
||
my <code>values.yaml</code>:</p>
|
||
<p>
|
||
<details>
|
||
<summary><code>release.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">apiVersion</span>: <span style="color:#ae81ff">helm.toolkit.fluxcd.io/v2beta1</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">kind</span>: <span style="color:#ae81ff">HelmRelease</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">metadata</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">web</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">estradiol-cloud</span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#f92672">spec</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">interval</span>: <span style="color:#ae81ff">5m</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">chart</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">spec</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">chart</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">version</span>: <span style="color:#e6db74">'15.12.2'</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">sourceRef</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">kind</span>: <span style="color:#ae81ff">HelmRepository</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">name</span>: <span style="color:#ae81ff">bitnami</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">namespace</span>: <span style="color:#ae81ff">default</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">interval</span>: <span style="color:#ae81ff">1m</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">values</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">cloneStaticSiteFromGit</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">repository</span>: <span style="color:#e6db74">"https://code.estradiol.cloud/tamsin/estradiol.cloud.git"</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">branch</span>: <span style="color:#ae81ff">trunk</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">gitClone</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">command</span>:
|
||
</span></span><span style="display:flex;"><span> - <span style="color:#ae81ff">/bin/bash</span>
|
||
</span></span><span style="display:flex;"><span> - -<span style="color:#ae81ff">ec</span>
|
||
</span></span><span style="display:flex;"><span> - |<span style="color:#e6db74">
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [[ -f "/opt/bitnami/scripts/git/entrypoint.sh" ]] && source "/opt/bitnami/scripts/git/entrypoint.sh"
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> git clone {{ .Values.cloneStaticSiteFromGit.repository }} --no-checkout --branch {{ .Values.cloneStaticSiteFromGit.branch }} /tmp/app
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> [[ "$?" -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/</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">ingress</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">hostname</span>: <span style="color:#ae81ff">estradiol.cloud</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">ingressClassName</span>: <span style="color:#ae81ff">nginx</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">tls</span>: <span style="color:#66d9ef">true</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">annotations</span>: {
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">cert-manager.io/cluster-issuer</span>: <span style="color:#ae81ff">letsencrypt-prod</span>
|
||
</span></span><span style="display:flex;"><span> }
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">serverBlock</span>: |-<span style="color:#e6db74">
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> server {
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> listen 8080;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> root /app/public;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> index index.html;
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> }</span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">service</span>:
|
||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">type</span>: <span style="color:#ae81ff">ClusterIP</span>
|
||
</span></span></code></pre></div></details>
|
||
</p>
|
||
|
||
<p>when i push these to my <code>flux</code> <a href="https://gitlab.com/no_reply/sublingual/-/tree/trunk/estradiol.cloud">source repository</a>, the Helm
|
||
release rolls out.</p>
|
||
<p><img src="images/flux-seq.svg" alt="diagram: flux git push/deploy sequence"></p>
|
||
<h2 id="a-note-about-software">A Note About Software</h2>
|
||
<p>in the end, i’m forced to admit there’s still a lot of software involved in all
|
||
of this. setting aside the stuff that provisions and scales my cluster nodes,
|
||
and the <em>magic</em> <code>LoadBalancer</code>, i have:</p>
|
||
<ul>
|
||
<li><code>nginx</code> (running from a stock image);</li>
|
||
<li><code>git</code> & <code>bash</code> (running from a stock image);</li>
|
||
<li>a remote git server (i’m running <code>gitea</code><sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup>, but github dot com is fine here);</li>
|
||
<li>Kubernetes (oops!);
|
||
<ul>
|
||
<li><code>flux</code>, especially <code>kustomize-controller</code> and <code>helm-controller</code>;</li>
|
||
<li><code>ingress-nginx</code> controller;</li>
|
||
<li><code>cert-manager</code> and Let’s Encrypt;</li>
|
||
</ul>
|
||
</li>
|
||
<li>the <code>bitnami/nginx</code> Helm chart;</li>
|
||
</ul>
|
||
<p>the bulk of this i’ll be able to reuse for the other things i deploy on the
|
||
cluster<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup>. and it replaces SASS black-boxes like “AWS Amplify, CloudCannon,
|
||
Cloudflare Pages, GitHub Pages, GitLab Pages, and Netlify” in the recommended
|
||
Hugo deployment.</p>
|
||
<p>to actually deploy my site, i get to maintain a <code>bash</code> scripts for <code>git-clone</code>, my
|
||
NGINX config, and a couple of blobs of YAML.</p>
|
||
<p>at least there are no webhooks.</p>
|
||
<hr>
|
||
<p><em>fin</em></p>
|
||
<div class="footnotes" role="doc-endnotes">
|
||
<hr>
|
||
<ol>
|
||
<li id="fn:1">
|
||
<p>i appreciate the culinary branding. <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
<li id="fn:2">
|
||
<p>unlikely. <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
<li id="fn:3">
|
||
<p>few of which could be considered relevant for my project. <a href="#fnref:3" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
<li id="fn:4">
|
||
<p>i absolutely will not need this <a href="#fnref:4" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
<li id="fn:5">
|
||
<p>i added <code>disableHTML = true</code> and <code>disableXML = true</code> to <code>[minify]</code>
|
||
configuration in <code>hugo.toml</code> to keep HTML and RSS diffs readable. <a href="#fnref:5" class="footnote-backref" role="doc-backlink">↩︎</a> <a href="#fnref1:5" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
<li id="fn:6">
|
||
<p>i can check that its working, at least, with a <a href="https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/">port-forward</a>. <a href="#fnref:6" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
<li id="fn:7">
|
||
<p>lmao <a href="#fnref:7" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
<li id="fn:8">
|
||
<p>what incredible luck! (obviously, until now i’ve been working backward from this chart) <a href="#fnref:8" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
<li id="fn:9">
|
||
<p>i also snuck a TLS certificate configuration via Let’s Encrypt with
|
||
<a href="https://cert-manager.io/docs/tutorials/acme/nginx-ingress/"><code>cert-manager</code></a> into this iteration. if you’re following along at home and don’t have <code>cert-manager</code> installed, this should still work fine (but with no HTTPS). <a href="#fnref:9" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
<li id="fn:10">
|
||
<p>because i’m running <code>gitea</code> in my cluster and i want to avoid a circular
|
||
dependency for my <code>flux</code> source repository, i also depend on GitLab dot com. <a href="#fnref:10" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
<li id="fn:11">
|
||
<p>i won’t. <a href="#fnref:11" class="footnote-backref" role="doc-backlink">↩︎</a></p>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
|
||
</div>
|
||
<footer class="content__footer"></footer>
|
||
</section>
|
||
|
||
<section class="page__aside">
|
||
<div class="aside__about">
|
||
<div class="aside__about"><h1 class="about__title">it's estradiol.cloud!</h1>
|
||
<p class="about__description"><blockquote>
|
||
<p><a href="https://doi.org/10.5749/minnesota/9780816650477.003.0001">the regrown limb can be monstrous, duplicated, potent. We have all been injured, profoundly.</a></p>
|
||
</blockquote>
|
||
<hr>
|
||
<p>Ь 887 | 2</p>
|
||
</p>
|
||
</div>
|
||
|
||
|
||
<ul class="aside__social-links">
|
||
<li>
|
||
<i class="fa-brands fa-mastodon"></i> <a href="https://hachyderm.io/@no_reply" rel="me" title="Hachyderm">hachyderm.io/@no_reply</a>
|
||
</li>
|
||
<li>
|
||
<i class="fa-brands fa-mastodon"></i> <a href="https://chaosfem.tw/@t4tamsin" rel="me" title="Chaosfem"></i>chaosfem.tw/@t4tamsin</a>
|
||
</li>
|
||
<li>
|
||
<i class="fa-brands fa-git-alt"></i> <a href="https://code.estradiol.cloud/tamsin" rel="me" title="Code">code</a>
|
||
</li>
|
||
<li>
|
||
<i class="fa-brands fa-gitlab"></i> <a href="https://gitlab.com/no-reply" rel="me" title="Code">work code</a>
|
||
</li>
|
||
<li>
|
||
<i class="fa-brands fa-github"></i> <a href="https://github.com/no_eply" rel="me" title="Code">more code</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<hr>
|
||
<div class="aside__content"><p>kubernetes is for girls</p><p>2024-03-12
|
||
</p><hr>
|
||
Hugo on Kubernetes & NGINX:
|
||
<nav id="TableOfContents">
|
||
<ol>
|
||
<li><a href="#getting-started">Getting Started</a></li>
|
||
<li><a href="#getting-static">Getting Static</a></li>
|
||
<li><a href="#getting-web">Getting Web</a></li>
|
||
<li><a href="#getting-fluxd">Getting Flux’d</a></li>
|
||
<li><a href="#a-note-about-software">A Note About Software</a></li>
|
||
</ol>
|
||
</nav>
|
||
</div>
|
||
</section>
|
||
|
||
<footer class="page__footer"></footer>
|
||
|
||
</div>
|
||
</body>
|
||
|
||
</html>
|