Linkerd - Troubleshooting mit einem Service Mesh

15.09.2021Stefan Welsch
Cloud Service Mesh kubernetes Istio Hands-on

Heute widme ich mich dem Thema Service Mesh und will euch linkerd etwas näher bringen. Tom hat uns ja bereits Istio gezeigt und hat uns dort eine sehr gute Basis gelegt um eine weitere Service Mesh Platform unter die Lupe zu nehmen.

Linkerd ist also wie Istio ein Service Mesh. Bevor ich aber tief ins Thema einsteige, will ich kurz noch einmal einen Schritt zurück machen und erklären, was genau ein Service Mesh ist und warum es Wert ist diesen einzusetzen.

Ein Service Mesh steuert im Prinzip, wie unterschiedliche Teile einer Applikation oder Anwendung Daten miteinander teilen können. Dabei wird das Service Mesh direkt in die Anwendung integriert, ohne dabei jedoch den Code der Applikation verändern zu müssen. Das ist möglich indem vor die Applikation ein Proxy gestellt wird, der alle Anfragen entgegennimmt und diese dann an die Applikation weiterleitet.

Die Vorteile werden dabei sehr schnell klar. Will man beispielsweise einen Service nur autorisierten Benutzern zur Verfügung stellen, so kann man dies zentral über das Service Mesh steuern und braucht nicht pro Applikation die Logik zu implementieren. Wer sich noch einmal ein genaueres Bild machen will, der sollte unbedingt noch einmal den Blogbeitrag von Tom dazu lesen.

Fakten zu linkerd

Linkerd ist ein OpenSource Projekt (Apache 2.0 Lizenz) und wurde im Jahr 2015 ins Leben gerufen. Die Entwickler von linkerd sind ehemalige Twitter Mitarbeiter und gründeten das Unternehmen Buoyant, welches eine Managed linkerd Platform anbietet. Das Projekt ist jetzt ganz frisch ein CNCF Graduated Project und mittlerweile in der Version 2.10.2 verfügbar. Laut eigenen Angaben gibt es über 200 Contributor, welche aktiv am Projekt mitentwickeln. Linkerd selbst ist überwiegend in Go geschrieben, die Proxies wurden allerdings in Rust geschrieben.

Architektur von linkerd

Linkerd besteht im Prinzip aus einem Control Plane und einem Data Plane. Dazu kommt noch eine sehr übersichtliche UI und ein paar weitere Komponenten. Wir schauen uns die Architektur kurz im Detail an.

Control Plane

Das Control Plane bietet Services, welche in einem eigenen Namespace (linkerd) angesiedelt sind. Diese Services sind für verschiedene Aufgaben, wie beispielsweise Telemetriedaten zu aggregieren oder das Anbieten einer API für die CLI und die Web-UI, zuständig. Das Control Plane stellt ausserdem den Data Plane Proxies Daten zur Verfügung, um das Verhalten des Data Plane zu steuern.

Das Control Plane besteht dabei aus den folgenden Komponenten:

Web + CLI

Das Web Deployment stellt uns das linkerd Dashboard zur Verfügung. Die CLI kann auf verschiedenen Systemen installiert werden um mit der Public API zu kommunizieren.

Controller

Die Public-API bietet wie bereits erwähnt die Schnittstelle zu der CLI und der UI an.
Die Destination Komponente sorgt dafür das jeder Proxy im Data Plane weiss, wo Requests hingesendet werden sollen.

Die Identity Komponente stellt eine Certificate Authority zur Verfügung. Mit dieser können sich Proxies Zertifikate ausstellen lassen um mTLS zu implementieren.

Die Tap Komponente nimmt Requests von der CLI und dem Dashboard entgegen um Realtime Überwachungen von Requests und Responses zu zeigen.

Der Project Injector ist ein Admission Controller, der einen Pod beim einem Webhook Request erstellt. Wenn ein Pod die Annotation linkerd.io/inject: enabled hat, wird vom Proxy Injector ein init-Container und ein Sidecar Container mit dem eigentlichen Proxy bereitgestellt.

Der Service Profile Validator ist auch ein Admission Controller welcher neue Service Profile validiert, bevor diese abgespeichert werden.

Monitoring

Linkerd bietet uns eine komfortable Sicht auf die Resourcen, welche in unserem Cluster laufen. Eine ganz entscheidende Rolle zur Aufbereitung und Visualisierung der Daten spielen dabei Prometheus und Grafana.

