# Install as a DaemonSet Default install is using a `Deployment` but it's possible to use `DaemonSet` ```yaml deployment: kind: DaemonSet ``` # Configure traefik Pod parameters ## Extending /etc/hosts records In some specific cases, you'll need to add extra records to the `/etc/hosts` file for the Traefik containers. You can configure it using [hostAliases](https://kubernetes.io/docs/tasks/network/customize-hosts-file-for-pods/): ```yaml deployment: hostAliases: - ip: "127.0.0.1" # this is an example hostnames: - "foo.local" - "bar.local" ``` ## Extending DNS config In order to configure additional DNS servers for your traefik pod, you can use `dnsConfig` option: ```yaml deployment: dnsConfig: nameservers: - 192.0.2.1 # this is an example searches: - ns1.svc.cluster-domain.example - my.dns.search.suffix options: - name: ndots value: "2" - name: edns0 ``` # Install in a dedicated namespace, with limited RBAC Default install is using Cluster-wide RBAC but it can be restricted to target namespace. ```yaml rbac: namespaced: true ``` # Install with auto-scaling When enabling [HPA](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) to adjust replicas count according to CPU Usage, you'll need to set resources and nullify replicas. ```yaml deployment: replicas: null resources: requests: cpu: "100m" memory: "50Mi" limits: cpu: "300m" memory: "150Mi" autoscaling: enabled: true maxReplicas: 2 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 80 ``` # Access Traefik dashboard without exposing it This Chart does not expose the Traefik local dashboard by default. It's explained in upstream [documentation](https://doc.traefik.io/traefik/operations/api/) why: > Enabling the API in production is not recommended, because it will expose all configuration elements, including sensitive data. It says also: > In production, it should be at least secured by authentication and authorizations. Thus, there are multiple ways to expose the dashboard. For instance, after enabling the creation of dashboard `IngressRoute` in the values: ```yaml ingressRoute: dashboard: enabled: true ``` The traefik admin port can be forwarded locally: ```bash kubectl port-forward $(kubectl get pods --selector "app.kubernetes.io/name=traefik" --output=name) 8080:8080 ``` This command makes the dashboard accessible on the url: http://127.0.0.1:8080/dashboard/ # Publish and protect Traefik Dashboard with basic Auth To expose the dashboard in a secure way as [recommended](https://doc.traefik.io/traefik/operations/dashboard/#dashboard-router-rule) in the documentation, it may be useful to override the router rule to specify a domain to match, or accept requests on the root path (/) in order to redirect them to /dashboard/. ```yaml # Create an IngressRoute for the dashboard ingressRoute: dashboard: enabled: true # Custom match rule with host domain matchRule: Host(`traefik-dashboard.example.com`) entryPoints: ["websecure"] # Add custom middlewares : authentication and redirection middlewares: - name: traefik-dashboard-auth # Create the custom middlewares used by the IngressRoute dashboard (can also be created in another way). # /!\ Yes, you need to replace "changeme" password with a better one. /!\ extraObjects: - apiVersion: v1 kind: Secret metadata: name: traefik-dashboard-auth-secret type: kubernetes.io/basic-auth stringData: username: admin password: changeme - apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: traefik-dashboard-auth spec: basicAuth: secret: traefik-dashboard-auth-secret ``` # Publish and protect Traefik Dashboard with an Ingress To expose the dashboard without IngressRoute, it's more complicated and less secure. You'll need to create an internal Service exposing Traefik API with special _traefik_ entrypoint. This internal Service can be created from an other tool, with the `extraObjects` section or using [custom services](#add-custom-internal-services). You'll need to double check: 1. Service selector with your setup. 2. Middleware annotation on the ingress, _default_ should be replaced with traefik's namespace ```yaml ingressRoute: dashboard: enabled: false additionalArguments: - "--api.insecure=true" # Create the service, middleware and Ingress used to expose the dashboard (can also be created in another way). # /!\ Yes, you need to replace "changeme" password with a better one. /!\ extraObjects: - apiVersion: v1 kind: Service metadata: name: traefik-api spec: type: ClusterIP selector: app.kubernetes.io/name: traefik app.kubernetes.io/instance: traefik-default ports: - port: 8080 name: traefik targetPort: 8080 protocol: TCP - apiVersion: v1 kind: Secret metadata: name: traefik-dashboard-auth-secret type: kubernetes.io/basic-auth stringData: username: admin password: changeme - apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: traefik-dashboard-auth spec: basicAuth: secret: traefik-dashboard-auth-secret - apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: traefik-dashboard annotations: traefik.ingress.kubernetes.io/router.entrypoints: websecure traefik.ingress.kubernetes.io/router.middlewares: default-traefik-dashboard-auth@kubernetescrd spec: rules: - host: traefik-dashboard.example.com http: paths: - path: / pathType: Prefix backend: service: name: traefik-api port: name: traefik ``` # Install on AWS It can use [native AWS support](https://kubernetes.io/docs/concepts/services-networking/service/#aws-nlb-support) on Kubernetes ```yaml service: annotations: service.beta.kubernetes.io/aws-load-balancer-type: nlb ``` Or if [AWS LB controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/service/annotations/#legacy-cloud-provider) is installed : ```yaml service: annotations: service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip ``` # Install on GCP A [regional IP with a Service](https://cloud.google.com/kubernetes-engine/docs/tutorials/configuring-domain-name-static-ip#use_a_service) can be used ```yaml service: spec: loadBalancerIP: "1.2.3.4" ``` Or a [global IP on Ingress](https://cloud.google.com/kubernetes-engine/docs/tutorials/configuring-domain-name-static-ip#use_an_ingress) ```yaml service: type: NodePort extraObjects: - apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: traefik annotations: kubernetes.io/ingress.global-static-ip-name: "myGlobalIpName" spec: defaultBackend: service: name: traefik port: number: 80 ``` Or a [global IP on a Gateway](https://cloud.google.com/kubernetes-engine/docs/how-to/deploying-gateways) with continuous HTTPS encryption. ```yaml ports: websecure: appProtocol: HTTPS # Hint for Google L7 load balancer service: type: ClusterIP extraObjects: - apiVersion: gateway.networking.k8s.io/v1beta1 kind: Gateway metadata: name: traefik annotations: networking.gke.io/certmap: "myCertificateMap" spec: gatewayClassName: gke-l7-global-external-managed addresses: - type: NamedAddress value: "myGlobalIPName" listeners: - name: https protocol: HTTPS port: 443 - apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: traefik spec: parentRefs: - kind: Gateway name: traefik rules: - backendRefs: - name: traefik port: 443 - apiVersion: networking.gke.io/v1 kind: HealthCheckPolicy metadata: name: traefik spec: default: config: type: HTTP httpHealthCheck: port: 8080 requestPath: /ping targetRef: group: "" kind: Service name: traefik ``` # Install on Azure A [static IP on a resource group](https://learn.microsoft.com/en-us/azure/aks/static-ip) can be used: ```yaml service: spec: loadBalancerIP: "1.2.3.4" annotations: service.beta.kubernetes.io/azure-load-balancer-resource-group: myResourceGroup ``` Here is a more complete example, using also native Let's encrypt feature of Traefik Proxy with Azure DNS: ```yaml persistence: enabled: true size: 128Mi certificatesResolvers: letsencrypt: acme: email: "{{ letsencrypt_email }}" #caServer: https://acme-v02.api.letsencrypt.org/directory # Production server caServer: https://acme-staging-v02.api.letsencrypt.org/directory # Staging server dnsChallenge: provider: azuredns storage: /data/acme.json env: - name: AZURE_CLIENT_ID value: "{{ azure_dns_challenge_application_id }}" - name: AZURE_CLIENT_SECRET valueFrom: secretKeyRef: name: azuredns-secret key: client-secret - name: AZURE_SUBSCRIPTION_ID value: "{{ azure_subscription_id }}" - name: AZURE_TENANT_ID value: "{{ azure_tenant_id }}" - name: AZURE_RESOURCE_GROUP value: "{{ azure_resource_group }}" deployment: initContainers: - name: volume-permissions image: busybox:latest command: ["sh", "-c", "ls -la /; touch /data/acme.json; chmod -v 600 /data/acme.json"] volumeMounts: - mountPath: /data name: data podSecurityContext: fsGroup: 65532 fsGroupChangePolicy: "OnRootMismatch" service: spec: type: LoadBalancer annotations: service.beta.kubernetes.io/azure-load-balancer-resource-group: "{{ azure_node_resource_group }}" service.beta.kubernetes.io/azure-pip-name: "{{ azure_resource_group }}" service.beta.kubernetes.io/azure-dns-label-name: "{{ azure_resource_group }}" service.beta.kubernetes.io/azure-allowed-ip-ranges: "{{ ip_range | join(',') }}" extraObjects: - apiVersion: v1 kind: Secret metadata: name: azuredns-secret namespace: traefik type: Opaque stringData: client-secret: "{{ azure_dns_challenge_application_secret }}" ``` # Use an IngressClass Default install comes with an `IngressClass` resource that can be enabled on providers. Here's how one can enable it on CRD & Ingress Kubernetes provider: ```yaml ingressClass: name: traefik providers: kubernetesCRD: ingressClass: traefik kubernetesIngress: ingressClass: traefik ``` # Use HTTP3 By default, it will use a Load balancers with mixed protocols on `websecure` entrypoint. They are available since v1.20 and in beta as of Kubernetes v1.24. Availability may depend on your Kubernetes provider. When using TCP and UDP with a single service, you may encounter [this issue](https://github.com/kubernetes/kubernetes/issues/47249#issuecomment-587960741) from Kubernetes. If you want to avoid this issue, you can set `ports.websecure.http3.advertisedPort` to an other value than 443 ```yaml ports: websecure: http3: enabled: true ``` You can also create two `Service`, one for TCP and one for UDP: ```yaml ports: websecure: http3: enabled: true service: single: false ``` # Use PROXY protocol on Digital Ocean PROXY protocol is a protocol for sending client connection information, such as origin IP addresses and port numbers, to the final backend server, rather than discarding it at the load balancer. ```yaml .DOTrustedIPs: &DOTrustedIPs - 127.0.0.1/32 - 10.120.0.0/16 service: enabled: true type: LoadBalancer annotations: # This will tell DigitalOcean to enable the proxy protocol. service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: "true" spec: # This is the default and should stay as cluster to keep the DO health checks working. externalTrafficPolicy: Cluster ports: web: forwardedHeaders: trustedIPs: *DOTrustedIPs proxyProtocol: trustedIPs: *DOTrustedIPs websecure: forwardedHeaders: trustedIPs: *DOTrustedIPs proxyProtocol: trustedIPs: *DOTrustedIPs ``` # Enable plugin storage This chart follows common security practices: it runs as non root with a readonly root filesystem. When enabling a plugin which needs storage, you have to add it to the deployment. Here is a simple example with crowdsec. You may want to replace with your plugin or see complete exemple on crowdsec [here](https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/blob/main/examples/kubernetes/README.md). ```yaml deployment: additionalVolumes: - name: plugins additionalVolumeMounts: - name: plugins mountPath: /plugins-storage additionalArguments: - "--experimental.plugins.bouncer.moduleName=github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin" - "--experimental.plugins.bouncer.version=v1.1.9" ``` # Use Traefik native Let's Encrypt integration, without cert-manager In Traefik Proxy, ACME certificates are stored in a JSON file. This file needs to have 0600 permissions, meaning, only the owner of the file has full read and write access to it. By default, Kubernetes recursively changes ownership and permissions for the content of each volume. => An initContainer can be used to avoid an issue on this sensitive file. See [#396](https://github.com/traefik/traefik-helm-chart/issues/396) for more details. Once the provider is ready, it can be used in an `IngressRoute`: ```yaml apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: [...] spec: entryPoints: [...] routes: [...] tls: certResolver: letsencrypt ``` :information_source: Change `apiVersion` to `traefik.containo.us/v1alpha1` for charts prior to v28.0.0 See [the list of supported providers](https://doc.traefik.io/traefik/https/acme/#providers) for others. ## Example with CloudFlare This example needs a CloudFlare token in a Kubernetes `Secret` and a working `StorageClass`. **Step 1**: Create `Secret` with CloudFlare token: ```yaml --- apiVersion: v1 kind: Secret metadata: name: cloudflare type: Opaque stringData: token: {{ SET_A_VALID_TOKEN_HERE }} ``` **Step 2**: ```yaml persistence: enabled: true storageClass: xxx certificatesResolvers: letsencrypt: acme: dnsChallenge: provider: cloudflare storage: /data/acme.json env: - name: CF_DNS_API_TOKEN valueFrom: secretKeyRef: name: cloudflare key: token deployment: initContainers: - name: volume-permissions image: busybox:latest command: ["sh", "-c", "touch /data/acme.json; chmod -v 600 /data/acme.json"] volumeMounts: - mountPath: /data name: data podSecurityContext: fsGroup: 65532 fsGroupChangePolicy: "OnRootMismatch" ``` >[!NOTE] > With [Traefik Hub](https://traefik.io/traefik-hub/), certificates can be stored as a `Secret` on Kubernetes with `distributedAcme` resolver. # Provide default certificate with cert-manager and CloudFlare DNS Setup: * cert-manager installed in `cert-manager` namespace * A cloudflare account on a DNS Zone **Step 1**: Create `Secret` and `Issuer` needed by `cert-manager` with your API Token. See [cert-manager documentation](https://cert-manager.io/docs/configuration/acme/dns01/cloudflare/) for creating this token with needed rights: ```yaml --- apiVersion: v1 kind: Secret metadata: name: cloudflare namespace: traefik type: Opaque stringData: api-token: XXX --- apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: cloudflare namespace: traefik spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: email@example.com privateKeySecretRef: name: cloudflare-key solvers: - dns01: cloudflare: apiTokenSecretRef: name: cloudflare key: api-token ``` **Step 2**: Create `Certificate` in traefik namespace ```yaml apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: wildcard-example-com namespace: traefik spec: secretName: wildcard-example-com-tls dnsNames: - "example.com" - "*.example.com" issuerRef: name: cloudflare kind: Issuer ``` **Step 3**: Check that it's ready ```bash kubectl get certificate -n traefik ``` If needed, logs of cert-manager pod can give you more information **Step 4**: Use it on the TLS Store in **values.yaml** file for this Helm Chart ```yaml tlsStore: default: defaultCertificate: secretName: wildcard-example-com-tls ``` **Step 5**: Enjoy. All your `IngressRoute` use this certificate by default now. They should use websecure entrypoint like this: ```yaml apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: example-com-tls spec: entryPoints: - websecure routes: - match: Host(`test.example.com`) kind: Rule services: - name: XXXX port: 80 ``` # Add custom (internal) services In some cases you might want to have more than one Traefik service within your cluster, e.g. a default (external) one and a service that is only exposed internally to pods within your cluster. The `service.additionalServices` allows you to add an arbitrary amount of services, provided as a name to service details mapping; for example you can use the following values: ```yaml service: additionalServices: internal: type: ClusterIP labels: traefik-service-label: internal ``` Ports can then be exposed on this service by using the port name to boolean mapping `expose` on the respective port; e.g. to expose the `traefik` API port on your internal service so pods within your cluster can use it, you can do: ```yaml ports: traefik: expose: # Sensitive data should not be exposed on the internet # => Keep this disabled ! default: false internal: true ``` This will then provide an additional Service manifest, looking like this: ```yaml --- # Source: traefik/templates/service.yaml apiVersion: v1 kind: Service metadata: name: traefik-internal namespace: traefik [...] spec: type: ClusterIP selector: app.kubernetes.io/name: traefik app.kubernetes.io/instance: traefik-traefik ports: - port: 8080 name: "traefik" targetPort: traefik protocol: TCP ``` # Use this Chart as a dependency of your own chart First, let's create a default Helm Chart, with Traefik as a dependency. ```bash helm create foo cd foo echo " dependencies: - name: traefik version: "24.0.0" repository: "https://traefik.github.io/charts" " >> Chart.yaml ``` Second, let's tune some values like enabling HPA: ```bash cat <<-EOF >> values.yaml traefik: autoscaling: enabled: true maxReplicas: 3 EOF ``` Third, one can see if it works as expected: ```bash helm dependency update helm dependency build helm template . | grep -A 14 -B 3 Horizontal ``` It should produce this output: ```yaml --- # Source: foo/charts/traefik/templates/hpa.yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: release-name-traefik namespace: flux-system labels: app.kubernetes.io/name: traefik app.kubernetes.io/instance: release-name-flux-system helm.sh/chart: traefik-24.0.0 app.kubernetes.io/managed-by: Helm spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: release-name-traefik maxReplicas: 3 ``` # Configure TLS The [TLS options](https://doc.traefik.io/traefik/https/tls/#tls-options) allow one to configure some parameters of the TLS connection. ```yaml tlsOptions: default: labels: {} sniStrict: true custom-options: labels: {} curvePreferences: - CurveP521 - CurveP384 ``` # Use latest build of Traefik v3 from master An experimental build of Traefik Proxy is available on a specific repository. It can be used with those _values_: ```yaml image: repository: traefik/traefik tag: experimental-v3.0 ``` # Use Prometheus Operator An optional support of this operator is included in this Chart. See documentation of this operator for more details. It can be used with those _values_: ```yaml metrics: prometheus: service: enabled: true disableAPICheck: false serviceMonitor: enabled: true metricRelabelings: - sourceLabels: [__name__] separator: ; regex: ^fluentd_output_status_buffer_(oldest|newest)_.+ replacement: $1 action: drop relabelings: - sourceLabels: [__meta_kubernetes_pod_node_name] separator: ; regex: ^(.*)$ targetLabel: nodename replacement: $1 action: replace jobLabel: traefik interval: 30s honorLabels: true prometheusRule: enabled: true rules: - alert: TraefikDown expr: up{job="traefik"} == 0 for: 5m labels: context: traefik severity: warning annotations: summary: "Traefik Down" description: "{{ $labels.pod }} on {{ $labels.nodename }} is down" ``` # Use kubernetes Gateway API One can use the new stable kubernetes gateway API provider setting the following _values_: ```yaml providers: kubernetesGateway: enabled: true ```
With those values, a whoami service can be exposed with a HTTPRoute ```yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: whoami spec: replicas: 2 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami --- apiVersion: v1 kind: Service metadata: name: whoami spec: selector: app: whoami ports: - protocol: TCP port: 80 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami spec: parentRefs: - name: traefik-gateway hostnames: - whoami.docker.localhost rules: - matches: - path: type: Exact value: / backendRefs: - name: whoami port: 80 weight: 1 ``` Once it's applied, whoami should be accessible on http://whoami.docker.localhost/
:information_source: In this example, `Deployment` and `HTTPRoute` should be deployed in the same namespace as the Traefik Gateway: Chart namespace. # Use Kubernetes Gateway API with cert-manager One can use the new stable kubernetes gateway API provider with automatic TLS certificates delivery (with cert-manager) setting the following _values_: ```yaml providers: kubernetesGateway: enabled: true gateway: enabled: true annotations: cert-manager.io/issuer: selfsigned-issuer listeners: websecure: hostname: whoami.docker.localhost port: 8443 protocol: HTTPS certificateRefs: - name: whoami-tls ``` Install cert-manager: ```bash helm repo add jetstack https://charts.jetstack.io --force-update helm upgrade --install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.15.1 \ --set crds.enabled=true \ --set "extraArgs={--enable-gateway-api}" ```
With those values, a whoami service can be exposed with HTTPRoute on both HTTP and HTTPS ```yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: whoami spec: replicas: 2 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami --- apiVersion: v1 kind: Service metadata: name: whoami spec: selector: app: whoami ports: - protocol: TCP port: 80 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: whoami spec: parentRefs: - name: traefik-gateway hostnames: - whoami.docker.localhost rules: - matches: - path: type: Exact value: / backendRefs: - name: whoami port: 80 weight: 1 --- apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: selfsigned-issuer spec: selfSigned: {} ``` Once it's applied, whoami should be accessible on https://whoami.docker.localhost/