These are optional, but good places to start if you’re totally unfamiliar with Kubernetes cluster administration.
- Store app/service manifests in git, in subdirectories under this one. Inside each service subdirectory, have a sub-subdir for each type of kubernetes object, with manifests inside. Similar to this suggestion.
- Use
sops
to encrypt secrets. In my case, I’m using mypsyops
container built from code in this repo to runkubectl
, so I store mysops
age key in my gopass repository. See below subsection for some examples. This is particularly well suited to tiny clusters and teams. Based on this suggestion. - Note that Kubernetes stores all of the manifests in its etcd database, but you should probably keep your own copy here so you know how the services work. There are gitops tools like argocd that can automatically apply them for you, but for a tiny home cluster you can also just save them to git and apply them on the command line yourself.
- You can run
kubectl
on any machine with network access to the cluster; you don’t have to ssh to one of the cluster nodes first. (This also means you don’t have to keep the git repo checked out on your cluster node(s).) See the k3s Cluster Access page for instructions; basically you copy/etc/rancher/k3s/k3s.yaml
and change theserver
to your server’s IP. In this cluster, we usekube-vip
to create a floating VIP on the cluster network, so wait to do this step untilkube-vip
is configured, and use the VIP (in my case192.168.1.200
) as theserver
in the kube config. Save it to~/.kube/config
on the machine you’ll runkubectl
from. I actually save mine to the normal place for psyops secrets in/secrets/psyops-secrets/kubernasty/kubeconfig.yml
and setKUBECONFIG=/secrets/psyops-secrets/kubernasty/kubeconfig.yml
instead.
Initial sops
configuration
#
First, I had to create an age
key for Kubernasty’s sops
encryption.
age-keygen -o /path/to/somewhere/safe/kubernasty-sops.age
Now you can use your newly created key for cluster secrets.
You could run sops
like this:
sops \
--age="$SOPS_AGE_RECIPIENTS" \
--encrypted-regex '^(data|stringData)$' \
...
… however, it’s nicer to create a sops config file under
♘
kubernasty/.sops.yaml
:
creation_rules:
- path_regex: .*.yaml
encrypted_regex: ^(data|stringData)$
age: age1869u6cnxhf7a6u6wqju46f2yas85273cev2u6hyhedsjdv8v39jssutjw9
With that file in place,
sops will find it when you’re trying to encrypt any item from a pwd of kubernasty/
or any of its subdirectories.
cluster.sh
script
#
Dot-source the cluster.sh
script from within the psyops container.
Here’s an annotated example:
# Set some things for my environment.
# I save this as cluster.sh for dot-sourcing.
#
# I keep my kubeconfig file here
export KUBECONFIG=/secrets/psyops-secrets/kubernasty/kubeconfig.yml
# Exporting this variable means that sops will use this public key for encryption.
# This value comes from the kubernasty-sops.age file created above.
export SOPS_AGE_RECIPIENTS=age1869u6cnxhf7a6u6wqju46f2yas85273cev2u6hyhedsjdv8v39jssutjw9
# Exporting this variable means that sops will find the private key at this path.
export SOPS_AGE_KEY_FILE=/secrets/psyops-secrets/kubernasty/kubernasty-sops.age
I can dot-source that script and then use it to easily encrypt secrets and store the encrypted result in this git repo.
# Source the above script
. cluster.sh
# Create a secrets file... this is just an example.
# Remember that it must be created in the same namespace as the service that will use it.
cat > secret.tmp <<EOF
---
kind: Secret
apiVersion: v1
type: Opaque
metadata:
name: example-credential-name
namespace: asdfwhatever
stringData:
secretName: s3cr3tV@lue
EOF
# Use sops to encrypt it
# We save it to the right location for the psyops container, adjust to your own needs if not using psyops.
sops --encrypt secret.tmp > /psyops/kubernasty/SERVICENAME/secrets/SECRETNAME.yml
# Then you can delete the tmp secret file
rm secret.tmp
# Use sops to decrypt the encrypted file for viewing.
sops --decrypt /psyops/kubernasty/SERVICENAME/secrets/SECRETNAME.yml
# Use sops to decrypt the file to apply with kubectl
sops --decrypt /psyops/kubernasty/SERVICENAME/secrets/SECRETNAME.yml |
kubectl apply -f -