kubectl patch: Is it possible to add multiple values to an array within a sinlge patch execution

6/25/2020

I tried to use kubectl patch to add two more values to the args list of a kubernetes deployment. I've gone over the officially documented (https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/) variants but did not manage to append more than one value at a time.

Assume this simple deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
spec:
  replicas: 1
  selector:
    matchLabels:
      name: test
  template:
    metadata:
      labels:
        name: test
      name: test
    spec:
      containers:
      - image: alpine
        name: test
        command:
        - echo
        args:
        - my
        - text

I now want to append additional values to the args section. This works for a single value at a time:

Adding a single additional value

kubectl patch deployments.apps test --type=json -p='[{"op": "add", "path": "/spec/t
emplate/spec/containers/0/args/-", "value": "additional" }]'

This works and leaves me with the following:

...
        args:
        - my
        - text
        - additional

But running the patch with an array of values gives me an error:

# running:
k patch deployments.apps test --type=json -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": ["additional","text"] }]'

# results in:
The request is invalid: patch: Invalid value: "...": v1.Deployment.Spec: v1.DeploymentSpec.Template: v1.PodTemplateSpec.Spec: v1.PodSpec.Containers: []v1.Container: v1.Container.Args: []string: ReadString: expects " or n, but found [, error found in #10 byte of ...|itional",["additiona|..., bigger context ...|{"containers":[{"args":["my","text","additional",["additional","text"]],"command":["echo"],"image":"|...

Does anyone know a way to add mutliple values to an array within a single patch command without overwriting the whole args array? Thanks for your help.

-- jonny
json
kubernetes
patch

3 Answers

8/16/2020

Below uses a single patch but it's not very DRY:

kubectl patch deployment <deployment-name> -n <namespace> --type "json" -p '[
{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"arg-1"},
{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"arg-2"},
{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"arg-3"}]'

I've been doing something similar for cert-manager to allow fully automated TLS:

kubectl patch deployment cert-manager -n cert-manager --type "json" -p '[
{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--default-issuer-name=letsencrypt-prod"},
{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--default-issuer-kind=ClusterIssuer"},
{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--default-issuer-group=cert-manager.io"}]'
-- GuyC
Source: StackOverflow

1/20/2022

The simplest way I've found is to use jq to edit the json, so instead of:

kubectl patch deployment <deployment-name> -n <namespace> --type "json" -p '[
{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"arg-1"},
{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"arg-2"},
{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"arg-3"}]'

You can use:

kubectl get deployment <deployment-name> -n <namespace> -o json \
  | jq '.spec.template.spec.containers[0].args += ["arg-1", "arg-2", "arg-3"]'  \
  | kubectl apply -f -

This has an advantage: it allows to inject even objects such as patching permissions. Example (taken from the requirements for upgrading coredns to 1.8.3):

kubectl get clusterrole system:coredns -n kube-system -o json \
  | jq '.rules += [{"apiGroups":["discovery.k8s.io"],"resources":["endpointslices"],"verbs":["list","watch"]}]' \
  | kubectl apply -f -

And another advantage: it is very easy to test before applying, just removing the kubectl apply -f - part:

kubectl get clusterrole system:coredns -n kube-system -o json \
  | jq '.rules += [{"apiGroups":["discovery.k8s.io"],"resources":["endpointslices"],"verbs":["list","watch"]}]' \
-- MagMax
Source: StackOverflow

6/25/2020

You can use kubectl edit command to edit the resource.
Example usage:
kubectl edit deploy <deployment_name>

For more info, refer: https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#edit.

Edit: There is a nasty way of doing it programmatically. You can pipe the yaml to python, alter the values you want to change and apply the new yaml. In your case, it would be something like,

kubectl get deploy <deploy_name> -o yaml | python -c 'import sys,yaml; yml = yaml.safe_load(sys.stdin); yml["spec"]["template"]["spec"]["containers"][0]["args"].extend(["newValue1", "newValue2"]); print(yaml.dump(yml));' | kubectl apply -f -

Obviously you want to do this only if there isn't any easier way to do it.

-- lightBullet
Source: StackOverflow