Im Gegensatz zu den bekannten anderen Ingress-Controllern für k8s, die auf entweder
- althergebrachter Reverse Proxy-Software wie Nginx und HAProxy, oder
- 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.