Im Gegensatz zu den bekannten anderen Ingress-Controllern für k8s, die auf entweder

  1. althergebrachter Reverse Proxy-Software wie Nginx und HAProxy, oder
  2. der verwendeten Systemumgebung, sei es ein Cloud-Provider oder auch Netzwerkhardware

basieren, ist Traefik ein reverse proxy, der von der Erstentwicklung her auf “cloud-native” (oder auch: “was mit Containern”) angepasst wurde.

In diesem Kontext steht dann auch das Design: das Programm selbst ist (oft) ein statisch kompiliertes Go-Binary, die Konfiguration sollte möglichst dynamisch sein und über Schnittstellen statt über irgendwelche Dateien aktualisiert werden, etc. pp.

Der Featuresatz ist dementsprechend auch etwas anders ausgerichtet als klassische Reverse Proxies, und es versucht ein primär auf HTTP(S) ausgerichtetes und keiner Erweiterung bedürftiges Tool zu sein. Das heißt:

  • Configuration Discovery: Man kann verschiedene Dienste definieren, die als Quelle für Routing-Informationen dienen sollen. Hier setzt auch die Kubernetes-Funktion an.
  • Eingebaute TLS-Verwaltung: Neben selbst mitgebrachten Zertifikaten kann Traefik von Haus aus LetsEncrypt.
  • Middlewares zur schnellen Veränderungen im Ingress: Anstatt auf die mächtigen und lasterzeugenden Engines der Klassiker zu setzen, geht Traefik den Weg von Middlewares, die einige verschiedene wohldefinierte Funktionen im Stream bereitstellen können, z.B. Basic Auth, Redirects, zusätzliche Header, usw.
  • Monitoring onboard: Neben einem eingebauten Dashboard für die gesamte Systemübersicht sind diverse Metriken und Tracing-Systeme eingebaut und können ziemlich trivial angesteuert werden.

Was heißt das im Rahmen von Kubernetes?

Nehmen wir an, Ingress wurde über z.B. Helm einfach in einen k8s-Cluster geworfen; für Kubernetes-Installationen ist das sicherlich der einfachste Weg. Hierbei sollte aufgepasst werden, dass wie in der offiziellen Dokumentation erwähnt auch das Chart-Repository von Traefik benutzt wird, da das Chart im stable-Repository von Helm noch auf einem recht alten Traefik beruht.

Im simpelsten Falle reicht zur Installation also einfach:

helm repo add traefik https://helm.traefik.io/traefik
helm repo update
helm install traefik traefik/traefik

Nota bene: Warum Sie für einen produktiven Cluster für Ihre Firma vielleicht einen anderen Weg gehen sollten als das Äquivalent von curl | sh, können Sie gerne bei uns anfragen. Wir beraten Sie gerne — für eine Demonstration reicht dieser Weg allemal.

Ebenso wie z.B. der Nginx Ingress kann der Traefik Ingress über Annotationen auf einem Ingress-Objekt definiert werden:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: keycloak
  namespace: keycloak
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  hosts:
    - auth.example.com
  rules:
  - host: auth.example.com
    http:
      paths:
        - pathType: Prefix
          path: '/'
          backend:
            service:
              name: keycloak
              port:
                number: 8080

Wie zu erwarten wird dies einfach eine Traefik-Instanz starten, die über HTTP (und nur HTTP, es fehlt der tls-Schlüssel unter spec) dann einen Keycloak im Backend unter auth.example.com zur Verfügung stellt.

TLS made easier

Der Clou, der für alle relevant ist, die Ihre TLS-Zertifikate wirklich nur für Ihre Frontend-Dienste brauchen, ist das eingebaute ACME für z.B. Let’s Encrypt. Wenn man sich nicht mit dem mächtigen cert-manager.io abgeben will, was gerade in kleineren Umgebungen wünschenswert sein kann, dann lässt sich hier Traefik über die Annotationen auf einem Ingress für automatische SSL-Zertifikate freischalten.

Hierfür erweitern wir die Helm-Konfiguration von Traefik; dies muss als Teil der statischen Konfiguration von Traefik erfolgen, daher die Config-CR. Hier wird die tlsChallenge genutzt, d.h. tls-alpn-01 — hierfür muss der Server öffentlich auf Port 443 erreichbar sein. Der etwas verträglichere Weg wäre die dnsChallenge mit einem DNS-Provider, aber das sprengt hier leicht den Rahmen.

$ cat <<EOF > traefik-tls.yaml
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
  name: traefik
  namespace: kube-system
spec:
  valuesContent: |-
    additionalArguments:
      - "--log.level=DEBUG"
      - "--certificatesresolvers.le.acme.email=contact@example.com"
      - "--certificatesresolvers.le.acme.storage=/data/acme.json"
      - "--certificatesresolvers.le.acme.tlschallenge=true"
      - "--certificatesresolvers.le.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory"
