Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to patch a deployed Ingress resource on Kubernetes?

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!

like image 582
Kostas Demiris Avatar asked Jun 08 '18 13:06

Kostas Demiris


People also ask

How do I update k8s resources?

You have to download the current version of the resource spec, e.g., using kubectl get -o yaml , edit it, and then use kubectl replace to update the resource using the modified spec. If any changes have occurred between reading and replacing the resource, the replace will fail.

What is patch command in Kubernetes?

With the patch command, Kubernetes performs a merge, merging the JSON provided with the current definition of the deployment/versions object. Go ahead and reload the app in your browser, and then you should notice (after a few seconds) that the new version of the app becomes available.

What happens when an ingress resource is created in Kubernetes?

Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Ingress resource. An Ingress may be configured to give Services externally-reachable URLs, load balance traffic, terminate SSL / TLS, and offer name-based virtual hosting.


1 Answers

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.

like image 147
Janos Lenart Avatar answered Sep 18 '22 11:09

Janos Lenart