Add support for traefik as an ingress#140
Conversation
There was a problem hiding this comment.
3 issues found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="charts/n8n/templates/service-main.yaml">
<violation number="1" location="charts/n8n/templates/service-main.yaml:8">
P2: Traefik backend detection misses the common annotation-based class (`kubernetes.io/ingress.class: traefik`), so sticky-session service annotations may not render for valid Traefik configurations.</violation>
</file>
<file name="charts/n8n/values.yaml">
<violation number="1" location="charts/n8n/values.yaml:159">
P1: Using `className` to conditionally render annotations breaks sticky sessions for users with default or custom NGINX ingress class names.</violation>
<violation number="2" location="charts/n8n/values.yaml:164">
P2: The comment incorrectly claims `cookieMaxAge` is ignored by Traefik, leading to an unimplemented feature.</violation>
</file>
Architecture diagram
sequenceDiagram
participant Client as External Client
participant TE as Traefik Ingress
participant NE as Nginx Ingress
participant Svc as n8n Service
participant Pod as n8n Pod
Note over Client,Pod: Ingress Selection Flow (values.yaml: ingress.className)
alt Traefik Ingress Selected
Client->>TE: Request to n8n
TE->>Svc: Route request
Note over Svc: Service annotations include:<br/>traefik.ingress.kubernetes.io/service.sticky.cookie=true
Svc->>Pod: Forward to pod (sticky session via cookie)
Pod-->>Svc: Response
Svc-->>TE: Response with Set-Cookie
TE-->>Client: Response + sticky cookie
else Nginx Ingress Selected (default/backward compatible)
Client->>NE: Request to n8n
Note over NE: Ingress annotations include:<br/>nginx.ingress.kubernetes.io/affinity: cookie
NE->>Svc: Route request with cookie affinity
Note over Svc: No Traefik annotations added
Svc->>Pod: Forward to pod (sticky session)
Pod-->>Svc: Response
Svc-->>NE: Response with Set-Cookie
NE-->>Client: Response + sticky cookie
end
Note over Svc: Key configuration decisions:<br/>- sticky.enabled controls both ingress types<br/>- cookieName shared between Traefik/nginx<br/>- cookieExpires/cookieMaxAge only for nginx<br/>- cookieSecure applies only to Traefik
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| # ----- Ingress ----- | ||
| ingress: | ||
| enabled: false | ||
| className: "" # supported types are "traefik" & "nginx", "traefik" is suggested as nginx-ingress is deprecated |
There was a problem hiding this comment.
P1: Using className to conditionally render annotations breaks sticky sessions for users with default or custom NGINX ingress class names.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At charts/n8n/values.yaml, line 159:
<comment>Using `className` to conditionally render annotations breaks sticky sessions for users with default or custom NGINX ingress class names.</comment>
<file context>
@@ -156,9 +156,12 @@ service:
# ----- Ingress -----
ingress:
enabled: false
+ className: "" # supported types are "traefik" & "nginx", "traefik" is suggested as nginx-ingress is deprecated
sticky:
enabled: false
</file context>
There was a problem hiding this comment.
This is the default configuration as it existed originally
There was a problem hiding this comment.
Yes, agreed. Users with a custom class name like "nginx-internal", etc. would have had the same behavior before this PR change.
| namespace: {{ .Release.Namespace }} | ||
| labels: | ||
| {{- include "n8n.labels" . | nindent 4 }} | ||
| {{- $isTraefik := and .Values.ingress.enabled .Values.ingress.sticky.enabled (or (eq .Values.ingress.className "traefik") (hasKey (default dict .Values.ingress.annotations) "traefik.ingress.kubernetes.io/router.entrypoints")) }} |
There was a problem hiding this comment.
P2: Traefik backend detection misses the common annotation-based class (kubernetes.io/ingress.class: traefik), so sticky-session service annotations may not render for valid Traefik configurations.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At charts/n8n/templates/service-main.yaml, line 8:
<comment>Traefik backend detection misses the common annotation-based class (`kubernetes.io/ingress.class: traefik`), so sticky-session service annotations may not render for valid Traefik configurations.</comment>
<file context>
@@ -5,7 +5,14 @@ metadata:
namespace: {{ .Release.Namespace }}
labels:
{{- include "n8n.labels" . | nindent 4 }}
+ {{- $isTraefik := and .Values.ingress.enabled .Values.ingress.sticky.enabled (or (eq .Values.ingress.className "traefik") (hasKey (default dict .Values.ingress.annotations) "traefik.ingress.kubernetes.io/router.entrypoints")) }}
{{- $merged := merge (deepCopy (.Values.service.main.annotations | default dict)) (.Values.service.annotations | default dict) }}
+ {{- if $isTraefik }}
</file context>
| {{- $isTraefik := and .Values.ingress.enabled .Values.ingress.sticky.enabled (or (eq .Values.ingress.className "traefik") (hasKey (default dict .Values.ingress.annotations) "traefik.ingress.kubernetes.io/router.entrypoints")) }} | |
| {{- $isTraefik := and .Values.ingress.enabled .Values.ingress.sticky.enabled (or (eq .Values.ingress.className "traefik") (and (hasKey (default dict .Values.ingress.annotations) "kubernetes.io/ingress.class") (eq (get (default dict .Values.ingress.annotations) "kubernetes.io/ingress.class") "traefik")) (hasKey (default dict .Values.ingress.annotations) "traefik.ingress.kubernetes.io/router.entrypoints")) }} |
There was a problem hiding this comment.
Sticky-service annotations did appear during testing.
| enabled: false | ||
| cookieName: n8n_affinity | ||
| cookieSecure: true # set to false when using plain HTTP (e.g. local minikube) | ||
| # cookieExpires and cookieMaxAge are nginx-only, these are ignored by traefik |
There was a problem hiding this comment.
P2: The comment incorrectly claims cookieMaxAge is ignored by Traefik, leading to an unimplemented feature.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At charts/n8n/values.yaml, line 164:
<comment>The comment incorrectly claims `cookieMaxAge` is ignored by Traefik, leading to an unimplemented feature.</comment>
<file context>
@@ -156,9 +156,12 @@ service:
enabled: false
cookieName: n8n_affinity
+ cookieSecure: true # set to false when using plain HTTP (e.g. local minikube)
+ # cookieExpires and cookieMaxAge are nginx-only, these are ignored by traefik
cookieExpires: "172800" # 2 days in seconds
cookieMaxAge: "172800" # 2 days in seconds
</file context>
There was a problem hiding this comment.
This is correct according to testing, these settings were ignored.
| {{- $_ := set $merged "traefik.ingress.kubernetes.io/service.sticky.cookie.name" .Values.ingress.sticky.cookieName }} | ||
| {{- $_ := set $merged "traefik.ingress.kubernetes.io/service.sticky.cookie.secure" (.Values.ingress.sticky.cookieSecure | toString) }} | ||
| {{- $_ := set $merged "traefik.ingress.kubernetes.io/service.sticky.cookie.httponly" "true" }} | ||
| {{- end }} |
There was a problem hiding this comment.
| {{- end }} | |
| {{- $_ := set $merged "traefik.ingress.kubernetes.io/service.sticky.cookie.maxage" (.Values.ingress.sticky.cookieMaxAge | toString) }} | |
| {{- end }} |
| enabled: false | ||
| cookieName: n8n_affinity | ||
| cookieSecure: true # set to false when using plain HTTP (e.g. local minikube) | ||
| # cookieExpires and cookieMaxAge are nginx-only, these are ignored by traefik |
There was a problem hiding this comment.
| # cookieExpires and cookieMaxAge are nginx-only, these are ignored by traefik | |
| # cookieExpires is nginx-only and ignored by traefik |
I think what the bot wants to say is that the statement is not fully correct. cookieExpires is not support by Traefik, but cookieMaxAge is indeed supported.
| namespace: {{ .Release.Namespace }} | ||
| labels: | ||
| {{- include "n8n.labels" . | nindent 4 }} | ||
| {{- $isTraefik := and .Values.ingress.enabled .Values.ingress.sticky.enabled (or (eq .Values.ingress.className "traefik") (hasKey (default dict .Values.ingress.annotations) "traefik.ingress.kubernetes.io/router.entrypoints")) }} |
There was a problem hiding this comment.
| {{- $isTraefik := and .Values.ingress.enabled .Values.ingress.sticky.enabled (or (eq .Values.ingress.className "traefik") (hasKey (default dict .Values.ingress.annotations) "traefik.ingress.kubernetes.io/router.entrypoints")) }} | |
| {{- $ingressAnnotations := default dict .Values.ingress.annotations }} | |
| {{- $legacyClass := index $ingressAnnotations "kubernetes.io/ingress.class" }} | |
| {{- $isTraefik := and .Values.ingress.enabled .Values.ingress.sticky.enabled (or (eq .Values.ingress.className "traefik") (eq $legacyClass "traefik") (hasKey $ingressAnnotations "traefik.ingress.kubernetes.io/router.entrypoints")) }} |
I think this actually a valid finding. The previous check only looked for the existence of kubernetes.io/ingress.class, so a user with kubernetes.io/ingress.class: traefik would have incorrectly gotten Nginx annotations rendered on their Ingress.
| {{- if .Values.ingress.sticky.enabled }} | ||
| {{- $isNginx := or (eq .Values.ingress.className "nginx") (hasKey (default dict .Values.ingress.annotations) "kubernetes.io/ingress.class") }} | ||
| {{- if $isNginx }} |
There was a problem hiding this comment.
| {{- if .Values.ingress.sticky.enabled }} | |
| {{- $isNginx := or (eq .Values.ingress.className "nginx") (hasKey (default dict .Values.ingress.annotations) "kubernetes.io/ingress.class") }} | |
| {{- if $isNginx }} | |
| {{- if .Values.ingress.sticky.enabled }} | |
| {{- $legacyClass := index (default dict .Values.ingress.annotations) "kubernetes.io/ingress.class" }} | |
| {{- $isNginx := or (eq .Values.ingress.className "nginx") (eq $legacyClass "nginx") }} | |
| {{- if $isNginx }} |
Pull Request
Description
As announced on November 11, 2025, Kubernetes has deprecated the Nginx ingress. To account for this change, this PR adds support for using Traefik instead.
Type of Change
Related Issues
Fixes # (issue)
Relates to # (issue)
Changes Made
Testing Performed
Chart Validation
helm lint charts/n8npasses./scripts/validate-examples.shpassesDeployment Testing (if applicable)
Specific Testing for Changes
Describe any specific testing you performed for your changes:
Breaking Changes
If this includes breaking changes, describe what they are and provide migration instructions:
Documentation Updates
Checklist
Screenshots (if applicable)
Add screenshots to help explain your changes.
Additional Notes
Any additional information that reviewers should know.