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
secretName
in thetls
section 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
HTTPIngressPath
to thePaths
slice within a specific rule, or add a newIngressRule
to theRules
slice.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
resourceVersion
is assigned.If they don't match: This means someone else (or another process) modified the object between the time you performed your
Get
and when you submitted yourUpdate
. The API server rejects your update with an HTTP 409 Conflict error.client-go
'sk8serrors.IsConflict(err)
function will returntrue
in 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
Update
again 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.Update
returns a conflict error (errors.IsConflict
). It uses default backoff settings between retries.Get Latest: Inside the function, the first step is always to
Get
the most current version of the Ingress.Modify In Memory: We find the specific rule for the
targetHost
and append our newHTTPIngressPath
struct to itsHTTP.Paths
slice. 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
Update
using the modifiedcurrentIngress
object.Return Error: The function passed to
RetryOnConflict
must return the error from theUpdate
call.RetryOnConflict
checks if this error is a conflict; if so, it waits and retries the function. If it's another error, or if the update succeeds (nil
error), 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?