kubectl patch: Is it possible to add multiple values to an array within a sinlge patch execution
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.
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"}]'
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.
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 -