Runbook — Patch di risorse Kubernetes / OpenShift
Runbook — Patch di risorse Kubernetes / OpenShift
1. Concetti base
In Kubernetes/OpenShift puoi modificare una risorsa in vari modi:
oc edit <kind> <name> -n <namespace>oppure con patch diretta:
oc patch <kind> <name> -n <namespace> --type <tipo_patch> -p '<payload>'I tipi patch più usati sono:
| Tipo | Quando usarlo |
|---|---|
merge | Il più comodo per modificare campi semplici dentro oggetti YAML/JSON |
json | Utile per aggiungere/rimuovere/sostituire campi in modo preciso |
strategic | Utile su alcune risorse Kubernetes native, ma non sempre supportato sulle CRD |
Su OpenShift puoi usare sia oc sia kubectl. Negli esempi uso oc, ma quasi tutti i comandi valgono anche con kubectl.
2. Prima regola: fai sempre backup della risorsa
Prima di patchare:
oc get <kind> <name> -n <namespace> -o yaml > backup-<kind>-<name>.yamlEsempio:
oc get argocd openshift-gitops -n openshift-gitops -o yaml > backup-argocd-openshift-gitops.yamlSe hai kubectl-neat:
oc get argocd openshift-gitops -n openshift-gitops -o yaml | kubectl-neat > backup-argocd-openshift-gitops-neat.yaml3. Verificare il valore attuale di un campo
Con jsonpath:
oc get <kind> <name> -n <namespace> -o jsonpath='{.spec.campo}{"\n"}'Esempio per OpenShift GitOps notifications:
oc get argocd openshift-gitops -n openshift-gitops \ -o jsonpath='{.spec.notifications.enabled}{"\n"}'Con jq:
oc get <kind> <name> -n <namespace> -o json | jq '.spec'Esempio:
oc get argocd openshift-gitops -n openshift-gitops -o json | jq '.spec.notifications'4. Patch semplice con --type merge
4.1 Impostare un campo booleano a true
oc patch <kind> <name> -n <namespace> \ --type merge \ -p '{"spec":{"campo":{"enabled":true}}}'Esempio reale: abilitare notifications su OpenShift GitOps:
oc patch argocd openshift-gitops \ -n openshift-gitops \ --type merge \ -p '{"spec":{"notifications":{"enabled":true}}}'Verifica:
oc get argocd openshift-gitops -n openshift-gitops \ -o jsonpath='{.spec.notifications.enabled}{"\n"}'4.2 Impostare un campo booleano a false
oc patch argocd openshift-gitops \ -n openshift-gitops \ --type merge \ -p '{"spec":{"notifications":{"enabled":false}}}'4.3 Cambiare una stringa
oc patch <kind> <name> -n <namespace> \ --type merge \ -p '{"spec":{"campo":"nuovo-valore"}}'Esempio:
oc patch route my-route -n my-namespace \ --type merge \ -p '{"spec":{"host":"app.example.com"}}'4.4 Cambiare un numero
oc patch <kind> <name> -n <namespace> \ --type merge \ -p '{"spec":{"replicas":3}}'Esempio Deployment:
oc patch deployment my-app -n my-namespace \ --type merge \ -p '{"spec":{"replicas":3}}'Nota: per i replica è spesso più leggibile usare:
oc scale deployment my-app -n my-namespace --replicas=35. Patch annidata
Se il campo è dentro più livelli YAML:
spec: server: route: enabled: falsePatch:
oc patch <kind> <name> -n <namespace> \ --type merge \ -p '{"spec":{"server":{"route":{"enabled":true}}}}'Esempio ArgoCD route:
oc patch argocd openshift-gitops \ -n openshift-gitops \ --type merge \ -p '{"spec":{"server":{"route":{"enabled":true}}}}'6. Patch di risorse gestite da operator/controller
Se la console mostra:
Managed resourceThis resource is managed by ...la patch può essere sovrascritta.
Prima controlla owner, label e annotation:
oc get <kind> <name> -n <namespace> -o json | jq '.metadata.ownerReferences'oc get <kind> <name> -n <namespace> -o json | jq '.metadata.labels'oc get <kind> <name> -n <namespace> -o json | jq '.metadata.annotations'Esempio:
oc get argocd openshift-gitops -n openshift-gitops -o json | jq '.metadata.ownerReferences'oc get argocd openshift-gitops -n openshift-gitops -o json | jq '.metadata.labels, .metadata.annotations'Se la risorsa è gestita da ArgoCD/GitOps, modifica il manifest nel repository Git o nella Application che la riconcilia.
Cerca eventuali Application ArgoCD:
oc get applications.argoproj.io -ACerca riferimenti alla risorsa:
oc get applications.argoproj.io -A -o yaml | grep -B20 -A20 "openshift-gitops"7. Patch con file JSON/YAML
Se il payload è lungo, evita il one-liner e usa un file.
Crea file:
cat > patch.json <<'EOF'{ "spec": { "notifications": { "enabled": true } }}EOFApplica:
oc patch argocd openshift-gitops \ -n openshift-gitops \ --type merge \ --patch-file patch.json8. Patch label
8.1 Aggiungere o aggiornare una label
Modo consigliato:
oc label <kind> <name> -n <namespace> chiave=valore --overwriteEsempio:
oc label namespace my-namespace environment=prod --overwriteCon patch:
oc patch <kind> <name> -n <namespace> \ --type merge \ -p '{"metadata":{"labels":{"environment":"prod"}}}'8.2 Rimuovere una label
oc label <kind> <name> -n <namespace> chiave-Esempio:
oc label namespace my-namespace environment-Con JSON patch:
oc patch <kind> <name> -n <namespace> \ --type json \ -p='[{"op":"remove","path":"/metadata/labels/environment"}]'9. Patch annotation
9.1 Aggiungere o aggiornare una annotation
Modo consigliato:
oc annotate <kind> <name> -n <namespace> chiave=valore --overwriteEsempio:
oc annotate deployment my-app -n my-namespace backup.velero.io/backup-volumes=data --overwriteCon patch:
oc patch <kind> <name> -n <namespace> \ --type merge \ -p '{"metadata":{"annotations":{"mia.annotation/chiave":"valore"}}}'9.2 Rimuovere una annotation
oc annotate <kind> <name> -n <namespace> chiave-Esempio:
oc annotate deployment my-app -n my-namespace backup.velero.io/backup-volumes-Con JSON patch, attenzione agli slash / nella chiave: vanno scritti come ~1.
Esempio annotation:
backup.velero.io/backup-volumesPath JSON patch:
/metadata/annotations/backup.velero.io~1backup-volumesComando:
oc patch deployment my-app -n my-namespace \ --type json \ -p='[{"op":"remove","path":"/metadata/annotations/backup.velero.io~1backup-volumes"}]'10. JSON Patch: add, replace, remove
Il tipo json usa operazioni precise.
10.1 Replace
oc patch <kind> <name> -n <namespace> \ --type json \ -p='[{"op":"replace","path":"/spec/replicas","value":3}]'Esempio:
oc patch deployment my-app -n my-namespace \ --type json \ -p='[{"op":"replace","path":"/spec/replicas","value":3}]'10.2 Add
oc patch <kind> <name> -n <namespace> \ --type json \ -p='[{"op":"add","path":"/spec/nuovoCampo","value":"valore"}]'10.3 Remove
oc patch <kind> <name> -n <namespace> \ --type json \ -p='[{"op":"remove","path":"/spec/campoDaRimuovere"}]'Esempio:
oc patch route my-route -n my-namespace \ --type json \ -p='[{"op":"remove","path":"/spec/host"}]'11. Patch di liste/array
11.1 Aggiungere un elemento in fondo a una lista
Usa /- per append.
Esempio: aggiungere una tolleration a un Deployment:
oc patch deployment my-app -n my-namespace \ --type json \ -p='[ { "op": "add", "path": "/spec/template/spec/tolerations/-", "value": { "key": "node-role.kubernetes.io/infra", "operator": "Exists", "effect": "NoSchedule" } } ]'Se la lista tolerations non esiste, prima devi crearla:
oc patch deployment my-app -n my-namespace \ --type json \ -p='[ { "op": "add", "path": "/spec/template/spec/tolerations", "value": [] } ]'Poi aggiungi l’elemento.
11.2 Sostituire il primo elemento di una lista
oc patch <kind> <name> -n <namespace> \ --type json \ -p='[{"op":"replace","path":"/spec/lista/0","value":"nuovo-valore"}]'11.3 Rimuovere il primo elemento di una lista
oc patch <kind> <name> -n <namespace> \ --type json \ -p='[{"op":"remove","path":"/spec/lista/0"}]'12. Patch nodeSelector e tolerations su Deployment
12.1 Aggiungere nodeSelector
oc patch deployment my-app -n my-namespace \ --type merge \ -p '{"spec":{"template":{"spec":{"nodeSelector":{"node-role.kubernetes.io/infra":""}}}}}'12.2 Aggiungere toleration infra
Se tolerations non esiste:
oc patch deployment my-app -n my-namespace \ --type merge \ -p '{"spec":{"template":{"spec":{"tolerations":[{"key":"node-role.kubernetes.io/infra","operator":"Exists","effect":"NoSchedule"}]}}}}'Attenzione: con merge, una lista viene sostituita interamente. Se esistono già altre toleration, meglio usare JSON patch append.
oc patch deployment my-app -n my-namespace \ --type json \ -p='[ { "op": "add", "path": "/spec/template/spec/tolerations/-", "value": { "key": "node-role.kubernetes.io/infra", "operator": "Exists", "effect": "NoSchedule" } } ]'13. Patch risorse CPU/Memoria su Deployment
13.1 Cambiare requests/limits del primo container
oc patch deployment my-app -n my-namespace \ --type merge \ -p '{ "spec": { "template": { "spec": { "containers": [ { "name": "my-container", "resources": { "requests": { "cpu": "100m", "memory": "256Mi" }, "limits": { "cpu": "500m", "memory": "512Mi" } } } ] } } } }'Per i Deployment, lo strategic merge può funzionare meglio sulle liste di container perché usa name come chiave di merge:
oc patch deployment my-app -n my-namespace \ --type strategic \ -p '{ "spec": { "template": { "spec": { "containers": [ { "name": "my-container", "resources": { "requests": { "cpu": "100m", "memory": "256Mi" }, "limits": { "cpu": "500m", "memory": "512Mi" } } } ] } } } }'Nota: sulle CRD lo strategic merge spesso non è supportato. Usa merge o json.
14. Patch Service
14.1 Cambiare type da ClusterIP a NodePort
oc patch svc my-service -n my-namespace \ --type merge \ -p '{"spec":{"type":"NodePort"}}'14.2 Cambiare type da NodePort a ClusterIP
Prima potresti dover rimuovere i nodePort assegnati.
oc patch svc my-service -n my-namespace \ --type merge \ -p '{"spec":{"type":"ClusterIP"}}'14.3 Impostare un nodePort specifico
Attenzione: il nodePort deve essere libero e nel range ammesso dal cluster.
oc patch svc my-service -n my-namespace \ --type json \ -p='[ { "op": "replace", "path": "/spec/ports/0/nodePort", "value": 30080 } ]'15. Patch Route OpenShift
15.1 Cambiare host
oc patch route my-route -n my-namespace \ --type merge \ -p '{"spec":{"host":"my-app.apps.example.com"}}'15.2 Cambiare termination TLS
oc patch route my-route -n my-namespace \ --type merge \ -p '{"spec":{"tls":{"termination":"edge","insecureEdgeTerminationPolicy":"Redirect"}}}'15.3 Rimuovere TLS da una Route
oc patch route my-route -n my-namespace \ --type json \ -p='[{"op":"remove","path":"/spec/tls"}]'16. Patch IngressController OpenShift
16.1 Cambiare numero repliche router
oc patch ingresscontroller default -n openshift-ingress-operator \ --type merge \ -p '{"spec":{"replicas":3}}'16.2 Aggiungere nodePlacement su infra
oc patch ingresscontroller default -n openshift-ingress-operator \ --type merge \ -p '{ "spec": { "nodePlacement": { "nodeSelector": { "matchLabels": { "node-role.kubernetes.io/infra": "" } }, "tolerations": [ { "key": "node-role.kubernetes.io/infra", "operator": "Exists", "effect": "NoSchedule" } ] } } }'17. Patch MachineConfigPool
17.1 Pausare un MachineConfigPool
oc patch mcp worker \ --type merge \ -p '{"spec":{"paused":true}}'17.2 Riattivare un MachineConfigPool
oc patch mcp worker \ --type merge \ -p '{"spec":{"paused":false}}'Verifica:
oc get mcp18. Patch Operator Subscription
18.1 Cambiare installPlanApproval a Manual
oc patch subscription <subscription-name> -n <namespace> \ --type merge \ -p '{"spec":{"installPlanApproval":"Manual"}}'Esempio:
oc patch subscription openshift-gitops-operator -n openshift-operators \ --type merge \ -p '{"spec":{"installPlanApproval":"Manual"}}'18.2 Cambiare channel
oc patch subscription <subscription-name> -n <namespace> \ --type merge \ -p '{"spec":{"channel":"stable"}}'Esempio:
oc patch subscription openshift-gitops-operator -n openshift-operators \ --type merge \ -p '{"spec":{"channel":"latest"}}'19. Patch ConfigMap
19.1 Cambiare un valore semplice
oc patch configmap my-config -n my-namespace \ --type merge \ -p '{"data":{"CHIAVE":"valore"}}'19.2 Aggiungere più chiavi
oc patch configmap my-config -n my-namespace \ --type merge \ -p '{"data":{"KEY1":"value1","KEY2":"value2"}}'19.3 Rimuovere una chiave
Con JSON patch:
oc patch configmap my-config -n my-namespace \ --type json \ -p='[{"op":"remove","path":"/data/CHIAVE"}]'Se la chiave contiene /, sostituire / con ~1.
20. Patch Secret
20.1 Aggiornare una chiave in un Secret
I valori nei Secret devono essere base64.
echo -n 'nuova-password' | base64 -w0Su macOS:
echo -n 'nuova-password' | base64Patch:
oc patch secret my-secret -n my-namespace \ --type merge \ -p '{"data":{"password":"bnVvdmEtcGFzc3dvcmQ="}}'Metodo più sicuro per generare il payload:
PASSWORD_B64="$(echo -n 'nuova-password' | base64 -w0)"
oc patch secret my-secret -n my-namespace \ --type merge \ -p "{\"data\":{\"password\":\"${PASSWORD_B64}\"}}"21. Patch SecurityContextConstraints
21.1 Aggiungere un ServiceAccount a una SCC
Modo consigliato:
oc adm policy add-scc-to-user <scc-name> -z <serviceaccount> -n <namespace>Esempio:
oc adm policy add-scc-to-user privileged -z my-sa -n my-namespacePatch manuale, da usare con cautela:
oc patch scc privileged \ --type json \ -p='[ { "op": "add", "path": "/users/-", "value": "system:serviceaccount:my-namespace:my-sa" } ]'22. Patch ClusterLogForwarder esempio
Esempio generico per abilitare un campo booleano dentro una CRD:
oc patch clusterlogforwarder collector -n openshift-logging \ --type merge \ -p '{"spec":{"collector":{"someField":true}}}'Per CRD complesse, meglio prima esportare:
oc get clusterlogforwarder collector -n openshift-logging -o yaml > clf-before.yamlModificare un file locale e poi applicare:
oc apply -f clf-before.yamlOppure usare oc edit:
oc edit clusterlogforwarder collector -n openshift-logging23. Patch ArgoCD/OpenShift GitOps
23.1 Abilitare notifications
oc patch argocd openshift-gitops \ -n openshift-gitops \ --type merge \ -p '{"spec":{"notifications":{"enabled":true}}}'Verifica:
oc get argocd openshift-gitops -n openshift-gitops \ -o jsonpath='{.spec.notifications.enabled}{"\n"}'Controlla pod/deployment:
oc get deploy,pod -n openshift-gitops | egrep -i 'notification|argocd'23.2 Disabilitare notifications
oc patch argocd openshift-gitops \ -n openshift-gitops \ --type merge \ -p '{"spec":{"notifications":{"enabled":false}}}'23.3 Abilitare Grafana
oc patch argocd openshift-gitops \ -n openshift-gitops \ --type merge \ -p '{"spec":{"grafana":{"enabled":true}}}'23.4 Abilitare route server
oc patch argocd openshift-gitops \ -n openshift-gitops \ --type merge \ -p '{"spec":{"server":{"route":{"enabled":true}}}}'24. Patch su tutte le risorse di un namespace
24.1 Aggiungere una label a tutti i Deployment del namespace
for d in $(oc get deploy -n my-namespace -o name); do oc label "$d" -n my-namespace managed-by=ops --overwritedone24.2 Patchare tutte le Deployment con una label
oc get deploy -n my-namespace -l app=my-app -o name | while read d; do oc patch "$d" -n my-namespace \ --type merge \ -p '{"spec":{"replicas":2}}'done24.3 Patchare tutti i namespace non di sistema
Esempio: aggiungere una label a namespace applicativi.
oc get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \ | grep -vE '^(openshift-|kube-)' \ | while read ns; do oc label ns "$ns" checked-by=ops --overwrite done25. Dry-run e validazione
25.1 Dry-run server-side
Non sempre disponibile per tutte le operazioni patch, ma utile quando supportato.
oc patch <kind> <name> -n <namespace> \ --type merge \ -p '{"spec":{"campo":"valore"}}' \ --dry-run=server -o yaml25.2 Controllare differenze prima/dopo
Prima:
oc get <kind> <name> -n <namespace> -o yaml > before.yamlPatch:
oc patch <kind> <name> -n <namespace> \ --type merge \ -p '{"spec":{"campo":"valore"}}'Dopo:
oc get <kind> <name> -n <namespace> -o yaml > after.yamlDiff:
diff -u before.yaml after.yamlCon kubectl-neat:
oc get <kind> <name> -n <namespace> -o yaml | kubectl-neat > after-neat.yaml26. Rollback veloce
Se hai salvato il backup YAML:
oc apply -f backup-<kind>-<name>.yamlEsempio:
oc apply -f backup-argocd-openshift-gitops.yamlAttenzione: se la risorsa è gestita da un operator, il rollback manuale può essere a sua volta riconciliato dal controller.
27. Errori comuni
27.1 Invalid JSON
Errore tipico:
invalid character ...Controlla virgolette e apici.
Buona pratica:
cat <<'EOF' > patch.json{ "spec": { "notifications": { "enabled": true } }}EOF
jq . patch.jsonPoi:
oc patch argocd openshift-gitops -n openshift-gitops \ --type merge \ --patch-file patch.json27.2 Campo inesistente con JSON patch replace
replace richiede che il campo esista. Se non esiste, usa add.
oc patch <kind> <name> -n <namespace> \ --type json \ -p='[{"op":"add","path":"/spec/nuovoCampo","value":"valore"}]'27.3 Liste sovrascritte con merge patch
Con --type merge, le liste vengono normalmente sostituite.
Esempio rischioso:
oc patch deployment my-app -n my-namespace \ --type merge \ -p '{"spec":{"template":{"spec":{"tolerations":[...]}}}}'Se vuoi aggiungere un solo elemento senza perdere gli altri, usa --type json con path /-.
27.4 La patch funziona ma poi torna indietro
Probabile risorsa gestita da:
- Operator
- ArgoCD / OpenShift GitOps
- ACM
- Helm
- Kustomize
- altro controller
Controlla:
oc get <kind> <name> -n <namespace> -o json | jq '.metadata.ownerReferences'oc get <kind> <name> -n <namespace> -o json | jq '.metadata.labels, .metadata.annotations'28. Mini cheat sheet finale
Merge patch
oc patch <kind> <name> -n <namespace> \ --type merge \ -p '{"spec":{"campo":"valore"}}'JSON patch replace
oc patch <kind> <name> -n <namespace> \ --type json \ -p='[{"op":"replace","path":"/spec/campo","value":"valore"}]'JSON patch add
oc patch <kind> <name> -n <namespace> \ --type json \ -p='[{"op":"add","path":"/spec/campo","value":"valore"}]'JSON patch remove
oc patch <kind> <name> -n <namespace> \ --type json \ -p='[{"op":"remove","path":"/spec/campo"}]'Verifica campo
oc get <kind> <name> -n <namespace> \ -o jsonpath='{.spec.campo}{"\n"}'Backup
oc get <kind> <name> -n <namespace> -o yaml > backup.yamlRollback
oc apply -f backup.yaml29. Template rapido da riusare
KIND="argocd"NAME="openshift-gitops"NS="openshift-gitops"
oc get "$KIND" "$NAME" -n "$NS" -o yaml > "backup-${KIND}-${NAME}.yaml"
oc patch "$KIND" "$NAME" -n "$NS" \ --type merge \ -p '{"spec":{"notifications":{"enabled":true}}}'
oc get "$KIND" "$NAME" -n "$NS" \ -o jsonpath='{.spec.notifications.enabled}{"\n"}'30. Template con variabili e patch-file
KIND="argocd"NAME="openshift-gitops"NS="openshift-gitops"
cat > patch.json <<'EOF'{ "spec": { "notifications": { "enabled": true } }}EOF
jq . patch.json
oc get "$KIND" "$NAME" -n "$NS" -o yaml > "backup-${KIND}-${NAME}.yaml"
oc patch "$KIND" "$NAME" -n "$NS" \ --type merge \ --patch-file patch.json
oc get "$KIND" "$NAME" -n "$NS" -o yaml | kubectl-neat