Update multiple Kubernetes objects/configmaps in one go!
Tags: kubernetes, linux, devops, beginners
Published: 2024-05-22 12:54:25

There may be cases wherein we just need to update a Kubernetes configmap or any other Kubernetes object based on our requirements.

And let's say it's just one or two configmaps(here we will be talking about configmaps just for simplicity but its applicable for other Kubernetes objects as well) then that's fine, right? We can simply do the following:

- `kubectl edit -n NAMESPACE_NAME configmap CONFIGMAP_NAME`
- Update it based on our requirements.
- Save it.

But think about a scenario, wherein we need to update +100 configmaps with the same values how to do it?

We cannot update or edit each and every object since that would be a bit tedious and will be error-prone as well. Plus there might be chances we might skip some of them.

So, the best way to do it is by using `patch` command in an automated way.

Refer: https://kubernetes.io/docs/reference/kubectl/generated/kubectl_patch/ for more details about it.

Let's see this in action:

- I have a very minimal configmap which contains some DATABASE details.
```
apiVersion: v1
data:
  DATABASE_HOST: "api01.ybdb.io"
  DATABASE_NAME: "api01"
  DATABASE_PORT: "5433"
kind: ConfigMap
metadata:
  name: api01-configmap
  namespace: default
```
- Now, let's assume there is an update instead of port number 5433. Our database now listens on port 5444.
- We can easily accomplish this using `kubectl edit` but let's see `patch` in action:

```
$ kubectl patch configmap api01-configmap -n default -p '{"data":{"DATABASE_PORT":"5444"}}'
configmap/api01-configmap patched
$ kubectl get cm -n default -o yaml api01-configmap
apiVersion: v1
data:
  DATABASE_HOST: api01.ybdb.io
  DATABASE_NAME: api01
  DATABASE_PORT: "5444"
kind: ConfigMap
metadata:
  creationTimestamp: "2024-05-22T10:06:39Z"
  name: api01-configmap
  namespace: default
  resourceVersion: "67651"
  uid: 2d49a0ea-6910-420c-b2bf-00e42e6c08d7
```

- The command is pretty straight forward `kubectl patch configmap api01-configmap -n default -p '{"data":{"DATABASE_PORT":"5444"}}'`
- -n is to specify the namespace name where the configmap resides.
- -p is to specify what patch/update we want in the Kubernetes object.
- Here, under `data:` we are updating a key called `DATABASE_PORT:` to `5444`.
- Note: If in case `DATABASE_PORT:` key doesn't exist, it will create that key for us.

Assume you want to see the output as well in the same command then add -o or --output flag with the type [json,name,yaml,etc].

```
$ kubectl patch configmap api01-configmap -n default -p '{"data":{"DATABASE_PORT":"5444"}}' -o yaml
apiVersion: v1
data:
  DATABASE_HOST: api01.ybdb.io
  DATABASE_NAME: api01
  DATABASE_PORT: "5444"
kind: ConfigMap
metadata:
  creationTimestamp: "2024-05-22T10:47:41Z"
  name: api01-configmap
  namespace: default
  resourceVersion: "69416"
  uid: a303bd0e-7f61-49c0-b671-06649ecdf999
```

But there is another catch, you can also not run the patch command +100 times, I mean definitely you can but again that might be error-prone too.

So, in that case we can write a simple reusable bash script that can do the job for us and can help us to update +100 configmaps in one go.


It can be in any language but I have chosen `bash`, since it's pretty common.

Quick rundown of the script:
- Here I have three variables, NAMESPACE (where the object resides), CONFIGMAP_FILE (input file which contains a list of all the configmaps that need to be updated), DATA (a set of key:value pair which needs to be replaced/added).
- Here I am creating log files as well (update_cm.log - contains generic readable information, patch.log - contains output of patch command).
- As of now, I just have added action as add but we can have other actions as well like replace or remove (based on our requirements).

```
#!/bin/bash

NAMESPACE="default"
CONFIGMAP_FILE="configmaps"
DATA='{"data":{"DATABASE_PORT":"5444"}}'

rm patch.log update_cm.log

if [ ! -f "$CONFIGMAP_FILE" ]; then
  echo "File $CONFIGMAP_FILE not found."
  exit 1
fi

echo `date` >> update_cm.log
echo "----------------------------" >> update_cm.log

action=$1

if [ "$action" == "add" ]; then
  echo "Action: $action"
  echo "Action: $action" >> update_cm.log
  while IFS= read -r cm; do
    echo "Updating ConfigMap: $cm"
    echo "Updating ConfigMap: $cm" >> update_cm.log
    kubectl patch configmap "$cm" -n "$NAMESPACE" -p $DATA >> patch.log 2>&1
  done < "$CONFIGMAP_FILE"

else
  echo "Invalid action, please specify add".
  exit 1
fi

echo "----------------------------" >> update_cm.log
```

Feel free to use it, tweak it, based on your requirements. This script is for configmaps but similar logic we can write for other objects as well if required.

**Happy learning :)**

**References:**
- Google.
- Kubernetes docs (https://kubernetes.io/docs/home/).
- `kubectl explain`

**Disclaimer:** 
- We should not manually update/patch the Kubernetes objects, this should be done when absolutely necessary or needed on the fly.
- Ideally these all values should come from the version control system wherein the values files are maintained.