Deploying packages with Helm can require a lot of ceremony on the command line. It's not senseless ceremony: there are use cases where the flexibility of Helm is helpful. Yet, if you're anything like me, you want as little typing as possible when you're ready to throw a thing at Kubernetes. This post is about some simple tooling I created to achieve that.

This post is part 3 in my series about running my own Kubernetes deployment using Digital Ocean managed Kubernetes. If you're interested in what else is involved in my setup, be sure to check out part 1 and part 2.

Deploying something to my cluster using Helm loosely involves a Helm invocation that looks something like this:

helm upgrade deployment_name \
  chart_name \
  -f override_values.yaml \
  --tls \ # if you don't have the env var set
  --install \
  --namespace target_namespace

This is fine until you've got to keep everything straight for more than two deployments or if you're not doing deployments frequently. At work, we built out a good amount of tooling to manage Helm for us. Honestly, though, I didn't need anything near that complex for my personal cluster. I settled down one evening not long ago, stretched my bash muscles, and came up with something "good enough" for me.

Matt's k8s-specs repo

I have a git repository that I've imaginatively named k8s-specs. The structure is pretty straightforward:

k8s-specs/
├── deploy.sh
├── fdn
│   ├── CHART_NAME
│   ├── dependencies.yaml
│   └── values.yaml
├── ghost-test
│   ├── CHART_NAME
│   ├── dependencies.yaml
│   └── values.yaml
├── mysql
│   ├── CHART_NAME
│   ├── dependencies.yaml
│   └── values.yaml
├── nfs
│   ├── CHART_NAME
│   └── values.yaml
└── traefik
    ├── CHART_NAME
    └── values.yaml

Under k8s-specs, each folder is a thing I want to deploy. The name that's used for the deployment name in Helm is the same as the folder name. Each folder has up to three items in it:

  1. The CHART_NAME file that is a valid reference to the Helm chart I want to use. This is the only file that's required.
  2. The dependencies.yaml file containing any Kubernetes resources that must be added before the Helm chart is run. I typically use this to deploy secrets or something similar.
  3. The values.yaml file that overrides the default settings for the Chart for my deployment.

This turns out to be a pretty excellent setup. It can even support a chart actually living in one of these folders, if needed.

The deploy.sh script is a few lines of bash that does the required legwork to make things happen in the Kubernetes cluster. It takes up to two arguments: the first is name of the folder you want to deploy, the second is the namespace in Kubernetes you want to deploy it in. The second argument is optional and only matters for initial deployments. Subsequent deployments of a chart will always go to the namespace the initial deployment targeted.

The source of my deploy script is:

#!/bin/bash

NAME=$1
CHART_NAME=$(cat $NAME/CHART_NAME)
NAMESPACE=${2:-default}

echo "Name:" $NAME
echo "Chart:" $CHART_NAME
echo "Namespace: " $NAMESPACE

echo "Ensuring dependencies are installed..."

if [[ -f "$NAME/dependencies.yaml" ]]; then
  echo "Applying dependencies..."
  kubectl apply -f $NAME/dependencies.yaml
else
  echo "No dependencies to apply."
fi

echo "Running helm"
helm upgrade $NAME $CHART_NAME -f $NAME/values.yaml --tls --install --namespace $NAMESPACE

Now whenever I have changes I want to deploy to the blog, I just drop into my k8s-specs repository on my terminal and type ./deploy.sh fdn to get rolling.

I've been using this setup for many weeks now and have found it to age pretty well so far. This is more than I can say for a lot of Chef cookbooks I've written in a prior life.