Traefik#
If Traefik is the ingress controller of your cluster, nplus offers two ways to publish an instance. Both are fully supported — they differ in what kind of objects the charts create, and therefore in how much of Traefik you can reach from the values.
backend: traefik | provider: traefik | |
|---|---|---|
| Objects | Ingress + a few Middleware | IngressRoute, Middleware, ServersTransport |
| Configured by | annotations on the Ingress | native CRD fields |
| Sticky cookie | annotation, name only | native, incl. maxAge, path, sameSite |
| Body size, timeouts | not available | maxRequestBodyBytes, responseHeaderTimeout |
| CORS, rate limiting | not available | per component |
| Own middlewares | not attachable | ingress.traefik.middlewares |
| Denied paths | routed to the void service | answered with 403 |
| Portable to another controller | yes, it stays an Ingress | no, Traefik only |
Rule of thumb: take the annotations variant if you want to keep the manifests portable and only need the basics. Take the native variant if you actually want to configure Traefik — body limits, timeouts, CORS, rate limiting — or if you want to attach middlewares of your own.
Both variants can be mixed per component: ingress.provider may be overridden on
any single component, and ingress.enabled: false still takes a component out of
the nplus routing completely, so you can route it yourself.
1. Kubernetes Ingress with Traefik annotations#
The classic way: the charts create a standard Ingress object per component and
describe the behavior in Traefik annotations. Switch the backend — the provider
stays ingress:
global:
ingress:
provider: ingress
backend: traefik
class: traefikWhat the charts generate for a component:
traefik.ingress.kubernetes.io/service.serversschemefor the backend protocol- sticky cookie annotations, if
ingress.cookieis set - a
Middlewareper component for those features that have no annotation: theappRootredirect, aninputPath/rewriteTargetrewrite and thewhitelist— bound to the Ingress viarouter.middlewares
Note that these middlewares are created per component: five components with
an appRoot also mean five identical redirect middlewares. Anything Traefik can
do beyond that (body limits, timeouts, CORS, rate limits) is not reachable from
the values here — that is what the native variant is for.
See annotations.yaml.
2. Native Traefik CRDs#
Here the charts skip the Ingress object and write Traefik resources directly:
global:
ingress:
provider: traefik
class: traefikEvery component renders its own IngressRoute — just like it renders its own
Ingress in the other variants, so a single component chart still works on its own.
Traefik merges all IngressRoutes of a namespace into one routing table anyway.
What exists once per instance are the cross cutting middlewares, rendered by the instance chart and referenced by the components by name:
global:
ingress:
appRoot: /nscale_web # redirect middleware + a route for the host root
whitelist: "10.0.0.0/8" # ipAllowList middleware
traefik:
maxRequestBodyBytes: 52428800 # buffering middleware
responseHeaderTimeout: 600s # ServersTransportPer component, a middleware is only created where the content really differs:
cmis:
ingress:
traefik:
cors:
enabled: true
allowOrigins:
- https://apps.example.com
rateLimit:
enabled: true
average: 100
burst: 200
# attach middlewares you created yourself
middlewares:
- name: my-own-middlewareSticky sessions are configured natively on the route service. The cookie name and
sameSite come from the values you already use (ingress.cookie, ingress.sameSite),
everything else is merged in from ingress.traefik.sticky:
web:
ingress:
cookie: XtConLoadBalancerSession
traefik:
sticky:
maxAge: 86400
path: /nscale_webDenied paths (ingress.deny) become their own rules with a blocking middleware and
are answered with 403. Traefik prefers the longer rule, so they always win over
the component route — without depending on the void service.
If the generated routes do not cover a case, append raw routes; they are rendered verbatim into an IngressRoute of their own:
global:
ingress:
traefik:
extraRoutes:
- match: Host(`demo.example.com`) && PathPrefix(`/custom`)
kind: Rule
services:
- name: my-backend
port: 8080See native.yaml.
TLS#
In both variants TLS stays where it always was: the certificate is the one of
ingress.secret (by default <domain>-tls), created by your issuer or by the
chart itself. See the certificates sample.
A component that overrides ingress.domain gets its own host rule and references
its own secret — make sure a matching certificate exists in that case.
Files#
Download all files of this sample
annotations.yaml#
global:
ingress:
# keep the standard Kubernetes Ingress object ...
provider: ingress
# ... but let the chart write Traefik annotations instead of NGINX ones
backend: traefik
class: traefik
# the host root is redirected to the web client by a generated middleware
appRoot: /nscale_web
# rendered as an ipAllowList middleware, not as an annotation
whitelist: "10.0.0.0/8,192.168.0.0/16"
web:
ingress:
# rendered as traefik sticky cookie annotations on the service
cookie: XtConLoadBalancerSession
sameSite: none
nappl:
ingress:
enabled: true
# denied paths are routed to the void service, which has no endpoints
deny:
- /nscalealinst1/webc/configuration
- /nscalealinst1/webb/configurationbuild.sh#
#!/bin/bash
#
# This sample script builds the example as described. It is also used to build the test environment in our lab,
# so it should be well tested.
#
# Make sure it fails immediately, if anything goes wrong
set -e
# -- ENVironment variables:
# CHARTS: The path to the source code
# DEST: The path to the build destination
# SAMPLE: The directory of the sample
# NAME: The name of the sample, used as the .Release.Name
# KUBE_CONTEXT: The name of the kube context, used to build this sample depending on where you run it against. You might have different Environments such as lab, dev, qa, prod, demo, local, ...
# Check, if we have the source code available
if [ ! -d "$CHARTS" ]; then
echo "ERROR Building $SAMPLE example: The Charts Sources folder is not set. Please make sure to run this script with the full Source Code available"
exit 1
fi
if [ ! -d "$DEST" ]; then
echo "ERROR Building $SAMPLE example: DEST folder not found."
exit 1
fi
if [ ! -d "$CHARTS/instance" ]; then
echo "ERROR Building $SAMPLE example: Chart Sources in $CHARTS/instance not found. Are you running this script as a subscriber?"
exit 1
fi
# Set the Variables
SAMPLE="traefik"
NAME="sample-$SAMPLE"
# Output what is happening
echo "Building $NAME"
# Create the manifests - one per variant
mkdir -p $DEST/instance
for VARIANT in annotations native; do
helm template --debug \
--values $SAMPLES/application/empty.yaml \
--values $SAMPLES/environment/$KUBE_CONTEXT.yaml \
--values $SAMPLES/resources/$KUBE_CONTEXT.yaml \
--values $SAMPLES/$SAMPLE/$VARIANT.yaml \
$NAME-$VARIANT $CHARTS/instance > $DEST/instance/$SAMPLE-$VARIANT.yaml
donenative.yaml#
global:
ingress:
# native Traefik CRDs instead of a Kubernetes Ingress object
provider: traefik
class: traefik
appRoot: /nscale_web
traefik:
entryPoints:
- websecure
# one shared buffering middleware for the whole instance (50 MiB)
maxRequestBodyBytes: 52428800
# one shared ServersTransport for the whole instance
responseHeaderTimeout: 600s
web:
ingress:
# the sticky cookie is configured natively on the route service,
# derived from ingress.cookie / ingress.sameSite
cookie: XtConLoadBalancerSession
traefik:
sticky:
maxAge: 86400
cmis:
ingress:
traefik:
# dedicated CORS middleware, only for the cmis route
cors:
enabled: true
allowOrigins:
- https://apps.example.com
nappl:
ingress:
enabled: true
# denied paths are answered with 403 by a blocking middleware
deny:
- /nscalealinst1/webc/configuration
- /nscalealinst1/webb/configuration