Kubernetes: patching container arguments array with kubectl and jq

The need to configure a specific pod’s container arguments is a common Kubernetes administration task.  As examples, you might need to enable verbose logging, set an explicit value to override a default, or configure a host name or port set in a container’s arguments.

In the example below, we are targeting the ‘metrics-server’ in the kube-system namespace, but the same logic would apply to any resource.

Adding a single argument

# define variables that target deployment
deployment_name=metrics-server
deployment_ns=kube-system
container_name=metrics-server
additional_argument="--v=4"

# make sure 'jq' utility is installed for json manipulation
sudo apt install -y jq

# show current arguments
kubectl get deployment $deployment_name -n $deployment_ns -o json | jq ".spec.template.spec.containers[] | select (.name == \"$container_name\").args"

# get index of pod container
container_index=$(kubectl get deployment $deployment_name -n $deployment_ns -o json | jq ".spec.template.spec.containers | to_entries | .[] | select(.value.name | contains (\"$container_name\")) | .key")
echo "Going to update arguments of deployment/container/index: $deployment_name/$container_name/$container_index"

# do append of single argument to deployment
# append if dry run: --dry-run=client -o yaml
kubectl patch deployment $deployment_name -n $deployment_ns --type=json -p="[{'op': 'add', 'path': '/spec/template/spec/containers/$container_index/args/-', 'value': '$additional_argument' }]"

Adding multiple arguments

If you wanted to add multiple arguments at the same time, use ‘jq‘.

additional_arguments_json='["--v=4","--kubelet-insecure-tls"]' 

# append arguments and reapply
kubectl get deployment $deployment_name -n $deployment_ns -o json | jq ".spec.template.spec.containers[$container_index].args += $additional_arguments_json" | kubectl apply -f -

This appends to the argument list without checking for existence first.  So if these arguments already exist, you will end up with duplicates.

Adding multiple arguments idempotently (no duplicates)

If you need to ensure that added arguments are not duplicates, and that any existing arguments are overwritten with your new value, then use the commands below.

# save all current arguments to temp file
argsfile=$(mktemp -t "$container_name.XXXXXXXX.json")
kubectl get deployment $deployment_name -n $deployment_ns -o jsonpath="{.spec.template.spec.containers[0].args}" > $argsfile

# add argument as test
jq ". += [\"--mytestarg\"]" $argsfile | tee $argsfile.temp
cp $argsfile.temp $argsfile

# remove argument as test
jq ". |= map(select(startswith(\"--mytestarg\")|not))" $argsfile | tee $argsfile.temp
cp $argsfile.temp $argsfile

# do bulk modification. ensure no duplicates by first doing remove, then add
arg_array=("--a" "--b=2" "--v=5")
for carg in ${arg_array[@]}; do 
  justkey=$(echo $carg | awk -F'[= ]' '{print $1}')
  jq ". |= map(select(startswith(\"$justkey\")|not))" $argsfile > $argsfile.temp ; cp $argsfile.temp $argsfile
  jq ". += [\"$carg\"]" $argsfile > $argsfile.temp ; cp $argsfile.temp $argsfile
done

# show final result
jq . $argsfile

# apply latest arguments
kubectl get deployment $deployment_name -n $deployment_ns -o=json | jq ".spec.template.spec.containers[$container_index].args |= $(cat $argsfile)" | kubectl apply -f -

 

REFERENCES

jq manual

stackoverflow, getting index of item in yaml array using jq

stackoverflow, kubectl patch to delete specific object in array without numerical index

jsonpatch reference, library underneath kubectl patch

kubernetes.io, kubectl patch reference

stackoverflow, shows kubectl json patch with add for appending

kubernets.io, kubectl patch

jq, pulling parent fields

stackoverflow, jq deletion for array items that startwith

 

NOTES

jq with ‘|=’ would clear out and replace arguments with our additional argument list (versus ‘+=’ appends)

check for existence of argument first

# if you needed logic to check if argument was already set
if kubectl get deployment $deployment_name -n $deployment_ns -o=jsonpath="{.spec.template.spec.containers[$container_index].args}" | grep -q -- "$additional_argument" ; then echo "found argument '$additional_argument' there already"; fi

inline patch to null finalizers

kubectl patch pod pod_name -p '{"metadata":{"finalizers":null}}'