EOF
$ kubectl apply -f traefik-tls.yaml

Danach können wir unseren bisherigen Ingress um die entsprechenden TLS-Annotationen erweitern:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: keycloak
  namespace: keycloak
  annotations:
    kubernetes.io/ingress.class: traefik
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    traefik.ingress.kubernetes.io/router.tls.certresolver: le
spec:
  hosts:
    - auth.example.com
  rules:
  - host: auth.example.com
    http:
      paths:
        - pathType: Prefix
          path: '/'
          backend:
            service:
              name: keycloak
              port:
                number: 8080

Nun muss man nur kurz warten (und eventuell debuggen, wenn’s mal wieder mit Let’s Encrypt hakt…), und dann hat man schon ein Let’s Encrypt-Zertifikat und der Dienst lauscht auf einmal hinter TLS auf Port 443.

Die Kehrseite der Medaille

Das Manko an der Situation ist, dass Traefik Proxy in der Non-Enterprise-Version leider nicht für hochverfügbare Setups vorgesehen ist, was heißt, dass man das eingebaute ACME nicht in HA-Situationen nutzen kann, ohne eventuell in Problemen zu landen. (Kurzum: die Challenges werden nicht propagiert zwischen den verschiedenen Instanzen.)

Hierfür ist dann ein Schwenk auf cert-manager empfehlenswert, da dieser die Zertifikate unabhängig von Traefik verwaltet, der sich als stateless sieht.

cert-manager und Traefik

Es würde diesen Beitrag sprengen, cert-manager auch noch zu erwähnen. Falls man aber schon cert-manager fertig rumliegen hat, gibt es gerade in Verbindung mit dem oben erwähnten k3s ein wichtiges Caveat: es ist nötig, die ingressTemplate von cert-manager anzupassen, damit der self-check auch den Dienst selber findet, statt hoffnungslos vor die Wand zu fahren. Dafür muss man z.B. bei einem ClusterIssuer entsprechend die ingressTemplate setzen:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
  namespace: cert-manager
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: contact@example.com
    privateKeySecretRef:
      name: letsencrypt-staging
    solvers:
    - http01:
        ingress:
          ingressTemplate:
            metadata:
              annotations:
                traefik.ingress.kubernetes.io/router.entrypoints: web

Hier wurde der Entrypoint web als Annotation auf der Vorlage für Ingresse hinterlegt. Dies sorgt nun dafür, dass der Ingress zum Abfangen des Selbsttests auch entsprechend über Traefiks web-Entrypoint geleitet wird, statt keinen default ingress zu finden.

Middlewares

Was Traefik noch als kleine Hilfestellung abhebt: es gibt diverse sogenannte Middlewares. Im Prinzip sind das kleine Wrapper um die Verbindung, welche typische Konfigurationsschnipsel, wie man sie von Nginx und Apache kennt, ersetzen. Hier gibt es die diversesten Beispiele, man vergleiche einfach die verlinkte Dokumentation.

Sollte man sich z.B. eine Basic Auth wünschen, vielleicht, weil man sicher gehen will, dass der dahinterliegende Dienst nicht zufällig durch einen Exploit im User-Agent-String aufgemacht wird, kann man hier leicht eine Authentifizierung vorschalten. Dafür braucht es nur ein entsprechendes Label:

"traefik.http.middlewares.test-auth.basicauth.users=[...]"

Und dort dann einfach eine kommagetrennte Liste von typisches htusers-Strings, wie sie htpasswd ausspuckt. Statt einer statischen Basic Auth lässt sich hier auch eine Authentifizierungs-Weiterleitung (z.B. zu Keycloak) stricken. Bei Interesse an einem Beitrag dazu einfach mal bei der Mailadresse unter diesem Beitrag hier melden.

Fortsetzung folgt?

Eine leicht spannendere Art, die Traefik abhebt vom klassischen Nginx Ingress, die ich bisher auch noch nicht erwähnt haben, ist die Konfiguration komplett über CRDs; d.h. statt mit Labeln zu arbeiten werden einfach entsprechende Objekte erstellt, die Traefik etwas mächtiger machen, da hier dann auch Secrets genutzt werden können.

Wen dies interessiert, der sollte auf Teil 2 warten, in welchem wir uns mit der CRD-Konfiguration von Traefik beschäftigen.

Tobias Wolter
towo macht seit dem letzten Jahrtausend Dinge mit Linux und verdient seit 2013 bei der B1 damit sein Brot. Für einen Wechsel zu was mit Holz ist es zu spät, deswegen passiert das nur in der Freizeit.