Introduction to Kustomize, Part 2: Overriding values with overlays

In part 1 of this tutorial, we looked at how to use Kustomize to combine multiple pieces into a single YAML file that can be deployed to Kubernetes. In doing that, we used the example of combining specs for WordPress and MySQL, automatically adding a common app label. Now we’re going to move on and look at what happens when we need to override some of the existing values that aren’t labels.

Curious about what else is new in Kubernetes 1.14 (besides integration of Kustomize)? Watch our webinar recording.

Changing parameters for a component using Kustomize overlays

Now, we’re almost ready, but we do have one more problem.  While we’re deploying our production system to a cloud provider that supports LoadBalancer, we’re developing on our laptop so we need our services to be of type: NodePort.  Fortunately we can solve this problem with overlays.

Overlays enable us to take the base YAML and selectively change pieces of it.  For example, we’re going to create an overlay that includes a patch to change the Services to NodePort type services.

It’s important that the overlay isn’t in the same directory as the base files, so we’ll create it in an adjacent directory, then add a dev subdirectory.

OVERLAY_HOME=$BASE/../overlays
mkdir $OVERLAY_HOME
DEV_HOME=$OVERLAY_HOME/dev
mkdir $DEV_HOME
cd $DEV_HOME

Next we want to create the patch file, $DEV_HOME/localserv.yaml:

apiVersion: v1
kind: Service
metadata:
  name: wordpress
spec:
  type: NodePort
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  type: NodePort

Notice that we’ve included the bare minimum of information here; just enough to identify each service we want to change, and then specify the change that we want to make — in this case, the type.

Now we need to create the $DEV_HOME/kustomization.yaml file to tie all of this together:

bases:
- ../../base
patchesStrategicMerge:
- localserv.yaml

Notice that this is really very simple; we’re pointing at our original base directory, and specifying the patch(es) that we want to add.

Now we can go ahead and build the original, and see that it’s untouched:

kustomize build $BASE

You can see that we still have LoadBalancer services:

...
spec:
  ports:
  - port: 3306
  selector:
    app: my-wordpress
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-wordpress
  name: wordpress
spec:
  ports:
  - port: 80
  selector:
    app: my-wordpress
  type: LoadBalancer
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  labels:
...

But if we build the overlay instead, we can see that we now have NodePort services:

$ kustomize build $DEV_HOME

...
  name: mysql-pass
type: Opaque
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-wordpress
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: my-wordpress
  type: NodePort
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-wordpress
  name: wordpress
spec:
  ports:
  - port: 80
  selector:
    app: my-wordpress
  type: NodePort
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
...

Notice that everything is unchanged by the patch except the type.  Now let’s look at making use of these objects in kubectl.

Using Kustomize with kubectl

Now, all of this is great, but saving it to a file then running the file seems like a little bit of overkill.  Fortunately there are two ways we can feed this in directly. One is to simply pipe it in, as you would do with any other Linux program:

kustomize build $DEV_HOME | kubectl apply -f -

Or if you’re using Kubernetes 1.14 or above, you can simply use the -k parameter:

kubectl apply -k $DEV_HOME
secret "mysql-pass" created
service "mysql" created
service "wordpress" created
deployment.apps "mysql" created
deployment.apps "wordpress" created

This may not seem like a big deal, but consider this example from the documentation, showing the old way of doing things:

kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
secret/myregistrykey created.

Versus the new way, where we create a kustomization.yaml file:

secretGenerator:
- name: myregistrykey
 type: docker-registry
 literals:
 - docker-server=DOCKER_REGISTRY_SERVER
 - docker-username=DOCKER_USER
 - docker-password=DOCKER_PASSWORD
 - docker-email=DOCKER_EMAIL
EOF

Then simply reference it using the -k parameter:

$ kubectl apply -k .
secret/myregistrykey-66h7d4d986 created

Considering that kustomization.yaml files can be stored in repos and subject to version control, where they can be tracked and more easily managed, this provides a much cleaner way to manage your infrastructure as code.

There are, of course, other things you can do with Kustomize, including adding name prefixes, generating ConfigMaps, and passing down environment variables, but we’ll leave that for another time.  (Let us know in the comments if you’d like to see that sooner rather than later.)

Meanwhile, if you’d like to see more of what’s new in Kubernetes 1.14, don’t forget to join us for that live webinar on March 21.  

LIVE WEBINAR
What's New in Kubernetes 1.15
Thurs., June 20, 2019
REGISTER
TECHNICAL TRAINING
KD250
Accelerated Kubernetes & Docker Bootcamp
LEARN MORE
LIVE DEMO
Create True Multi-Cloud Applications with Istio
REGISTER