Kustomize

Kustomize traverses a Kubernetes manifest to add, remove or update configuration options without forking. It is available both as a standalone binary and as a native feature of kubectl (and by extension oc).

The principals of kustomize are:

  • Purely declarative approach to configuration customization

  • Manage an arbitrary number of distinctly customized Kubernetes configurations

  • Every artifact that kustomize uses is plain YAML and can be validated and processed as such

  • As a "templateless" templating system; it encourages using YAML without forking the repo.

Kustomize Logo

Exploring Kustomize

Exploring the Kustomize CLI

The kustomize CLI should have been installed as part of the lab setup. Verify that it has been installed.

kustomize version --short

This should display the version, it should look something like this.

{kustomize/v4.0.5  2021-02-13T21:21:14Z  }

Kustomize, at it’s core, is meant to build native Kubernetes manifests based on YAML, while leaving the original YAML intact. It achieves this in a "template-less" templating format. This is done by providing a kustomization.yaml file.

We will be focusing on two sub-commands the build command and the edit command.

The build command takes the YAML source (via a path or URL) and creates a new YAML that can be piped into kubectl create. We will work with an example in the documentation/modules/ROOT/examples/kustomize-build directory.

cd documentation/modules/ROOT/examples/kustomize-build

Here you should see two files, a kustomization.yaml file and a welcome.yaml file, let’s have a look at them.

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: welcome-php
  name: welcome-php
spec:
  replicas: 1
  selector:
    matchLabels:
      app: welcome-php
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: welcome-php
    spec:
      containers:
      - image: quay.io/redhatworkshops/welcome-php:latest
        name: welcome-php
        resources: {}

This file shows nothing special. Just a standard Kubernetes manifest.

What if, for example, we wanted to add a label to this manifest without editing it? This is where the kustomization.yaml file comes in.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./welcome.yaml
patchesJson6902:
- patch: |-
    - op: add
      path: /metadata/labels/testkey
      value: testvalue
  target:
    group: apps
    kind: Deployment
    name: welcome-php
    version: v1
images:
- name: quay.io/redhatworkshops/welcome-php
  newTag: ffcd15

As you can see in the output there isn’t much. The two sections for this example are the resources and the patchesJson6902 sections.