Prometheus ist ein Cloud Native Monitoring Tool welches alles Metriken sammelt und speichert. Linkerd installiert Prometheus als Teil des Control Plane, so dass dieses Daten für die CLI das Dashbaord und Grafana zur Verfügung stellen kann.

Grafana bietet uns Dashboards an um unsere Komponenten zu überwachen. Im linkerd Dashboard gibt es zu allen Ressourcen Links, welche uns zum entsprechenden Grafana Dashboard führen.

Data Plane

Neben dem Control Plane gibt es die Data Plane, welche die Daten für linkerd produziert. Im Prinzip handelt es sich hierbei um unsere Applikations-Pods. In jedem Pod wird zu der eigentlichen Applikation ein Sidecar Container gestartet, welcher als Proxy für die Applikation dient. Damit der Pod einen solchen Container bekommt, ist es erforderlich eine bestimmte Annotation zu setzen. Man kann dies entweder über die CLI mit linkerd inject oder manuell über die Pod Spezifikation machen.

Der Proxy ist ein sehr kleines, in Rust geschriebenes Programm. Dieser sorgt dafür, das jegliche Kommunikation zu der Applikation nur noch über den Proxy erfolgt. Dabei wird nicht nur der eingehende, sondern mittels eines initContainer welcher iptables Regeln definiert, auch der ausgehende Traffic abgefangen.

Nun kennen wir alle Komponenten und wissen, wie linkerd in der Theorie funktioniert. Wollen wir uns jetzt anschauen, wie das ganze in der Praxis aussieht.

Installation

Als erstes installieren wir uns ein lokales Kubernetes mit kind. Ich gehe in diesem Blogpost nicht auf die Installation von kind ein. Nachdem Kind installiert ist, können wir unseren Cluster mit dem folgenden Befehl erstellen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ kind create cluster

Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.21.1) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-kind"
You can now use your cluster with:

$ kubectl cluster-info --context kind-kind

Danach installieren wir uns die CLI

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ curl -sL https://run.linkerd.io/install | sh

Downloading linkerd2-cli-stable-2.10.2-darwin...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   641    0   641    0     0   2553      0 --:--:-- --:--:-- --:--:--  2553
100 42.8M  100 42.8M    0     0  33.5M      0  0:00:01  0:00:01 --:--:-- 61.3M
Download complete!

Validating checksum...
Checksum valid.

Linkerd stable-2.10.2 was successfully installed 🎉


Add the linkerd CLI to your path with:

  export PATH=$PATH:/Users/swelsch/.linkerd2/bin

Now run:

  linkerd check --pre                     # validate that Linkerd can be installed
  linkerd install | kubectl apply -f -    # install the control plane into the 'linkerd' namespace
  linkerd check                           # validate everything worked!
  linkerd dashboard                       # launch the dashboard

Looking for more? Visit https://linkerd.io/2/tasks

Bevor wir nun das linkerd Control Plane installieren können, machen wir erstmal einen Pre Check, ob unser Cluster alle Anforderungen erfüllt.

Am Ende der Ausgabe sollte dann folgendes zu finden sein:

1
Status check results are √

Nun installieren wir das Control Plane und checken danach ob alles ok ist.

1
2
$ linkerd install | kubectl apply -f -
$ linkerd check

Wenn alles “grün” ist, können wir uns nun noch eine nützliche Extension installieren, welche uns Prometheus, das Dashboard und den Metrics Server installiert. Auch danach führen wir wieder den Check aus, ob alles richtig installiert wurde.

1
2
$ linkerd viz install | kubectl apply -f -
$ linkerd check

Wir haben nun ein lauffähiges linkerd auf unserem Cluster installiert. Schauen wir uns als nächstes das Dashboard an.

Dashboard

Um auf das Dashboard zu gelangen geben wir den folgenden Befehl in der Konsole ein. Dieser sorgt für ein Port-Forwarding auf den linkerd-web Pod und startet uns automatisch den Browser.

1
2
3
4
5
6
7
8
$ linkerd viz dashboard &

[1] 36621
~ ❯ Linkerd dashboard available at:                                                                                                                                                                                                                                                                          2.6.3 14:03:02
http://localhost:50750
Grafana dashboard available at:
http://localhost:50750/grafana
Opening Linkerd dashboard in the default browser

Nun sollten wir im Browser das Dashboard sehen.

Let’s play

Schauen wir uns nun im Detail an, welche Vorteile uns linkerd bringt. Dazu installieren wir uns die Demo App emojivoto, welche auch als Beispiel App auf der offiziellen linkerd Seite genutzt wird.

