Tutorial - Kustomize

width=100%

Objective

Understand the basics of Kustomize, a tool whose personalize default YAML manifests with custom values.

Installation and first use

Install Kustomize via the GCloud CLI:

gcloud components install kustomize

Make sure it is properly installed:

kustomize version

Preamble

A nice feature of Kustomize, besides patching values, is to inspect Kubernetes resources in a directory.

In a directory containing some YAML manifests, issue the following command to list resources in a tree-like structure:

kustomize cfg tree .

Another subcommand of cfg is count that resumes how many resources of each kind is present in the directory.

kustomize cfg count .

Add default labels

Create directory named base and add the following Service and Deployment:

kubia-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: kubia

kubia-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubia
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kubia
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
      - image: luksa/kubia:v1
        name: nodejs

Then create a file kustomization.yaml with the following content:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - kubia-deploy.yaml
  - kubia-svc.yaml
commonLabels:
  pkg: fila2
  stage: tuto

This tells Kustomize to manage our two resources and for each of them add two labels pkg: fila2 and stage: tuto.

To apply the customization, issue

kustomize build .

Notice that labels are appended not only on the "/metadata" field, but also under "/selector/matchLabels" and "/template/metadata" of the Deployment, and "/spec/selector" of the Service.

Remember that Kustomize do not modifiy the original YAML manifest, this is why the build command outputs the result but do not write anything to disk. In order to apply the resulting configuration onto the cluster, we can pipe the result into kubectl as such

kustomize build . | kubectl apply -f -

But Kustomize is built-in kubectl, so we can more simply use the -k flag to achieve the same result. In fact, we need not have the kustomize CLI tool to use it. Issue the following command:

kubectl apply -k .

and show Services and Deployments with their labels to confirm:

kubectl get svc,deploy --show-labels

Customise "dev" and "prod" environments

We have applied a basic customization to a base directory. We will now create two sibling directories dev and prod that will apply more specific variants on the base directory. The file structure will look like this

├── base
│   ├── kubia-deploy.yaml
│   ├── kubia-svc.yaml
│   └── kustomization.yaml
├── dev
│   └── kustomization.yaml
└── prod
    ├── kubia-deploy-patch.yaml
    ├── kubia-svc-patch.yaml
    └── kustomization.yaml

Each directory contains a kustomization.yaml file. The specific dev and prod will make a reference to the base and add some patch overlays.

Create dev/kustomization.yaml with the following:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../base
patches:
  - target:
      kind: Deployment
      name: kubia
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 5
      - op: add
        path: /spec/template/spec/containers/0/imagePullPolicy
        value: Never

It instructs Kustomize to use the resources from the base directory and apply a patch to the deployment/kubia resource. The patch operations are written in the JSON Patch format.

Build the customization with kustomize build dev from the parent directory. If everything seems ok, apply the patch to the cluster with kubectl apply -k dev and verify the replica count with

kubectl get deploy/kubia

and the imagePullPolicy value with

kubectl get deploy/kubia -oyaml | grep imagePullPolicy

Note that both the prod/kustomization.yaml and the base/kustomization.yaml patches are applied.

Now create prod/kustomization.yaml with the following:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../base
patches:
  - path: kubia-deploy-patch.yaml
  - path: kubia-svc-patch.yaml

Here, the patches are just files which will consist of a subset of the original ones, with updated values. Kustomize will detect the different patch format and will use the strategic merge operation.

In prod/kubia-deploy-patch.yaml, paste the following:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubia
spec:
  template:
    spec:
      containers:
        - name: nodejs
          resources:
            requests:
              cpu: 100m

Notice that applying this file as is to the cluster will not work because it is not complete (e.g. replica is missing). Only the fields we want to overlay and the fields to identify their position are present. Namely in a strategic merge we need to provide the three apiVersion, kind and metadata/name fields to select the corresponding resource. Also, the containers field is an array, so we need to tell Kustomize which element to update, here we use the name field.

In prod/kubia-svc-patch.yaml, paste the following:

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - port: 80
    targetPort: 5050

Here, in addition to the resource selection fields (apiVersion, kind and metadata/name), we select an element of the ports array by using the port field. All this to update the targetPort.

Build the customization and apply it to the cluster if everything seems good.

Clean the resources

Delete the resources by using a label selector on the CLI with the following command

kubectl delete svc,deploy -lstate=tuto

which tell Kubernetes to delete all Services and Deployments that have the label stage=tuto.