Closed mflendrich closed 2 years ago
This can be potentially a big breaking change so we have to be careful when designing a solution.
At present, we loop over ingress rules, and then after loop over paths within rules. The controller composes route names from the namespace, Ingress name, rule index, and path index, in that order. As such, this ruleset:
rules:
- host: first.example
http:
paths:
- backend:
serviceName: first
servicePort: 80
path: /first
pathType: ImplementationSpecific
- host: second.example
http:
paths:
- backend:
serviceName: secondA
servicePort: 80
path: /secondA
pathType: ImplementationSpecific
- backend:
serviceName: secondB
servicePort: 80
path: /secondB
pathType: ImplementationSpecific
results in 3 routes, namespace.ingress.00
(first), namespace.ingress.10
(secondA), and namespace.ingress.11
(secondB).
Prefix-type paths further split into multiple paths: a single /example/
path becomes /example$
and /example/
. This isn't particularly important since the order of those paths is consistent: a Prefix path will just result in two path indexes rather than one, preserving relative order within other paths. For example, if secondA was a Prefix path, we'd get 10
and 11
for it and 12
for secondB.
Hashing components, rather than indexing them, seems the only viable option if we want to make these consistent. Sorting doesn't get us anything, and using the actual values, while consistent, could potentially result in very long route names. adler32 or crc32 should be fine for short, albeit meaningless consistent IDs from the combos. I don't think we have any reason to preserve separation between rule and path without meaningful IDs, so it makes sense to use the second, combined string input. CRC32 is probably the better choice, as our data are short and adler32 deals poorly with that.
Though not directly related to static naming, it's worth noting that this does not match neatly with Kong routes. Kong routes can contain multiple hostnames and paths that all resolve to a single Kong service, whereas Ingresses only map a single hostname and path to a given Service: backends are set at the path level rather than at the Ingress level. Because of this, although we provide a single plugin annotation at the Ingress level, the resulting Kong configuration is a separate plugin configuration for each rule+path combination. This often doesn't matter, but does for some plugins (e.g. rate-limiting-advanced will not share counters between rule+path combinations unless you intentionally set namespace
, and oauth2 won't share sessions unless you set global_credentials
). Unfortunately there's no way to avoid this while maintaining Ingress rule+path->Service mapping.
From discussion of #1003 there are some challenges generating consistent names:
Harry noted that Service APIs will introduce more matching criteria (e.g. methods) in K8S rules down the road. This is partially already true for us, since although such criteria aren't in Ingress rules, konghq.com/methods
and similar add them to all rules in an Ingress. Two Ingress resources with an identical ruleset and different konghq.com/methods
annotations is a valid configuration, though it cannot result in conflicts as long as we somehow include Ingress namespaces and names (we do so already).
As an alternative to deterministically generating names, we can instead deterministically generate IDs, using the same guaranteed unique combination (Ingress namespace and name plus Ingress rule criteria) as input to a UUID5 generator. This strategy actually already exists in Kong's declarative config system, and (to my surprise) resource IDs persist across restarts, even though the config POST does not include them. However, this does rely on the resource primary key (for routes, the name), and if that changes, the ID will also, or rather, an existing ID will point to a new route, since we reuse names for a different set of configuration.
Postgres-backed instances have no such mechanism, and IDs randomize if the database is blown away. If the database persists, IDs persistence depends on deck's lookup strategy.
The PoC for consistent IDs reuses the #1003 inputs, with the addition of an initial input to generate a seed UUID from the namespace+Ingress name combo (recall that we may add further Ingress-wide match criteria via annotations, so we cannot generate the UUID from the Ingress rules alone). This works fine for DB-less mode but presents a challenge for Postgres mode: the deck library lookup and sync will retrieve existing routes whose config satisfies what we want but not overwrite their ID. To use the new scheme, you'll need to perform a database reset.
Closed "won't fix" - we'll implement stable UUIDv5s instead.
It would appear we still need to do some work on this issue, relevant to some conversations in PRs that came up recently:
https://github.com/Kong/kubernetes-ingress-controller/pull/1400#discussion_r649369884
UDPIngress
has opted for resource based prefixing of route names, but we may need to complete the UUID efforts described here before KIC 2.0 Beta.1 in order to avoid adding more technical debt around how route naming is done.
KIC 2.0 works around this for the new UDPIngress type as described above, and we don't have any directly linked bug reports of issues with this in the wild. Since this is fundamentally not a new issue in 2.0 so as such moving this to the POST 2.0 scope.
With the advent of Gateway APIs, we decided to add support for this for the HTTPRoute
API and #2222 adds that plus retroactive support for all others.
This is now declined due to a lack of end-user or customer request and the complexity in implementation.
The route naming scheme we use currently (for v1beta1, v1, tcp and knative ingress) is not stable:
The scope of this issue is to fix the issue identified in the comment above.