Updating Ingress Resources
Creating an Ingress resource is just the first step. Applications evolve, routing needs change, and TLS certificates get renewed. Therefore, knowing how to update existing Ingress resources programmatically is just as important as creating them.
Common reasons to update an Ingress resource include:
Adding a new path rule to route traffic for a new feature or microservice.
Changing the backend Service for an existing path (e.g., during a blue-green deployment).
Adding or modifying host rules.
Updating the
secretNamein thetlssection when a certificate is renewed.Modifying annotations to change the behavior of the Ingress Controller.
Removing obsolete rules or hosts.
The Get-Modify-Update Pattern
You cannot directly modify just a part of an existing Kubernetes resource via a simple API call (except through Patch, which is more complex). The standard pattern for updating resources using client-go's typed clients (like the Ingress client) is:
Get: Retrieve the current version of the Ingress resource from the API server using
ingressClient.Get(...).Modify: Make the desired changes to the Go struct object you received in memory. For example, append a new
HTTPIngressPathto thePathsslice within a specific rule, or add a newIngressRuleto theRulesslice.Update: Call
ingressClient.Update(...), passing the entire modified Go struct.
Crucial Concept: Optimistic Concurrency and resourceVersion
Kubernetes uses a mechanism called optimistic concurrency control to prevent conflicting updates. Every Kubernetes object has a metadata.resourceVersion field. This field is updated by the API server every time the object is changed.
When you call Update, the API server compares the resourceVersion of the object you're submitting with the resourceVersion of the object currently stored in etcd (the cluster's database).
If they match: The update is allowed, the object is changed, and a new
resourceVersionis assigned.If they don't match: This means someone else (or another process) modified the object between the time you performed your
Getand when you submitted yourUpdate. The API server rejects your update with an HTTP 409 Conflict error.client-go'sk8serrors.IsConflict(err)function will returntruein this case.
Handling Conflicts:
The standard way to handle a conflict error during an update is to:
Catch the conflict error (
k8serrors.IsConflict).Re-Get: Fetch the latest version of the resource from the API server again.
Re-Apply Changes: Apply your intended modifications to this newly fetched object. (This might require some care if the conflicting change affected the part you wanted to modify).
Retry Update: Call
Updateagain with the re-modified object.
This process might need to be repeated a few times if conflicts are frequent. Libraries like k8s.io/client-go/util/retry provide helpers (like retry.RetryOnConflict) to automate this retry loop.
Example: Adding a Path Rule to an Existing Ingress
Let's extend our previous example. Assume the Ingress example-ingress already exists (created in the previous step). We now want to add a new path rule under the app.example.com host to route /admin traffic to an admin-service on port 8888.
Explanation:
retry.RetryOnConflict: We wrap the Get-Modify-Update logic inside this helper function. It automatically retries the inner function ifingressClient.Updatereturns a conflict error (errors.IsConflict). It uses default backoff settings between retries.Get Latest: Inside the function, the first step is always to
Getthe most current version of the Ingress.Modify In Memory: We find the specific rule for the
targetHostand append our newHTTPIngressPathstruct to itsHTTP.Pathsslice. We added a check to avoid adding duplicates. (More complex logic would be needed to add a new host rule if it didn't exist).Call Update: We attempt the
Updateusing the modifiedcurrentIngressobject.Return Error: The function passed to
RetryOnConflictmust return the error from theUpdatecall.RetryOnConflictchecks if this error is a conflict; if so, it waits and retries the function. If it's another error, or if the update succeeds (nilerror), the retry loop stops.
Patch vs Update:
While Update replaces the entire object, Kubernetes also supports Patch operations (JSON Patch, Strategic Merge Patch, Server-Side Apply) for partial updates. Patching can be more efficient network-wise and less prone to certain types of conflicts, but constructing the patch requests can be more complex than modifying the Go struct for Update. For many common modifications like adding items to lists within the spec, the Get-Modify-Update pattern with RetryOnConflict is a robust and widely used approach.
Mastering the Get-Modify-Update pattern (especially with conflict handling) is essential for building reliable Go applications that manage the lifecycle of Kubernetes resources like Ingress.
Last updated
Was this helpful?