resources is an array of individual files, directories, and/or URLs where other manifests are stored. In this example we are just loading in one file. The (patchesJson6902 is a patching RFC that kustomize supports. As you can see, in the patchesJson6902 file, I am adding a label to this manifest.

NOTE You can read about what options are available for patching in the official documentation site

Build this manifest by running:

kustomize build

You can see that the new label got added to the manifest!

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: welcome-php
    testkey: testvalue
  name: welcome-php
spec:
  replicas: 1
  selector:
    matchLabels:
      app: welcome-php
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: welcome-php
    spec:
      containers:
      - image: quay.io/redhatworkshops/welcome-php:ffcd15
        name: welcome-php
        resources: {}

You can use the kustomize edit command instead of writing YAML. For example, you can change the image tag this Deployment uses from latest to ffcd15 by running the following:

kustomize edit set image quay.io/redhatworkshops/welcome-php:ffcd15

This will update the kustomization.yaml file with a images section.

cat kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ./welcome.yaml
patchesJson6902:
- patch: |-
    - op: add
      path: /metadata/labels/testkey
      value: testvalue
  target:
    group: apps
    kind: Deployment
    name: welcome-php
    version: v1
images:
- name: quay.io/redhatworkshops/welcome-php
  newTag: ffcd15

Now when you run:

 kustomize build .

You should see not only the new label but also the new ffcd15 image tag.

NOTE You may have to close the kustomization.yaml tab and re-open it to see the changes.

You can see how you can take already existing YAML and modify it for your specific environment without the need to copy or edit the original.

Kustomize can be used to write a new YAML file or be pipped into the kubectl (or oc) command. Example:

kustomize build . | kubectl apply -f -

Exploring Kustomize with Kubectl

Since Kubernetes 1.14, The kubectl command (and by extension the oc cli) has support for Kustomize built in.

You can see this by running:

kubectl kustomize --help

This runs the kustomize build command. You can see this by running:

kubectl kustomize

Although you can use this to pipe it into the apply command, you don’t have to. The kubectl apply command has the -k option that will run the build before it applies the manifest.

  • Minikube

  • OpenShift

To test this out, first create a namespace:

kubectl create namespace kustomize-test

Next make sure you’re on the namespace:

kubectl config set-context --current --namespace=kustomize-test

To test this out, first create a project:

oc new-project kustomize-test

Next make sure you’re on the project:

oc project kustomize-test

Finally run the command to build and apply the manifests:

kubectl apply -k ./

NOTE You can pass not only directories, but URLs as well. The only requirement is that you have a kustomization.yaml file in the path.

This should create the deployment and you should see the pods running in the namespace:

kubectl get pods -n kustomize-test

You can see the deployment was created with the additional labels:

kubectl get deployment welcome-php -o jsonpath='{.metadata.labels}' | jq -r

Also, the image was updated based on the customization that was made:

kubectl get deploy welcome-php  -o jsonpath='{.spec.template.spec.containers[].image}{"\n"}'

As you can see kustomize can be a powerful tool.

  • Minikube

  • OpenShift

You can now safely delete this namespace:

kubectl delete namespace kustomize-test

If you want, you can now delete this project as we won’t use it for next steps

oc delete project kustomize-test

Deploying Kustomized Application

In previous chapter, you learned that in a GitOps workflow; the entire application stack (including infrastructure) is reflected in a git repo. The challenge is how to do this without duplicating YAML.

So now that you’ve explored kustomize, let’s see how it fits into Argo CD and how it can be used in a GitOps workflow.

Before preceeding, move back into the home directory:

cd -

The Argo CD Web Console

Access Argo CD Web Console.

Once you have accepted the self signed certificate, you should be presented with the Argo CD login screen.

ArgoCD Login

You can login with the following

Username:

admin

Password:

  • Minikube

  • OpenShift

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
oc extract secret/openshift-gitops-cluster -n openshift-gitops --to=-

Kustomized Application

Argo CD has native support for Kustomize. You can use this to avoid duplicating YAML for each deployment. This is especially good to use if you have different environments or clusters you’re deploying to.

Take a look at the Application definition:

  • Minikube

  • OpenShift

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: bgdk-app
  namespace: argocd
spec:
  destination:
    namespace: bgdk
    server: https://kubernetes.default.svc
  project: default
  source:
    path: apps/bgd/overlays/bgdk
    repoURL: https://github.com/redhat-developer-demos/openshift-gitops-examples
    targetRevision: minikube
  syncPolicy:
    automated:
      prune: true
      selfHeal: false
    syncOptions:
    - CreateNamespace=true

This application is pointed to the same repo but different directory.

This is using a concept of an "overlay", where you have a "base" set of manifests and you overlay your customizations.

Take a look at the kustomization.yaml file:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: bgdk
resources:
- ../../base
- bgdk-ns.yaml
patchesJson6902:
  - target:
      version: v1
      group: apps
      kind: Deployment
      name: bgd
      namespace: bgdk
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0/env/0/value
        value: yellow
  - target:
      version: v1
      group: networking.k8s.io
      kind: Ingress
      name: bgd
      namespace: bgdk
    patch: |-
      - op: replace
        path: /spec/rules/0/host
        value: bgdk.devnation

This kustomization.yaml take the base application and patches the manifest so that we get a yellow square instead of a blue one. It also deploys the application to the bgdk namespace (denoted by the namespace: section of the file) and update the Ingress hostname for this new namespace to be bgdk.devnation.

Add Minikube IP (minikube ip) and the Ingress hostname bgdk.devnation to your Host file, like /etc/hosts.

Example:

192.168.39.242 bgd.devnation bgdk.devnation

Deploy this application:

kubectl apply -f documentation/modules/ROOT/examples/minikube/bgdk-app/bgdk-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: bgdk-app
  namespace: openshift-gitops
spec:
  destination:
    namespace: bgdk
    server: https://kubernetes.default.svc
  project: default
  source:
    path: apps/bgd/overlays/bgdk
    repoURL: https://github.com/redhat-developer-demos/openshift-gitops-examples
    targetRevision: main
  syncPolicy:
    automated:
      prune: true
      selfHeal: false
    syncOptions:
    - CreateNamespace=true

This application is pointed to the same repo but different directory.

This is using a concept of an "overlay", where you have a "base" set of manifests and you overlay your customizations.

Take a look at the kustomization.yaml file:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: bgdk
resources:
- ../../base
- bgdk-ns.yaml
patchesJson6902:
  - target:
      version: v1
      group: apps
      kind: Deployment
      name: bgd
      namespace: bgdk
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0/env/0/value
        value: yellow

This kustomization.yaml take the base application and patches the manifest so that we get a yellow square instead of a blue one. It also deploys the application to the bgdk namespace (denoted by the namespace: section of the file).

Deploy this application:

kubectl apply -f documentation/modules/ROOT/examples/bgdk-app/bgdk-app.yaml

This should show you two apps on the Argo CD UI.

Two Apps

Open the application’s Ingress or Route.

Yellow Square

As you can see, the application deployed with your customizations! To review what we just did.

  • Deployed an Application called bgd with a blue square.

  • Deployed another Application based on bgd called bgdk

  • The Application bgdk was deployed in it’s own namespace, with deployment customizations.

  • ALL without having to duplicate YAML!