1
$ curl -sL https://run.linkerd.io/emojivoto.yml | kubectl apply -f -

Im Dashboard sehen wir nun, dass die Applikation installiert wurde, allerdings sehen wir noch keine Metriken, da der Proxy Container noch nicht im Pod injected wurde.

Um auf die Applikation zugreifen zu können, müssen wir ein Port-Forwarding auf den Pod einrichten.

1
$ kubectl -n emojivoto port-forward svc/web-svc 8080:80

Danach kann die Applikation lokal mit http://localhost:8080 aufgerufen werden.

Sieht soweit gut aus. Nun wollen wir linkerd zur Applikation hinzufügen. Dazu führen wir den folgenden Befehl aus, welcher uns die linkerd Sidecar Container in den Deployments erstellt.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ kubectl get -n emojivoto deploy -o yaml | linkerd inject - | kubectl apply -f -
  
deployment "emoji" injected
deployment "vote-bot" injected
deployment "voting" injected
deployment "web" injected

deployment.apps/emoji configured
deployment.apps/vote-bot configured
deployment.apps/voting configured
deployment.apps/web configured

Wie wir sehen können wurde linkerd in die Deployments injected. Das linkerd inject Kommando fügt spezielle Annotations zur Pod Spezifikation hinzu, damit linkerd weiss, in welchen Pods ein Proxy Container hinzugefügt werden soll. Schauen wir uns den Pod genauer an, so sehen wir die Annotations:

1
$ kubectl describe -n emojivoto pod emoji-XXXXXXXXX-XXXXX

Weiter können wir sehen, dass es einen zweiten Container im Pod gibt.

Ein anderer Weg um zu checken ob der Proxy richtig läuft ist per linkerd CLI

1
linkerd -n emojivoto check --proxy

Ein Blick ins Dashboard zeigt nun wie erwartet Metriken von der Applikation an.

Wie können hier die HTTP Metriken vom gesamten Namespace sehen. Wir können jetzt durch einen Klick auf den Namespace in die Detailansicht springen, wo wir die einzelnen Ressourcen (z.B. Deployments und Pods) sehen.

Wir können diese Informationen natürlich auch jederzeit über die CLI abrufen.

1
2
3
4
5
6
$ linkerd -n emojivoto viz stat deploy                                                                                                                                                                                                                                                                      2.6.3 15:57:47
NAME       MESHED   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99   TCP_CONN
emoji         1/1   100.00%   2.3rps           1ms           1ms           1ms          3
vote-bot      1/1   100.00%   0.3rps           1ms           1ms           1ms          1
voting        1/1    87.01%   1.3rps           1ms           1ms           1ms          3
web           1/1    92.65%   2.3rps           4ms           9ms          10ms          3

Top & Tap

Linkerd bietet uns zwei nützliche Tools, mit denen wir den Traffic von und zu den Resourcen überwachen können. Top bietet uns hier eine Übersicht der einzelnen Request (Summiert gleiche Requests auf), während Tap uns den kompletten Stream (also jeden einzelnen Request) präsentiert.

Auch hier haben wir wieder die Möglichkeit sowohl die UI, als auch die CLI zu benutzen.

Top

1
$ linkerd -n emojivoto viz top deploy/web

Tap

1
$ linkerd -n emojivoto viz tap deploy/web

Schlusswort

Wie wir sehen konnten bietet uns linkerd einen schnellen Überblick über Metriken unserer Ressourcen. Das Tool ist sehr übersichtlich aufgebaut und dank der in Rust geschriebenen Sidecard Proxies auch sehr performant und erzeugt relativ wenig Overhead (Sidecar Image ist 114 MB gross).

Wir werden uns auf jeden Fall weiter mit dem Service Mesh beschäftigen und in einem weiteren Blogbeitrag zeigen, wie man mit linkerd Fehler in einer Applikation debuggen kann.

Sollten es noch Fragen zu linkerd oder rund um das Thema Service Mesh geben, dann nehmen Sie einfach Kontakt mit uns auf. Wir helfen Ihnen gerne weiter.

Stay tuned.

Stefan Welsch

Stefan Welsch – Manitu, Pionier, Stuntman, Mentor. Als Gründer von b-nova ist Stefan immer auf der Suche nach neuen und vielversprechenden Entwicklungsfeldern. Er ist durch und durch Pragmatiker und schreibt daher auch am liebsten Beiträge die sich möglichst nahe an 'real-world' Szenarien anlehnen.