blumeops/docs/tutorials/replication/kubernetes-bootstrap.md
Erich Blume b0bac91ca9 Fix frontmatter field name for Quartz date display (#158)
## Summary

- Rename `date-modified` -> `modified` in all 80 docs and the `docs-check-frontmatter` task

Quartz's `CreatedModifiedDate` plugin recognizes `modified`, `lastmod`, `updated`, and `last-modified` — but not `date-modified`. The wrong field name caused Quartz to ignore frontmatter dates entirely and fall through to filesystem timestamps (UTC inside Dagger), showing Feb 12 on pages built late on Feb 11 PST.

## Test plan

- [x] `mise run docs-check-frontmatter` passes
- [ ] Kick off docs release after merge — verify rendered dates match frontmatter values

Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/158
2026-02-11 16:45:12 -08:00

4.1 KiB

title modified tags
Kubernetes Bootstrap 2026-02-07
tutorials
replication
kubernetes

Bootstrapping Kubernetes

Audiences: Replicator

This tutorial walks through setting up a Kubernetes cluster for your homelab, making it accessible via Tailscale.

Choosing a Distribution

For homelab use, lightweight distributions work well:

Distribution Best For BlumeOps Uses
Minikube Single-node, macOS Yes
k3s Single-node, Linux -
kind Local development -
kubeadm Multi-node clusters -

This tutorial uses minikube, but principles apply broadly.

For BlumeOps specifics, see cluster.

Step 1: Install Minikube

macOS

brew install minikube

Linux

curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

Step 2: Create the Cluster

minikube start \
  --driver=docker \
  --cpus=4 \
  --memory=8g \
  --disk-size=100g \
  --apiserver-names=k8s.your-tailnet.ts.net,$(hostname) \
  --listen-address=0.0.0.0

Key flags:

  • --apiserver-names - Include your Tailscale hostname for remote access
  • --listen-address=0.0.0.0 - Allow connections from other machines

Step 3: Verify the Cluster

kubectl get nodes
# Should show your node as Ready

kubectl get pods -A
# Should show system pods running

Step 4: Expose via Tailscale

To access the cluster from other Tailscale devices, expose the API server:

Option A: Tailscale Serve (Simple)

tailscale serve --bg --tcp 6443 tcp://localhost:$(minikube ip --format '{{.Port}}')

Option B: Tailscale Kubernetes Operator (Advanced)

For production-like setup, install the Tailscale operator which manages ingress automatically.

BlumeOps uses TCP passthrough via Caddy - see routing.

Step 5: Configure Remote Access

On your workstation, add a context for the remote cluster:

# Copy the CA cert from the server
scp server:~/.minikube/ca.crt ~/.kube/minikube-ca.crt

# Add the cluster
kubectl config set-cluster minikube-remote \
  --server=https://k8s.your-tailnet.ts.net:6443 \
  --certificate-authority=$HOME/.kube/minikube-ca.crt

# Add credentials (copy from server's ~/.kube/config)
kubectl config set-credentials minikube-remote \
  --client-certificate=... \
  --client-key=...

# Add context
kubectl config set-context minikube-remote \
  --cluster=minikube-remote \
  --user=minikube-remote

# Test
kubectl --context=minikube-remote get nodes

Step 6: Storage Configuration

For persistent workloads, configure storage:

Local Path Provisioner (Simple)

kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/master/deploy/local-path-storage.yaml
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

NFS for Shared Storage

If you have a NAS:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-share
spec:
  capacity:
    storage: 1Ti
  accessModes:
    - ReadWriteMany
  nfs:
    server: nas.your-tailnet.ts.net
    path: /volume1/k8s

What You Now Have

  • A Kubernetes cluster running on your server
  • Remote access via Tailscale
  • Storage for persistent workloads

Next Steps

  • argocd-config - GitOps deployments
  • Install essential addons (ingress controller, cert-manager)

BluemeOps Specifics

BlumeOps' cluster configuration includes:

  • Tailscale operator for automatic ingress
  • NFS mounts from sifaka for media storage
  • CloudNativePG for PostgreSQL databases

See cluster and apps for full details.

Troubleshooting

Problem Solution
Can't connect remotely Check --apiserver-names includes Tailscale hostname
Pods stuck pending Check storage class is available
Connection refused Verify --listen-address=0.0.0.0 was set
Certificate errors Ensure CA cert matches server's