I have the following Ingress resource:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: main-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
nginx.ingress.kubernetes.io/proxy-read-timeout: "86400"
nginx.ingress.kubernetes.io/proxy-send-timeout: "86400"
spec:
tls:
- secretName: the-secret
hosts:
- sample.domain.com
- sample2.domain.com
- rabbit.domain.com
- hub.domain.com
- grafana.domain.com
rules:
- host: sample.domain.com
http:
paths:
- path: /
backend:
serviceName: fe-srvc
servicePort: 80
- path: /api
backend:
serviceName: be-srvc
servicePort: 80
- host: sample2.domain.com
http:
paths:
- path: /
backend:
serviceName: fe2-srvc
servicePort: 80
- path: /api
backend:
serviceName: be-srvc
servicePort: 80
## The Extra Services ###
- host: rabbit.domain.com
http:
paths:
- path: /
backend:
serviceName: rabbitmq-srvc
servicePort: 80
and I want to patch it after it is deployed.
So I use this, to try and replace the be-srvc
value with some-srvc
:
kubectl patch ing/main-ingress --patch '{ "spec" : { "rules": [{"http":{"paths":[ {"- path":"/"},{"backend":{"serviceName":"other-srvc"}},{"servicePort":"80"} ] }}]}}'
and I get this error:
The Ingress "main-ingress" is invalid:
* spec.rules[0].http.backend.serviceName: Required value
* spec.rules[0].http.backend.servicePort: Invalid value: 0: must be between 1 and 65535, inclusive
Any insight would be appreciated!
Your patch has a number of problems; for example "- path"
instead of "path"
but also incorrect referencing of object levels. However, even if you fixed the mistakes this would not work as intended. Let's see why.
kubectl patch
is a request for a strategic merge patch. When patching arrays, like the .spec.rules
and .spec.rules.http.paths
in this case, a strategic merge patch can use the defined patch type and merge patch merge key for the object to do The Right Thing. However, in case of the Ingress object no one bothered to define these. This means that any patch will overwrite the entire object; it will not be a nice merge that one is hoping for.
To accomplish the particular change referred to in the question you can do:
kubectl get ing/main-ingress -o json \
| jq '(.spec.rules[].http.paths[].backend.serviceName | select(. == "be-srvc")) |= "some-srvc"' \
| kubectl apply -f -
The above will change all occurrences of the be-srvc
Service to some-srvc
. Keep in mind that there is a short race condition here: if the Ingress is modified after kubectl get
ran the change will fail with the error Operation cannot be fulfilled on ingresses.extensions "xx": the object has been modified
; to handle that case you need implement a retry logic.
If the indexes are known in the arrays mentioned above you can accomplish the patch directly:
kubectl patch ing/main-ingress --type=json \
-p='[{"op": "replace", "path": "/spec/rules/0/http/paths/1/backend/serviceName", "value":"some-srvc"}]'
kubectl patch ing/main-ingress --type=json \
-p='[{"op": "replace", "path": "/spec/rules/1/http/paths/1/backend/serviceName", "value":"some-srvc"}]'
The two commands above will change the backends for sample.domain.com/api
and sample2.domain.com/api
to some-srvc
.
The two commands can also be combined like this:
kubectl patch ing/main-ingress --type=json \
-p='[{"op": "replace", "path": "/spec/rules/0/http/paths/1/backend/serviceName", "value":"some-srvc"}, {"op": "replace", "path": "/spec/rules/1/http/paths/1/backend/serviceName", "value":"some-srvc"}]'
This has the same effect and as an added bonus there is no race condition here; the patch guaranteed to be atomic.