What is Kustomize ?
Tags: devops, kubernetes
Published: 2022-05-03 21:13:21

When we start with Kubernetes and use YAML config files, generally we begin to install them one by one with the following command.

```
kubectl apply -f <file>
```

Then, we discover that we can directly target a complete folder instead of a file
```
kubectl apply -f <folder>
```

But, if we are doing it in each environment that we have, it can quickly be annoying to duplicate all the configs or update it each time we switch. That's why, in these cases, we start to use some tools to generate the configs dynamically.

Today, we will speak about one of them, **Kustomize**.

---

## What is Kustomize?
**Kustomize** is a configuration management tool embeded in Kubernetes! 

So if you already have **kubectl** setup, you can directly use it.

Unlike **Helm**, it's not a templating tool, but really a config management tool.

To give you a quick example to compare both tool, Helm will use a template (like behind) and the user will define a value for each variable.
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: the-deployment
spec:
  replicas: 5
  template:
    containers:
      - name: {{ .Values.containerName }}
        image: {{ .Values.containerImage }}
```
In this example, the user can define the container name and its image. But, they can't update the number of replicas.

Once called, Helm will generate a yaml file from the template and the values given by the user.

Kustomize will allow the user to override any configuration value. *(We will see how later.)*

---

Before going further, here is the context for our next examples.
```
- /kubernetes
    - /application
        - deployment.yaml
        - configmap.yaml
```

*deployment.yaml*
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
spec:
  replicas: 1
  template:
    containers:
      - name: my-container
        image: ubuntu:latest
        env:
        - name: TEST
          value: TOTO
        volumeMounts:
        - name: config-volume
          mountPath: /configs/
      volumes:
      - name: config-volume
        configMap:
          name: example-config
```

*configmap.yaml*
```yaml
 apiVersion: v1
 kind: ConfigMap
 metadata:
   name: example-config
   namespace: example
 data:
   config.json: |
     {
       "environment" : "test"
     }
```

---

## How works Kustomize ?
First, **Kustomize** needs a **kustomization.yaml** file which will contain all the configurations that it needs to know.

### Base
In our example context, we will add this file in the **/application** folder with this content : 
```yaml
resources:
  - deployment.yaml
  - configmap.yaml
```

Here, we indicate to Kustomize which files are the Kubernetes config files that we want to apply when this kustomization file is called. This folder become our **base** for our next configurations.

Therefore, if we use one of the following commands, we will generate the deployment and the configmap as defined in our YAML files.

```
kubectl kustomize .\kubernetes\application\ | kubectl apply -f -

# Or

kubectl apply -k .\kubernetes\application\
```

### Customization
Now that we have our base, we can create our custom configurations for each environment that we have.

In the **/kubernetes** folder, we create a folder **/environments**. Then, in this folder, we create two folders **/dev** and **/prod** *(representing each environment that we have)*, and we create a **kustomization.yaml** file in both **/dev** and **/prod**.

In both files, we add this content
```yaml
bases:
  - ../../application
```
This bloc define which is the configuration basis for our customization. *(In this example, it targets the previous folder that we configured)*

So, if we are using the same command to use Kustomize but targeting one of the environment folder, the deployment and configmap defined in the base will be created.
```
kubectl kustomize .\kubernetes\environments\dev | kubectl apply -f -

# Or

kubectl apply -k .\kubernetes\environments\dev
```

---

## Possible updates
Searching through the **Kustomize** documentation, you will see each and every update available, but now we will only see the principal ones.


### Patch
A patch in Kustomize is a file which will contains a partial configuration of a component which will override the base configuration.

For example, in production we want to increase the number of replicas and define how much resources a pod can use. So we create the two following files in the **/prod** folder.

*replica_count.yaml* *(Note: Kustomize doesn't care about the name)*
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment # Name of the deployment to update
spec:
  replicas: 6 # The new value
``` 

*resources.yaml*
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
spec:
  template:
    containers:
      - name: my-container
        resources:
          requests:
            memory: "50Mi"
            cpu: "50m"
          limits:
            memory: "500Mi"
            cpu: "500m"
```

Now, to be sure that they will be used as patches, we must add the following code bloc in **kustomization.yaml** in the **/prod** folder.

```yaml
patches:
  - replica_count.yaml
  - resources.yaml
```
We listed the two newly created files containing the new values.

---

### Patch Strategic Merge
Sometimes, we don't want to override the value of a list, but add something in the list. In this case, we use **patchesStrategicMerge**.

For example, if I want to add an environment variable to my container, I should :
- create a file with the new environment variables to add in the **/prod** folder

*env.yaml*
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
spec:
  template:
    containers:
      - name: my-container
        env:
        - name: ENVIRONMENT
          value: Production
```

- add the following bloc in **kustomization.yaml**
```yaml
patchesStrategicMerge:
  - env.yaml
```

Then, when it will be deployed in production, the container will have these environment variables : 
- TEST : TODO
- ENVIRONMENT : Production

---

### Generators
In Kustomize, some parameters exist to generate configmaps and secrets. Both are similar, so we will do the example with the **configMapGenerator**.

```yaml
configMapGenerator:
- name: example-config
  namespace: example 
  #behavior: replace
  files:
    - configs/config.json
```

In this code that we can found in the **kustomization.yaml** file, a configmap named "**example-config**" will be created in the **example* namespace with the content of **configs/config.json** as value.

In the commented line, we can see the parameter **behavior** which allows us to replace an existing configmap instead of creating a new one.

---

### Images
The last parameter that we will see today allows us to do some updates about the images used in our configurations

*Definition example in kustomization.yaml*
```yaml
images:
- name: hello-world 
  newTag: linux
  newName: ubuntu 
```

In this example, we see 3 parameters:
- **name** - To find all the images matching this name where the override will occur
- **newTag** - The new tag of the image to use
- **newName** - The new name of the image to use

---

If you are curious and wanted to go further, please go check the [documentation](https://kustomize.io). We only saw a part of Kustomize. 

I hope it will help you! 🍺

Don’t hesitate to give me feedback here, on twitter or by LinkedIn, I will be glad to read it. You can use the same links if you want to contact me or want to collaborate with me.

---

<center><h3>You want to support me?</h3></center>
<a href="https://www.buymeacoffee.com/mxguilbert7" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>