K8S Servicemesh Linkerd mit MicroK8S auf Raspberry PI - Alfred Sabitzer - E-Book

K8S Servicemesh Linkerd mit MicroK8S auf Raspberry PI E-Book

Alfred Sabitzer

0,0
5,99 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.

Mehr erfahren.
Beschreibung

Dieses Buch beschreibt die einzelnen Schritte, die ich durchgeführt habe um mir meine eigene Cloud zu bauen. Hier werden aufbauend auf dem Hardwareaufbau im Buch "Bau einer K8s bare-metal-cloud mit RaspberryPI" ISBN 978-3-7534-9851-4, sowie dem Buch "K8s Applications mit MicroK8S auf Raspberry PI" ISBN 978-3-7427-7013-4 unterschiedliche Konzepte und Ideen beschrieben. Der Bau von Microservices, das Einrichten einer CI/CD-Strecke, kpt, kustomize, Servicemesh usw, wird anhand von Beispielen soweit möglich erklärt. Hier finden sich viele Codefragmente, die eine Idee geben können, wie jemand das bei sich zu Hause selbst tun könnte.

Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:

EPUB

Seitenzahl: 313

Veröffentlichungsjahr: 2022

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



 

 

K8SServicemesh Linkerd

mit MicroK8S

auf Raspberry PI

 

 

Beispiele für das Entwickeln und Betreiben von Anwendungen mit einem Servicemesh auf einem mit einer Firewall gesicherten MicroK8s Cluster auf Raspberry PI Basis.

 

 

 

 

 

 

 

Alfred Sabitzer

 

https://www.linkedin.com/in/alfred-sabitzer-805312183/

https://www.xing.com/profile/Alfred_Sabitzer/cv

 

 

 

Vorwort

Die Idee eine „Cloud“ zu bauen entstand während der Corona-Zeit. Anstatt „Fernsehen“ könnte man doch was Sinnvolles ausprobieren. Außerdem ist der vorhandene Raspberry 4 bereits überlastet, und kann schwerlich neue Dienste anbieten. Da wäre doch ein System, das skalierbar ist, beliebig viele Services anbieten kann usw. doch genau das Richtige. Außerdem sind Microservices leichter auf neue Hardware portierbar!

Darum: eine Cloud muss her.

Generell: Der Bau einer Cloud ist ein komplexes Unternehmen (am einfachsten ist es, wenn man sich in einer bereits existenten Cloud einmietet – da gibt es genug Anbieter am Markt).

Dieses Buch beschreibt die einzelnen Schritte, die ich durchgeführt habe um mir meine eigene Cloud zu bauen. Hier werden aufbauend auf dem Hardwareaufbau im Buch "Bau einer K8s bare-metal-cloud mit RaspberryPI" ISBN 978-3-7534-9851-4, sowie dem Buch "K8s Applications mit MicroK8S auf Raspberry PI" ISBN 978-3-7427-7013-4 unterschiedliche Konzepte und Ideen beschrieben. Der Bau von Microservices, das Einrichten einer CI/CD-Strecke, kpt, kustomize, Servicemesh usw, wird anhand von Beispielen soweit möglich erklärt.

Hier finden sich viele Codefragmente, die eine Idee geben können, wie jemand das bei sich zu Hause selbst tun könnte. Diese Codeteile erheben keinen Anspruch auf Funktionalität oder dergleichen. Die Verwendung erfolgt auf eigenes Risiko.

Der Autor ist erreichbar unter [email protected] erreichbar.

Die in diesem Buch angeführten Programmteile gibt es online auf https://gitlab.com/Alfred-Sabitzer/mikrok8s .

Einleitung

Nach dem Aufsetzen des microK8s-Cluster auf RaspberryPI und prinzipiellem Einrichten der Infrastruktur (siehe „Bau einer K8s bare-metal-cloud mit RaspberryPI“), dient diese Beschreibung um die Schritte, Versuche und Fehlversuche zu dokumentieren, die ich beim Entwicklen, Einrichten und Betreiben von Anwendungen im k8s-Cluster unternommen habe. Es werden die folgenden Teile beschrieben

 

Prinzipieller Aufbau des Clusters

Automatisierung

Einrichten der Ingresse

Secretmanagement

Docker-Repositories

Clusterstorage

Webservices

Redis

PostgresDB

Joomla

Nextcloud

Mailcow

Starboard

Argo CD

Servicemesh Linkerd

 

Alle Services werden als yaml-File beschrieben. Die Sourcen befinden sich auf

https://gitlab.com/Alfred-Sabitzer/mikrok8s .

 

Leider ist nicht alles am Raspberry mit arm-Architekture verfügbar. Somit kann ein K8S-Cluster auf Raspberry Basis nicht wirklich mit einem Cluster auf Intel-Basis (oder noch besser in einer wirklichen Cloud wie Google oder Amazon) verglichen werden. Es ist dennoch eine gute und kostengünstige Basis um die Prinzipien kennen zu lernen, und Hands-On einen Cluster vom Scratch aufzubauen.

 

Der hier beschriebene Cluster baut auf den Büchern

 

"Bau einer K8s bare-metal-cloud mit RaspberryPI" ISBN 978-3-7534-9851-4 sowie "K8s Applications mit MicroK8S auf Raspberry PI" ISBN 978-3-7427-7013-4 auf.

 

Gutes Gelingen!

Architektur des Clusters

Inspiration:

https://de.wikipedia.org/wiki/Raspberry_Pi

https://www.picocluster.com/

https://microk8s.io/tutorials

 

 

Das System besteht aus einem RaspberryPI-Cluster mit microk8s. Die Raspberry-Version ist 4 mit 8GB RAM und einer 64GB SDRAM. Der Cluster besteht aus 5 Nodes. Jeder Node hat zusätzlich noch eine externe 110GB USB-SSD-Platte die als Clusterstorage konfiguriert ist. Weiterführende Details siehe in den referenzierten Büchern.

 

Für unseren Cluster brauchen wir einen "Build-Rechner", der auch NTP-Server für den Cluster ist. Der Build-Rechner ist ein Raspberry4 mit 8GB RAM und einer lokalen 117GB SDRAM. Installiert ist (neben ein paar anderen Kleinigkeiten) Docker, kpt, kustomize, kubectl. Der Build-Rechner bietet das Basis-Docker-Repository an (für Images, die für den Start des Clusters notwendig sind, und die ich nicht immer aus dem Internet holen möchte).

 

Der MicroK8S-Cluster bietet das private Docker-Repository an.

 

Die Steuerung bzw. der Zugriff auf den Cluster erfolgt von meinem lokalen Rechner (eine Linux-Maschine:)).

 

Ein Übersicht gibt folgendes Bild:

Abbildung 1: Cluster-Architektur

Das Source-Repository ist in Gitlab auf https://gitlab.com/Alfred-Sabitzer/mikrok8s . Dort können auch alle Skripten heruntergeladen werden. Manche Skripten werden zum besseren Verständnis hier im Buch beschrieben.

IP-Adressen

Inspiration:

https://cloud.google.com/kubernetes-engine/docs/concepts/network-overview

 

Die im Cluster verfügbaren Bereiche sind:

 

 

 

Das heisst, alle Services im Cluster werden über Ingress angesprochen. Viele Services besitzen aber ein Whitelisting, und können trotzdem nur von intern angesprochen werden. Es gibt aber auch Ausnahmen. Z.b. werden für die Postgres-Datenbanken 192.168.x.x-Adressen bereitgestellt. Das erleichtert die Konfiguration und manche Test- und Diagnoseskripten.

 

Um einfach auf den Cluster zugreifen zu können, sind die folgenden Einträge im /etc/hosts hilfreich.

 

192.168.0.210  k8s.slainte.at

192.168.0.210                longhorn.k8s.slainte.at

192.168.0.210                grafana.k8s.slainte.at

192.168.0.210                prometheus.k8s.slainte.at

192.168.0.210                docker.k8s.slainte.at

192.168.0.210                dockerui.k8s.slainte.at

192.168.0.210  viz.k8s.slainte.at

192.168.0.210  kubernetes-dashboard.127.0.0.1.nip.io

192.168.0.210                pc.home

192.168.0.201                pc1

192.168.0.202                pc2

192.168.0.203                pc3

192.168.0.204                pc4

192.168.0.205                pc5

 

Initiales Aufsetzen des Clusters

Inspiration:

https://microk8s.io/tutorials

 

Um den Cluster richtig (und immer wieder) aufsetzen zu können habe ich alles in ansible und bash-skripten abgebildet. Nach dem Initialisieren der SD-Karten haben wir fünf unabhängige Linux-Rechner. Auf jedem einzelnen Loggen wir uns ein und führen das Skript MicroK8SLocalNode.sh aus.

 

#!/bin/bash

############################################################################################

#

# Initialisierung auf dem lokalen Node

# Auf jedem Node einloggen, und Setup durchführen.

# Das ist eine notwendige Vorbereitung bevor der MicroK8S-Cluster aufgesetzt werden kann.

#

# wget https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/raw/main/ClusterSetup/MicroK8SLocalNode.sh

#

############################################################################################

IFS="

"

#

if [[ !                ${1} =~                (pc1|pc2|pc3|pc4|pc5) ]]; then

 echo "Usage ${0} (pc1|pc2|pc3|pc4|pc5) Passwort"

 exit 1

fi

Node=${1}

 echo "Usage ${0} (pc1|pc2|pc3|pc4|pc5) Passwort"

 exit 1

fi

PASS=${2}

#

#shopt -o -s errexit #—Terminates  the shell script if a command returns an error code.

shopt -o -s xtrace #—Displays each command before it’s executed.

shopt -o -s nounset #-No Variables without definition

#

# Wir werden Root

#

iam=$(whoami)

 echo "Benutzer muß Root sein"

 exit 1

fi

#

# Standarduser Ubuntu updaten

#

#echo ${PASS} > /tmp/pass.txt

#echo ${PASS} >> /tmp/pass.txt

#cat /tmp/pass.txt |  passwd ubuntu

# Sudo einrichten

sed --in-place '/ALL=(ALL:ALL) NOPASSWD:ALL/d' /etc/sudoers

echo '%sudo  ALL=(ALL:ALL) NOPASSWD:ALL'  >> /etc/sudoers

#

# Anlegen der User

#

username=$(cat /etc/passwd | grep -i alfred)

 userdel -f -r alfred

fi

username=$(cat /etc/passwd | grep -i ansible)

 userdel -f -r ansible

fi

useradd  --comment "Systemadmin" -m --shell "/bin/bash" --password $(openssl passwd -crypt $PASS)  alfred

useradd  --comment "Systembenutzer für ansible" -m --shell "/bin/bash" --password  $(openssl passwd -crypt $PASS)  ansible

usermod -aG sudo alfred

usermod -aG sudo ansible

#

# ssh-keys

#

mkdir -p /home/alfred/.ssh/

curl -L https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/raw/main/ClusterSetup/alfred_id_rsa.pub -o /home/alfred/.ssh/authorized_keys

chown -R alfred:alfred /home/alfred/.ssh

chown -R alfred:alfred /home/alfred/.ssh/authorized_keys

mkdir -p /home/ansible/.ssh/

curl -L https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/raw/main/ClusterSetup/ansible_id_rsa.pub -o /home/ansible/.ssh/authorized_keys

chown -R ansible:ansible /home/ansible/.ssh

chown -R ansible:ansible /home/ansible/.ssh/authorized_keys

#

# Firmware-Settings

#

curl -L https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/raw/main/ClusterSetup/cmdline.txt -o /boot/firmware/cmdline.txt

#

# Hostname

#

echo ${Node} > /etc/hostname

#

# Hosts-File

#

curl -L https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/raw/main/ClusterSetup/hosts -o /etc/hosts

NODEIP=$(cat /etc/hosts | grep -i ${Node})

sf="  ${Node}"

NODEIP=${NODEIP%"$sf"*}

sed -i "s,#NODE#,${Node},g" /etc/hosts

#

# Network-Config

#

curl -L https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/raw/main/ClusterSetup/99-disable-network-config.cfg -o /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg

curl -L https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/raw/main/ClusterSetup/50-cloud-init.yaml -o /etc/cloud/cloud.cfg.d/50-cloud-init.yaml

sed -i "s,#NODE#,${NODEIP},g" /etc/cloud/cloud.cfg.d/50-cloud-init.yaml

#

# NTP

#

curl -L https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/raw/main/ClusterSetup/timesyncd.conf -o /etc/systemd/timesyncd.conf

systemctl stop systemd-timesyncd.service

systemctl enable systemd-timesyncd.service

systemctl start systemd-timesyncd.service

systemctl status systemd-timesyncd.service

#

# Startup-file für Modprobe

#

curl -L https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/raw/main/ClusterSetup/modprobe.service -o /etc/systemd/system/modprobe.service

chown root:root /etc/systemd/system/modprobe.service

chmod 755 /etc/systemd/system/modprobe.service

systemctl stop modprobe.service

systemctl enable modprobe.service

systemctl start modprobe.service

systemctl status modprobe.service

#

# Lokale Rechte

#

 

#

# Jetzt ist der Node Startklar und kann mit ansible weiter konfiguriert werden

#

 

Wir werden Root (mit sudo su -l) und laden das Skript herunter.

 

wget https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/raw/main/ClusterSetup/MicroK8SLocalNode.sh

chmod 755 ./MicroK8SLocalNode.sh

/MicroK8SLocalNode.sh pc1 MeinGeheimesPasswort

 

Dieses Skript konfiguriert den lokalen Node für die spätere Benutzung. Es werden zwei User eingerichtet (eben alfred und ansible). Für diese User werden auch die SSH-Keys eingespielt (sie können sich später ohne Passwort einloggen). Diese User sind Mitglied der sudo-Gruppe und können jeden Befehl ohne Passwort absetzen. Danach kann von der Management-Console am "Management-Rechner" das Skript ClusterSetup.sh aufgerufen werden. Dieses Skript erzeugt dann den MicroK8S-Cluster und ruft die einzelnen Kommandos in der richtigen Reihenfolge auf.

 

#!/bin/bash

############################################################################################

#

# Schnell-Installation microk8s

#

############################################################################################

#shopt -o -s errexit  #—Terminates  the shell script  if a command returns an error code.

shopt -o -s xtrace #—Displays each command before it’s executed.

shopt -o -s nounset #-No Variables without definition

indir=$(dirname "$0")

#

# Vorraussetzung: Sauber installierte Nodes

# Ansible Account verfügbar

# Lokal vorhandenes Kubectl, kpt, kustomize, docker

#

${indir}/MicroK8SInit.sh

${indir}/MicroK8SCluster.sh

${indir}/MicroK8SKube.sh

${indir}/MicroK8Smetallb.sh

${indir}/MicroK8SHelm.sh

${indir}/MicroK8SIngress.sh

${indir}/MicroK8SCertManager.sh

${indir}/MicroK8SOpenEBS.sh

#${indir}/MicroK8SLonghorn.sh

#${indir}/MicroK8SRegistry.sh - Da läuft was schief

${indir}/MicroK8SDashboard.sh

${indir}/MicroK8GrafanaReports.sh

#${indir}/MicroK8SK8TZ.sh - reagiert nicht auf injectAll=false

${indir}/MicroK8SSecureRegistry.sh # Passworte

${indir}/MicroK8S_Registry.sh # Wir arbeiten mit der Secure Registry

#${indir}/MicroK8SISTIO.sh - wird auf Raspberry nicht supported

#${indir}/MicroK8SISTIOOperator.sh - wird auf Raspberry nicht supported

${indir}/MicroK8SLinkerd.sh

#

# Nun ist der Cluster bereit

#

exit

#

 

Danach ist der Cluster betriebsbereit, und es können die Applikationen installiert werden.

Namespaces

Inspiration:

https://microk8s.io/docs/registry-built-in

 

Um den Cluster richtig betreiben zu können, sind auch Namespaces wichtig. Es sind (neben den technischen Namespaces, die mit k8s automatisch angelegt werden) noch die folgenden Namespaces vorhanden.

 

---

apiVersion: v1

kind: Namespace

metadata:

 labels:

 kubernetes.io/metadata.name: slainte

 annotations:

 linkerd.io/inject: enabled

 name: slainte

spec:

 finalizers:

 - kubernetes

---

apiVersion: v1

kind: Namespace

metadata:

 labels:

 kubernetes.io/metadata.name: default

 annotations:

 linkerd.io/inject: enabled

 name: default

spec:

 finalizers:

 - kubernetes

---

apiVersion: v1

kind: Namespace

metadata:

 labels:

 kubernetes.io/metadata.name: admin

 annotations:

 linkerd.io/inject: enabled

 name: admin

spec:

 finalizers:

 - kubernetes

---

 

Slainte ist quasi die Produktion (von aussen erreichbar). Default ist ein Test-URL der auch von aussen erreichbar ist. Die Services in admin dienen zum Administrieren des Cluster. In der Regel sind die admin-Services geschützt gegen den Zugriff aus dem Internet.

Secret-Management

Inspiration:

https://keepassxc.org/docs/KeePassXC_UserGuide.html

https://keepassxc.org/

https://gitlab.com/Alfred-Sabitzer/keepassxc2k8s

https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/tree/main/ReadXML

https://de.wikipedia.org/wiki/XMLStarlet

 

Secret-Management ist eine recht komplexe Aufgabe. Es gibt auch unterschiedliche Arten von Secrets, manchmal muß dasselbe Credential in mehrere Secrets. Manche Secrets braucht man in Gruppen (z.b. bei basic-auth für den Ingress). Manche Secrets werden sogar in einer Konfig-Map zur Verfügung gestellt.

 

Ich habe zu diesem Zweck Keepassxc im Einsatz.

 

Abbildung 2: keepassxc - Secret Management

 

In dieser keepassxc-Datei werden alle Secrets erfasst und nach Namespaces gruppiert.

 

 

 

 

 

 

 

Abbildung 3: Keepassxc - Passwort

Für jedes Secret wird der Name, der Benutzername, das Passwort, auch der URL sowie Notizen erfasst.

 

Abbildung 4: keepassxc - Komplexes Secret

 

 

Jedes Secret kann einen oder mehrere Arten besitzen.

 

Basic-auth – Dieses Secret wird in einer Basic-Auth Datei (mit MD5 Verschlüsselung) gesammelt. Der Wert entspricht dem Namen der Basic-Auth-Datei. Es können beliebig viele Passworte in dieser  Basic-Auth-Datei gesammelt werden.

Bcrypt-auth - Dieses Secret wird in einer Bcrypt-Auth Datei (mit bcrypt Verschlüsselung) gesammelt. Der Wert entspricht dem Namen der Bcrypt-Auth-Datei. Es können beliebig viele Passworte in dieser  Bcrypt-Auth-Datei gesammelt werden.

Config-Map – Es wird eine Config-Map generiert. Der binäre Teil entspricht der angegebenen Datei (kann in unserem Falle eine bcrypt oder basic-auth sein).

Dockercfg – Es wird ein dockerjson-Secret erzeugt. Dieses Secret dient zur Anmeldung an Docker-Registries.

Secret – Das würde untersschiedliche Secret-Typen beschreiben. Derzeit wird nur "k8s" unterstützt.

 

Um die Secrets zu generieren, kann man das Java-Programm auf https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/tree/main/ReadXMLverwenden. Mittlerweile finde ich die Bash-Lösung auf  https://gitlab.com/Alfred-Sabitzer/keepassxc2k8s praktischer. Sie hat einen kleineren Footprint, muß nicht kompiliert werden, braucht aber xmlstarlet https://de.wikipedia.org/wiki/XMLStarlet installiert.

 

Ich verwende hier das Beispiel aus https://gitlab.com/Alfred-Sabitzer/keepassxc2k8s/-/tree/main/example . Die generierten Secrets sehen dann so aus (am Beispiel des complex-password):

 

---

# Secret generated with ../keepassxc2k8s.sh

apiVersion: v1

kind: Secret

metadata:

 name: complex.basic-auth-ba

 namespace: default

 labels:

 managed-by: keepassxc

 algorithm: MD5

type: Opaque

data:

---

 

---

# Secret generated with ../keepassxc2k8s.sh

apiVersion: v1

kind: Secret

metadata:

 name: complex.bcrypt-auth-bc

 namespace: default

 labels:

 managed-by: keepassxc

 algorithm: bcrypt

type: Opaque

data:

---

---

# Secret generated with ../keepassxc2k8s.sh

apiVersion: v1

kind: Secret

metadata:

 name: complex-password

 namespace: default

 annotations:

 LastModified: 2022-12-05T07:28:42Z

 Created: 2022-12-05T07:25:25Z

 labels:

 managed-by: keepassxc

type: Opaque

data:

 username: dmVyeWNvbXBsZXgK

---

---

# Secret generated with ../keepassxc2k8s.sh

apiVersion: v1

kind: ConfigMap

metadata:

 name: complex-password-cm

 namespace: default

 labels:

 managed-by: keepassxc

data:

binaryData:

---

 

---

apiVersion: v1

kind: Secret

metadata:

 name: complex-password-dc

 namespace: default

 annotations:

 LastModified: 2022-12-05T07:28:42Z

 Created: 2022-12-05T07:25:25Z

 labels:

 managed-by: keepassxc

type: kubernetes.io/dockerconfigjson

data:

---

 

Diese Secrets müssen dann mit

 

kubectl apply -f .

 

eingespielt werden, und stehen dann dem System zur Verfügung.

 

 

 

 

Linkerd

Inspiration:

https://microk8s.io/docs/addon-linkerd

https://linkerd.io/2.12/overview/

https://linkerd.hacker-linner.com/2.9/tasks/troubleshooting/

http://thinkmicroservices.com/blog/2021/service-mesh/service-mesh-linkerd-kubernetes.html

https://itnext.io/optimizing-linkerd-metrics-in-prometheus-de607ec10f6b

https://linkerd.io/2.12/tasks/exposing-dashboard/

https://linkerd.io/2.12/features/dashboard/

https://picluster.ricsanfre.com/docs/service-mesh/

 

Linkerd ist ein schlanker Service-Mesh. In mikrok8s ist dieser Servicemesh automatisch dabei, und kann leicht enabled werden.

 

#!/bin/bash

############################################################################################

#

# MicroK8S Einrichten des Linkerd Service Mesh

#

############################################################################################

#shopt -o -s errexit  #—Terminates  the shell script  if a command returns an error code.

shopt -o -s xtrace #—Displays each command before it’s executed.

shopt -o -s nounset #-No Variables without definition

indir=$(dirname "$0")

# Disablen

kubectl apply -f ./namespaces.yaml  # Namespaces für Linkerd enablen

ansible pc1 -m shell -a 'microk8s disable linkerd'  # Disablen des Service-Mesh

${indir}/check_running_pods.sh

${indir}/cluster_reboot.sh

# Enable

${indir}/check_running_pods.sh

ansible pc1 -m shell -a 'microk8s enable linkerd'  # Enablen des Service-Mesh

${indir}/check_running_pods.sh

ansible pc1 -m shell -a 'microk8s linkerd check'  # Überprüfen der Funktionalität

kubectl apply -f ./linkerd.yaml  # Ingress für den Zugang zum Linker-web

${indir}/check_running_pods.sh

${indir}/cluster_reboot.sh

${indir}/check_running_pods.sh

${indir}/MicroK8SGrafanaReports.sh  # Nochmal die Reports einspielen und Passwort resetten. Offensichtlich wird die Datenbank überschrieben.

#

 

Danach ist Linkerd enabled, und wird bei allen pods Sidecars konfigurieren, die den Traffic messen. Wir schauen mal, was das alles ist.

 

$ kubectl get all -n linkerd

NAME  READY  STATUS  RESTARTS  AGE

pod/linkerd-identity-778bd797b9-bm9gh  2/2  Running  2 (18h ago)  18h

pod/linkerd-destination-5bc458558c-lqsq2  4/4  Running  4 (18h ago)  18h

pod/linkerd-proxy-injector-84996c98f6-cvrbd  2/2  Running  3 (18h ago)  18h

 

NAME  TYPE  CLUSTER-IP  EXTERNAL-IP  PORT(S)  AGE

service/linkerd-identity  ClusterIP  10.152.183.137  <none>  8080/TCP  18h

service/linkerd-identity-headless  ClusterIP  None  <none>  8080/TCP  18h

service/linkerd-dst  ClusterIP  10.152.183.130  <none>  8086/TCP  18h

service/linkerd-dst-headless  ClusterIP  None  <none>  8086/TCP  18h

service/linkerd-sp-validator  ClusterIP  10.152.183.107  <none>  443/TCP  18h

service/linkerd-policy  ClusterIP  None  <none>  8090/TCP  18h

service/linkerd-policy-validator  ClusterIP  10.152.183.2  <none>  443/TCP  18h

service/linkerd-proxy-injector  ClusterIP  10.152.183.207  <none>  443/TCP  18h

 

NAME  READY  UP-TO-DATE  AVAILABLE  AGE

deployment.apps/linkerd-identity  1/1  1  1  18h

deployment.apps/linkerd-destination  1/1  1  1  18h

deployment.apps/linkerd-proxy-injector  1/1  1  1  18h

 

NAME  DESIRED  CURRENT  READY  AGE

replicaset.apps/linkerd-identity-778bd797b9  1  1  1  18h

replicaset.apps/linkerd-destination-5bc458558c  1  1  1  18h

replicaset.apps/linkerd-proxy-injector-84996c98f6  1  1  1  18h

 

NAME  SCHEDULE  SUSPEND  ACTIVE  LAST SCHEDULE  AGE

cronjob.batch/linkerd-heartbeat  29 14 * * *  False  0  <none>  18h

 

 

$ kubectl get all -n linkerd-viz

NAME  READY  STATUS  RESTARTS  AGE

pod/tap-injector-74859d5d6f-g2bxq  2/2  Running  2 (18h ago)  18h

pod/tap-64dcc6f597-wmgzn  2/2  Running  3 (18h ago)  18h

pod/prometheus-7c87db76d8-qtjwz  2/2  Running  2 (18h ago)  18h

pod/metrics-api-799cf8c6d4-w66kx  2/2  Running  3 (18h ago)  18h

pod/grafana-566598d49d-48588   2/2  Running  0  8m34s

 

NAME  TYPE  CLUSTER-IP  EXTERNAL-IP  PORT(S)  AGE

service/metrics-api  ClusterIP  10.152.183.145  <none>  8085/TCP  18h

service/grafana  ClusterIP  10.152.183.210  <none>  3000/TCP  18h

service/prometheus  ClusterIP  10.152.183.122  <none>  9090/TCP  18h

service/tap  ClusterIP  10.152.183.8  <none>  8088/TCP,443/TCP  18h

service/tap-injector  ClusterIP  10.152.183.108  <none>  443/TCP  18h

 

NAME  READY  UP-TO-DATE  AVAILABLE  AGE

deployment.apps/tap-injector  1/1  1  1  18h

deployment.apps/tap  1/1  1  1  18h

deployment.apps/prometheus  1/1  1  1  18h

deployment.apps/metrics-api  1/1  1  1  18h

deployment.apps/grafana  1/1  1  1  18h

 

NAME  DESIRED  CURRENT  READY  AGE

replicaset.apps/tap-injector-74859d5d6f  1  1  1  18h

replicaset.apps/tap-64dcc6f597  1  1  1  18h

replicaset.apps/prometheus-7c87db76d8  1  1  1  18h

replicaset.apps/metrics-api-799cf8c6d4  1  1  1  18h

replicaset.apps/grafana-566598d49d  1  1  1  18h

 

 

Es gibt jetzt einen zweiten Prometheus und ein zweites Grafana. Sieht soweit gut aus.

 

Linkerd unterstützt folgende Kommandos:

 

alfred@pc1:~$ microk8s linkerd

linkerd manages the Linkerd service mesh.

 

Usage:

 linkerd [command]

 

Available Commands:

 authz  List server authorizations for a resource

 check  Check the Linkerd installation for potential problems

 completion  Output shell completion code for the specified shell (bash, zsh or fish)

 diagnostics  Commands used to diagnose Linkerd components

 help  Help about any command

 identity  Display the certificate(s) of one or more selected pod(s)

 inject  Add the Linkerd proxy to a Kubernetes config

 install  Output Kubernetes configs to install Linkerd

 install-cni  Output Kubernetes configs to install Linkerd CNI

 jaeger  jaeger manages the jaeger extension of Linkerd service mesh

 multicluster Manages the multicluster setup for Linkerd

 profile  Output service profile config for Kubernetes

 repair  Output the secret/linkerd-config-overrides resource if it has been deleted

 uninject  Remove the Linkerd proxy from a Kubernetes config

 uninstall  Output Kubernetes resources to uninstall Linkerd control plane

 upgrade  Output Kubernetes configs to upgrade an existing Linkerd control plane

 version  Print the client and server version information

 viz  viz manages the linkerd-viz extension of Linkerd service mesh

 

Flags:

 --api-addr string  Override kubeconfig and communicate directly with the control plane at host:port (mostly for testing)

 --as string  Username to impersonate for Kubernetes operations

 --as-group stringArray  Group to impersonate for Kubernetes operations

 --cni-namespace string  Namespace in which the Linkerd CNI plugin is installed (default "linkerd-cni")

 --context string  Name of the kubeconfig context to use

 -h, --help  help for linkerd

 --kubeconfig string  Path to the kubeconfig file to use for CLI requests

 -L, --linkerd-namespace string  Namespace in which Linkerd is installed ($LINKERD_NAMESPACE) (default "linkerd")

 --verbose  Turn on debug logging

 

Additional help topics:

 linkerd alpha  experimental subcommands for Linkerd

 

Use "linkerd [command] --help" for more information about a command.

alfred@pc1:~$

 

Wir installieren den Cluster Metrics-Stack

 

$ microk8s linkerd viz install | kubectl apply -f - # install the on-cluster metrics stack

namespace/linkerd-viz unchanged

clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-viz-metrics-api unchanged

clusterrolebinding.rbac.authorization.k8s.io/linkerd-linkerd-viz-metrics-api unchanged

serviceaccount/metrics-api unchanged

serviceaccount/grafana unchanged

clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-viz-prometheus unchanged

clusterrolebinding.rbac.authorization.k8s.io/linkerd-linkerd-viz-prometheus unchanged

serviceaccount/prometheus unchanged

clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-viz-tap unchanged

clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-viz-tap-admin unchanged

clusterrolebinding.rbac.authorization.k8s.io/linkerd-linkerd-viz-tap unchanged

clusterrolebinding.rbac.authorization.k8s.io/linkerd-linkerd-viz-tap-auth-delegator unchanged

serviceaccount/tap unchanged

rolebinding.rbac.authorization.k8s.io/linkerd-linkerd-viz-tap-auth-reader unchanged

secret/tap-k8s-tls configured

apiservice.apiregistration.k8s.io/v1alpha1.tap.linkerd.io configured

role.rbac.authorization.k8s.io/web unchanged

rolebinding.rbac.authorization.k8s.io/web unchanged

clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-viz-web-check unchanged

clusterrolebinding.rbac.authorization.k8s.io/linkerd-linkerd-viz-web-check unchanged

clusterrolebinding.rbac.authorization.k8s.io/linkerd-linkerd-viz-web-admin unchanged

clusterrole.rbac.authorization.k8s.io/linkerd-linkerd-viz-web-api unchanged

clusterrolebinding.rbac.authorization.k8s.io/linkerd-linkerd-viz-web-api unchanged

serviceaccount/web unchanged

server.policy.linkerd.io/admin unchanged

serverauthorization.policy.linkerd.io/admin unchanged

server.policy.linkerd.io/proxy-admin unchanged

serverauthorization.policy.linkerd.io/proxy-admin unchanged

service/metrics-api unchanged

deployment.apps/metrics-api configured

server.policy.linkerd.io/metrics-api unchanged

serverauthorization.policy.linkerd.io/metrics-api unchanged

configmap/grafana-config unchanged

service/grafana unchanged

deployment.apps/grafana configured

server.policy.linkerd.io/grafana unchanged

serverauthorization.policy.linkerd.io/grafana unchanged

configmap/prometheus-config unchanged

service/prometheus unchanged

deployment.apps/prometheus configured

service/tap unchanged

Warning: spec.template.spec.nodeSelector[beta.kubernetes.io/os]: deprecated since v1.14; use "kubernetes.io/os" instead

deployment.apps/tap configured

server.policy.linkerd.io/tap-api unchanged

serverauthorization.policy.linkerd.io/tap unchanged

clusterrole.rbac.authorization.k8s.io/linkerd-tap-injector unchanged

clusterrolebinding.rbac.authorization.k8s.io/linkerd-tap-injector unchanged

serviceaccount/tap-injector unchanged

secret/tap-injector-k8s-tls configured

mutatingwebhookconfiguration.admissionregistration.k8s.io/linkerd-tap-injector-webhook-config configured

service/tap-injector unchanged

deployment.apps/tap-injector configured

server.policy.linkerd.io/tap-injector-webhook unchanged

serverauthorization.policy.linkerd.io/tap-injector created

service/web created

deployment.apps/web created

serviceprofile.linkerd.io/metrics-api.linkerd-viz.svc.cluster.local created

serviceprofile.linkerd.io/prometheus.linkerd-viz.svc.cluster.local created

serviceprofile.linkerd.io/grafana.linkerd-viz.svc.cluster.local created

alfred@pc1:~$

 

Wir können die Installation sicherheitshalber prüfen.

 

$ microk8s linkerd check

Linkerd core checks

 

kubernetes-api

--------------

√ can initialize the client

√ can query the Kubernetes API

 

kubernetes-version

------------------

√ is running the minimum Kubernetes API version

√ is running the minimum kubectl version

 

linkerd-existence

-----------------

√ 'linkerd-config' config map exists

√ heartbeat ServiceAccount exist

√ control plane replica sets are ready

√ no unschedulable pods

√ control plane pods are ready

 

linkerd-config

--------------

√ control plane Namespace exists

√ control plane ClusterRoles exist

√ control plane ClusterRoleBindings exist

√ control plane ServiceAccounts exist

√ control plane CustomResourceDefinitions exist

√ control plane MutatingWebhookConfigurations exist

√ control plane ValidatingWebhookConfigurations exist

 

linkerd-identity

----------------

√ certificate config is valid

√ trust anchors are using supported crypto algorithm

√ trust anchors are within their validity period

√ trust anchors are valid for at least 60 days

√ issuer cert is using supported crypto algorithm

√ issuer cert is within its validity period

√ issuer cert is valid for at least 60 days

√ issuer cert is issued by the trust anchor

 

linkerd-webhooks-and-apisvc-tls

-------------------------------

√ proxy-injector webhook has valid cert

√ proxy-injector cert is valid for at least 60 days

√ sp-validator webhook has valid cert

√ sp-validator cert is valid for at least 60 days

√ policy-validator webhook has valid cert

√ policy-validator cert is valid for at least 60 days

 

linkerd-version

---------------

√ can determine the latest version

‼ cli is up-to-date

 is running version 2.11.1 but the latest stable version is 2.12.2

 see https://linkerd.io/2.11/checks/#l5d-version-cli for hints

 

control-plane-version

---------------------

√ can retrieve the control plane version

‼ control plane is up-to-date

 is running version 2.11.1 but the latest stable version is 2.12.2

 see https://linkerd.io/2.11/checks/#l5d-version-control for hints

√ control plane and cli versions match

 

linkerd-control-plane-proxy

---------------------------

√ control plane proxies are healthy

‼ control plane proxies are up-to-date

 some proxies are not running the current version:

                * linkerd-identity-778bd797b9-bm9gh (stable-2.11.1)

                * linkerd-destination-5bc458558c-lqsq2 (stable-2.11.1)

                * linkerd-proxy-injector-84996c98f6-cvrbd (stable-2.11.1)

 see https://linkerd.io/2.11/checks/#l5d-cp-proxy-version for hints

√ control plane proxies and cli versions match

 

Status check results are √

 

Linkerd extensions checks

 

linkerd-viz

-----------

√ linkerd-viz Namespace exists

√ linkerd-viz ClusterRoles exist

√ linkerd-viz ClusterRoleBindings exist

√ tap API server has valid cert

√ tap API server cert is valid for at least 60 days

√ tap API service is running

√ linkerd-viz pods are injected

√ viz extension pods are running

√ viz extension proxies are healthy

‼ viz extension proxies are up-to-date

 some proxies are not running the current version:

                * tap-64dcc6f597-wmgzn (stable-2.11.1)

                * prometheus-7c87db76d8-qtjwz (stable-2.11.1)

                * metrics-api-799cf8c6d4-w66kx (stable-2.11.1)

                * grafana-566598d49d-48588 (stable-2.11.1)

                * tap-injector-779cc8995-vrfh8 (stable-2.11.1)

                * web-6b4755c997-8fsh9 (stable-2.11.1)

                * tap-56d9d558c5-jnzjc (stable-2.11.1)

                * tap-injector-74859d5d6f-g2bxq (stable-2.11.1)

 see https://linkerd.io/2.11/checks/#l5d-viz-proxy-cp-version for hints

√ viz extension proxies and cli versions match

√ prometheus is installed and configured correctly

√ can initialize the client

√ viz extension self-check

 

Status check results are √

 

Sieht soweit gut aus. Jetzt ist auch die noch fehlende Web-Komponente eingerichtet.

 

$ kubectl get all -n linkerd-viz

NAME  READY  STATUS  RESTARTS  AGE

pod/prometheus-7c87db76d8-qtjwz  2/2  Running  2 (18h ago)  19h

pod/metrics-api-799cf8c6d4-w66kx  2/2  Running  3 (18h ago)  19h

pod/grafana-566598d49d-48588  2/2  Running  0  42m

pod/web-6b4755c997-8fsh9  2/2  Running  0  2m35s

pod/tap-56d9d558c5-jnzjc  2/2  Running  0  2m36s

pod/tap-injector-779cc8995-vrfh8  2/2  Running  0  2m36s

 

NAME  TYPE  CLUSTER-IP  EXTERNAL-IP  PORT(S)  AGE

service/metrics-api  ClusterIP  10.152.183.145  <none>  8085/TCP  19h

service/grafana  ClusterIP  10.152.183.210  <none>  3000/TCP  19h

service/prometheus  ClusterIP  10.152.183.122  <none>  9090/TCP  19h

service/tap  ClusterIP  10.152.183.8  <none>  8088/TCP,443/TCP  19h

service/tap-injector  ClusterIP  10.152.183.108  <none>  443/TCP  19h

service/web  ClusterIP  10.152.183.148  <none>  8084/TCP,9994/TCP  2m36s

 

NAME  READY  UP-TO-DATE  AVAILABLE  AGE

deployment.apps/prometheus  1/1  1  1  19h

deployment.apps/metrics-api  1/1  1  1  19h

deployment.apps/grafana  1/1  1  1  19h

deployment.apps/tap-injector  1/1  1  1  19h

deployment.apps/web  1/1  1  1  2m36s

deployment.apps/tap  1/1  1  1  19h

 

Es gibt noch ein paar Adaptionen zum Standard.

 

---

# Zugang mit admin/admin

apiVersion: v1

kind: Secret

type: Opaque

metadata:

 name: web-ingress-auth

 namespace: linkerd-viz

data:

 auth: YWRtaW46JGFwcjEkbjdDdTZnSGwkRTQ3b2dmN0NPOE5SWWpFakJPa1dNLgoK

---

# apiVersion: networking.k8s.io/v1beta1 # for k8s < v1.19

apiVersion: networking.k8s.io/v1

kind: Ingress

metadata:

 name: web-ingress

 namespace: linkerd-viz

 annotations:

 kubernetes.io/ingress.class: public

 cert-manager.io/cluster-issuer: letsencrypt

 nginx.ingress.kubernetes.io/upstream-vhost: $service_name.$namespace.svc.cluster.local:8084

 nginx.ingress.kubernetes.io/configuration-snippet: |

 proxy_set_header Origin "";

 proxy_hide_header l5d-remote-ip;

 proxy_hide_header l5d-server-id;

 nginx.ingress.kubernetes.io/auth-type: basic

 nginx.ingress.kubernetes.io/auth-secret: web-ingress-auth

 nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'

 nginx.ingress.kubernetes.io/whitelist-source-range: '127.0.0.1/8,169.254.0.0/16,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16'

spec:

 tls:

 - hosts:

 - viz.k8s.slainte.at

 secretName: viz-k8s-slainte-at-tls

 rules:

 - host: viz.k8s.slainte.at

 http:

 paths:

 - path: /

 pathType: Prefix

 backend:

 service:

 name: web

 port:

 number: 8084

---

 

Um den Zugang zum Linkerd-Dashboard zu ermöglichen, konfigurieren wirobigen Ingress. Dann rufen wir das ganze mit dem Browser auf.

 

Abbildung 5: Linkerd - Dashboard

 

Hier kann man die linkerd-enabled Namespaces sehen. Wir interessiern uns in diesem Beispiel für die pods im Namespace slainte.

 

$ k get pods -n slainte

NAME  READY  STATUS  RESTARTS  AGE

postgresdb-state-0  2/2  Running  0  18h

joomla-nginx-f84fbb988-p6ffx  2/2  Running  0  5m

joomla-fpm-5b67d5d99f-w2j4d  2/2  Running  0  5m

redis-0  2/2  Running  0  36s

 

Joomla wird in diesem Buch etwas weiter hinten beschrieben (aber mit irgendwas muss man ja anfangen).

 

Abbildung 6: Linkerd - Slainte

 

In diesem Namespace gibt es ein Frontend, ein Backend (fpm), eine Redis-DB und eine Postgres-DB. Wir werden uns das im Detail ansehen.

 

Abbildung 7: Linkerd - Slainte fpm

Durch auswählen des Grafana-Symboles kann man für einen bestimmten Pod alle Statistiken sehen.

 

Abbildung 8: Linkerd - Statefulset

Das funktioniert natürlich auch bei Gruppen (z.b. alle Pods eines Statefulsets oder eines Deploymennts).

 

Gut beschrieben ist der Linkerd auch im Buch "K8s Applications mit MicroK8S auf Raspberry PI" ISBN 978-3-7427-7013-4.

 

 

 

 

 

 

Prometheus und Grafana

Inspiration:

https://prometheus.io/docs/prometheus/latest/getting_started/

https://www.computerweekly.com/de/ratgeber/Wie-man-Prometheus-fuer-das-Kubernetes-Monitoring-einrichtet

https://grafana.com/tutorials/grafana-fundamentals/?utm_source=grafana_gettingstarted

https://grafana.com/grafana/plugins/?utm_source=grafana_plugin_list

https://requestbin.com/

https://docs.nginx.com/nginx-ingress-controller/logging-and-monitoring/prometheus/https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/blob/main/ClusterSetup/MicroK8SDashboard.sh

 

Prometheus und Grafana sind Bestandteil von microK8S. Im Skript https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/blob/main/ClusterSetup/MicroK8SDashboard.sh wird der Metric-Server,  Prometheus, Grafana und das Dashboard enabled. Um vernünftig auf die Services zugreifen zu können machen wir spezielle Ingresse.

 

kind: Ingress

apiVersion: networking.k8s.io/v1

metadata:

 name: prometheus-ingress

 namespace: monitoring

 annotations:

 kubernetes.io/ingress.class: public

 # type of authentication

 nginx.ingress.kubernetes.io/auth-type: basic

 # name of the secret that contains the user/password definitions - Ist hier dasselbe wie bei Grafana

 nginx.ingress.kubernetes.io/auth-secret: grafana-frontend

 # message to display with an appropriate context why the authentication is required

 nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required '

 # prevent the controller from redirecting (308) to HTTPS

 nginx.ingress.kubernetes.io/ssl-redirect: "true"

 nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

 cert-manager.io/cluster-issuer: letsencrypt-prod

 # https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/

 #  nginx.ingress.kubernetes.io/rewrite-target: /$2

 #  nginx.ingress.kubernetes.io/ssl-redirect: "true"

 #  nginx.ingress.kubernetes.io/ssl-temporary-redirect: "false"

 nginx.ingress.kubernetes.io/secure-backends: "true"

 nginx.ingress.kubernetes.io/ssl-proxy-headers: "X-Forwarded-Proto: https"

 #nginx.ingress.kubernetes.io/proxy-body-size: 0m

 #nginx.ingress.kubernetes.io/proxy-buffering: "off"

 nginx.ingress.kubernetes.io/backend-protocol: "HTTP"

 #  nginx.ingress.kubernetes.io/ssl-passthrough: "true"

 # https://github.com/nginxinc/kubernetes-ingress/tree/v1.12.0/examples/ssl-services

 #  nginx.ingress.kubernetes.io/ssl-services: "${image}-svc"

 nginx.ingress.kubernetes.io/whitelist-source-range: '127.0.0.1/8,169.254.0.0/16,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16'

spec:

 tls:

 - hosts:

 - prometheus.k8s.slainte.at

 secretName: prometheus-k8s-slainte-at

 rules:

 - host: prometheus.k8s.slainte.at

 http:

 paths:

 - path: /

 pathType: Prefix

 backend:

 service:

 name: prometheus-k8s

 port:

 number: 9090

sowie

 

kind: Ingress

apiVersion: networking.k8s.io/v1

metadata:

 name: grafana-ingress

 namespace: monitoring

 annotations:

 kubernetes.io/ingress.class: public

 # type of authentication

 nginx.ingress.kubernetes.io/auth-type: basic

 # name of the secret that contains the user/password definitions

 nginx.ingress.kubernetes.io/auth-secret: grafana-frontend

 # message to display with an appropriate context why the authentication is required

 nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required '

 # prevent the controller from redirecting (308) to HTTPS

 nginx.ingress.kubernetes.io/ssl-redirect: "true"

 nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

 cert-manager.io/cluster-issuer: letsencrypt-prod

 # https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/

 #  nginx.ingress.kubernetes.io/rewrite-target: /$2

 #  nginx.ingress.kubernetes.io/ssl-redirect: "true"

 #  nginx.ingress.kubernetes.io/ssl-temporary-redirect: "false"

 nginx.ingress.kubernetes.io/secure-backends: "true"

 nginx.ingress.kubernetes.io/ssl-proxy-headers: "X-Forwarded-Proto: https"

 #nginx.ingress.kubernetes.io/proxy-body-size: 0m

 #nginx.ingress.kubernetes.io/proxy-buffering: "off"

 nginx.ingress.kubernetes.io/backend-protocol: "HTTP"

 #  nginx.ingress.kubernetes.io/ssl-passthrough: "true"

 # https://github.com/nginxinc/kubernetes-ingress/tree/v1.12.0/examples/ssl-services

 #  nginx.ingress.kubernetes.io/ssl-services: "${image}-svc"

 nginx.ingress.kubernetes.io/whitelist-source-range: '127.0.0.1/8,169.254.0.0/16,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16'

spec:

 tls:

 - hosts:

 - grafana.k8s.slainte.at

 secretName: grafana-k8s-slainte-at

 rules:

 - host: grafana.k8s.slainte.at

 http:

 paths:

 - path: /

 pathType: Prefix

 backend:

 service:

 name: grafana

 port:

 number: 3000

 

Das Dashboard bringt ja seinen eigenen Ingress mit. In diesem Setup haben beide Services unterschiedliche URL's, jeder hat sein eigenes Zertifikat, beide haben aber diesselben Passworte (bzw. diesselbe Passwortkonfiguration). Aus Sicherheitsgründen sind beide nur lokal erreichbar.

 

Die Passworte werden im Keepass definiert.

 

Abbildung 9: Keepass - Grafana Frontend

Die Type-Konfiguration erfolgt dann am Karteiblatt "Fortgeschritten".

 

Abbildung 10: Keepass - Grafana Basic Auth

Diese Konfiguration wird dann mit unserem Java-Programm (beschrieben in "K8s Applications mit MicroK8S auf Raspberry PI" ISBN 978-3-7427-7013-4) in ein Secret umgewandelt.

 

apiVersion: v1

kind: Secret

metadata:

 name: grafana-frontend

 namespace: monitoring

 labels:

 managed-by: keepassxc

 generated: 2022-01-27

type: Opaque

data:

---

 

Und kann dann verwendet werden.

 

 

Abbildung 11: Grafana - Url Passwort

Nach erfolgreicher Anmeldung kann der Service dann benutzt werden.

 

Abbildung 12: Grafana - NodeExporter

Dasselbe gilt auch für den Zugang zum Prometheus Frontend.

 

GrafanaDashboards - Import und Export

Inspiration:

https://gist.github.com/crisidev/bd52bdcc7f029be2f295

https://grafana.com/docs/grafana/latest/http_api/dashboard/#create-update-dashboard

https://github.com/monitoringartist/grafana-utils

 

Wie Grafana aufgesetzt wird und konfigiert werden kann, ist im Vorgängerbuch beschrieben. Grafana ist Teil des automatischen Cluster-Setups https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/blob/main/ClusterSetup/ClusterSetup.sh .

 

Aber wenn der Cluster neu aufgesetzt wird, hat man ein leeres Grafana. Alle Dashboards (und die Änderungen darin) sind dann verloren. Damit das nicht geschieht, gibt es die Skripts auf https://gitlab.com/Alfred-Sabitzer/mikrok8s/-/tree/main/Grafana

 

#!/bin/bash

############################################################################################

#

# MicroK8S Exportieren aller Grafana Dashboards

# https://gist.github.com/crisidev/bd52bdcc7f029be2f295

#

# Dazu muß händisch das Passwort im Grafana eingetragen werden, dass in monitoring/grafana-frontend-api im Keepassx registriert ist

#

############################################################################################

#shopt -o -s errexit  #—Terminates  the shell script  if a command returns an error code.

#shopt -o -s xtrace #—Displays each command before it’s executed.

shopt -o -s nounset #-No Variables without definition

indir=$(dirname "$0")

workdir=$(pwd)

#

secret=$(kubectl get secret -n monitoring grafana-frontend-api -o json | jq -c '. | {data}' )

#

apiurl=${secret#*"apiUrl\":\""}

apiurl=${apiurl%"\",\"password\""*}

apiurl=$(echo ${apiurl} | base64 -d)

apiurl=${apiurl#*"https://"}

#

password=${secret#*"password\":\""}

password=${password%"\",\"username\""*}

password=$(echo ${password} | base64 -d)

#

username=${secret#*"username\":\""}

username=${username%"\"}}"*}

username=$(echo ${username} | base64 -d)

#

cmd="kubectl -n monitoring port-forward service/grafana 3000:3000"

${cmd} &

pid=$!

sleep 3s

#

# Iterate through dashboards using the current Connection

for dashboard_uid in $(curl -sS -L http://${username}:${password}@localhost:3000/api/search\?query\=\& | jq -r '.[] | select( .type | contains("dash-db")) | .uid'); do

 url="http://${username}:${password}@localhost:3000/api/dashboards/uid/$dashboard_uid"

 dashboard_json=$(curl -sS $url)

 echo "${dashboard_json}"  > x.json

 

 dashboard_title=$(echo ${dashboard_json} | jq -r '.dashboard | .title' | sed -r 's/[ \/]+/_/g' )

 dashboard_version=$(echo ${dashboard_json} | jq -r '.dashboard | .version')

 folder_title="$(echo ${dashboard_json} | jq -r '.meta | .folderTitle')"

 echo "./${folder_title}/${dashboard_title}_v${dashboard_version}.json"

 mkdir -p "./${folder_title}"

 echo "${dashboard_json}" > ./${folder_title}/${dashboard_title}_v${dashboard_version}.json

done

#

kill ${pid}

#

# Jetzt sind alle Dashboards exportiert

#

 

Dieses Skript exportiert alle Dashboards aus allen Ordnern und speichert sie lokal ab.

 

#!/bin/bash

############################################################################################

#

# MicroK8S Importieren aller Grafana Dashboards

#

# https://grafana.com/docs/grafana/latest/http_api/dashboard/#create-update-dashboard

# https://github.com/monitoringartist/grafana-utils

#

# Dazu muß händisch das Passwort im Grafana eingetragen werden, dass in monitoring/grafana-frontend-api im Keepassx registriert ist

#

############################################################################################

#shopt -o -s errexit  #—Terminates  the shell script  if a command returns an error code.

#shopt -o -s xtrace #—Displays each command before it’s executed.

shopt -o -s nounset #-No Variables without definition

#

secret=$(kubectl get secret -n monitoring grafana-frontend-api -o json | jq -c '. | {data}' )

#

apiurl=${secret#*"apiUrl\":\""}

apiurl=${apiurl%"\",\"password\""*}

apiurl=$(echo ${apiurl} | base64 -d)

apiurl=${apiurl#*"https://"}

#

password=${secret#*"password\":\""}

password=${password%"\",\"username\""*}

password=$(echo ${password} | base64 -d)

#

username=${secret#*"username\":\""}

username=${username%"\"}}"*}

username=$(echo ${username} | base64 -d)

#

cmd="kubectl -n monitoring port-forward service/grafana 3000:3000"

${cmd} &

pid=$!

sleep 3s

FILES="./General/*.json

"

#

for filename in $FILES ; do

 if [ -f "${filename}" ]

 then

 echo ${filename}

 cat ${filename} | jq '. * {overwrite: true, dashboard: {id: null}}' | curl -L -X POST -H "Content-Type: application/json" http://${username}:${password}@localhost:3000/api/dashboards/db -d @-

 fi

done

#

kill ${pid}

#

# Jetzt sind alle Dashboards verfügbar

#

 

Dieses Skript lädt die Reports wieder. OK, hier wird hardcoded auf den Ordner "General" eingeschränkt, aber das lässt sich leicht ändern.

 

Somit kann nach dem Einrichten von Grafana (das Passwort und der User müssen dem Secret grafana-frontend-api entsprechen. Da wir aber auch einenm mit Passwort geschützten Ingress haben (der eine andere Verschlüsselung braucht), muß dass in unserem Keepassx richtig eingerichtet werden.

 

Abbildung 13: Grafana - Keepassx

 

Dieselbe Username/Passwort-Kombination wird in zwei Secrets gleichzeitig gespeichert. Einmal in das Secret grafana-frontend-api und einmal in das Secret grafana-frontend. Das sieht dann so aus.

 

---

apiVersion: v1

kind: Secret

metadata:

 name: grafana-frontend-api

 namespace: monitoring

 labels:

 managed-by: keepassxc

 generated: 2022-01-31

type: Opaque

data:

 apiUrl: aHR0cHM6Ly9ncmFmYW5hLms4cy5zbGFpbnRlLmF0

 password: VXRzclBYdm1FUVYzczZqM05Tb0FIVk5w

---

 

apiVersion: v1

kind: Secret

metadata:

 name: grafana-frontend

 namespace: monitoring

 labels:

 managed-by: keepassxc

 algorithm: MD5

 generated: 2022-01-27

type: Opaque

data:

---

 

Mit diesen Skripts kann man dann Dashboards auch leicht von einer Umgebung auf eine andere transportieren.

 

Kubernetes Management-Dashboard

Inspiration:

https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/

 

Um das mitgelieferte Management-Dashboard nutzen zu können, gibt es das Skript MicroK8SDashboard.sh. Dort wird neben Grafan auch das Kubernetes-Dashboard eingerichtet.

 

#!/bin/bash

############################################################################################

#

# MicroK8S Einrichten des Dashboards, Prometheus und Metrics Services

#

############################################################################################

#shopt -o -s errexit  #—Terminates  the shell script  if a command returns an error code.

shopt -o -s xtrace #—Displays each command before it’s executed.

shopt -o -s nounset #-No Variables without definition

indir=$(dirname "$0")

# Disablen

ansible pc1 -m shell -a 'microk8s disable dashboard-ingress  '  # Ingress definition for Kubernetes dashboard

ansible pc1 -m shell -a 'microk8s disable dashboard  '  # The Kubernetes dashboard

ansible pc1 -m shell -a 'microk8s disable prometheus '  # Prometheus operator for monitoring and logging

ansible pc1 -m shell -a 'microk8s disable metrics-server '  # K8s Metrics Server for API access to service metrics

kubectl delete -f ${indir}/dashboard-service-account.yaml  # Token für den Serviceaccount

kubectl delete -f ${indir}/grafana-ingress.yaml  # Ingress-Definition

kubectl delete -f ${indir}/prometheus-ingress.yaml  # Ingress-Definition

kubectl delete -f ${indir}/monitoring_grafana-frontend.yaml  # Secret

kubectl delete -f ${indir}/monitoring_grafana-frontend-api.yaml # Secret

ansible pc -m shell -a 'microk8s status --wait-ready'

${indir}/check_running_pods.sh

${indir}/cluster_reboot.sh

ansible-playbook -v ${indir}/check_hosts.yaml

ansible pc -m shell -a 'sudo /root/MicroK8S_Start.sh '

${indir}/check_running_pods.sh

# Enable

ansible pc1 -m shell -a 'microk8s enable metrics-server '  # K8s Metrics Server for API access to service metrics

${indir}/cluster_reboot.sh

ansible-playbook -v ${indir}/check_hosts.yaml

ansible pc -m shell -a 'sudo /root/MicroK8S_Start.sh '

${indir}/check_running_pods.sh

ansible pc1 -m shell -a 'microk8s enable prometheus '  # Prometheus operator for monitoring and logging

ansible pc1 -m shell -a 'microk8s enable dashboard  '  # The Kubernetes dashboard

kubectl apply -f ${indir}/dashboard-service-account.yaml  # Token für den Serviceaccount

kubectl apply -f ${indir}/monitoring_grafana-frontend.yaml  # Secret

kubectl apply -f ${indir}/monitoring_grafana-frontend-api.yaml # Secret

kubectl apply -f ${indir}/grafana-ingress.yaml  # Ingress-Definition

kubectl apply -f ${indir}/prometheus-ingress.yaml  # Ingress-Definition

ansible pc -m shell -a 'microk8s enable community '  # Ermöglichen der Zusatzfeatures

ansible pc1 -m shell -a 'microk8s enable dashboard-ingress  '  # Ingress definition for Kubernetes dashboard

kubectl apply -f ${indir}/namespaces.yaml  # Einspielen der Standard-Namespaces

kubectl apply -f ${indir}/clusterrole-prometheus-k8s.yaml  # Erweiterte Rechte für den Prometheus

ansible pc -m shell -a 'microk8s status --wait-ready'

# Anzeigen der Tokens

#kubectl -n kube-system describe secret $(microk8s kubectl -n kube-system get secret | grep default-token | cut -d " " -f1)

#kubectl -n kube-system get secret $(kubectl -n kube-system get sa/admin-user -o jsonpath="{.secrets[0].name}") -o go-template="{{.data.token | base64decode}}"

#kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print \$1}')

${indir}/check_running_pods.sh

#

# Jetzt sind alle Standard-Services verfügbar

#

# kubernetes-dashboard.127.0.0.1.nip.io in die /etc/hosts Datei eintragen, und man kann über den Ingress auf das Dashboard zugreifen

#Dieses Skript legt die richtigen Ingresse an. Die Community ist schon so nett, und legt den Ingress für das Kubernetes Dashboard richtig an.

 

kind: Ingress

apiVersion: networking.k8s.io/v1

metadata:

 name: kubernetes-dashboard-ingress

 namespace: kube-system

 uid: 3ea80fa2-c7ce-4bd2-92ea-e627dd99fede

 resourceVersion: '331883'

 generation: 1

 creationTimestamp: '2022-09-01T13:07:52Z'

 annotations:

 kubectl.kubernetes.io/last-applied-configuration: >

 {"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"public","nginx.ingress.kubernetes.io/backend-protocol":"HTTPS","nginx.ingress.kubernetes.io/force-ssl-redirect":"true","nginx.ingress.kubernetes.io/ssl-passthrough":"true","nginx.ingress.kubernetes.io/whitelist-source-range":"127.0.0.1/8,169.254.0.0/16,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"},"name":"kubernetes-dashboard-ingress","namespace":"kube-system"},"spec":{"rules":[{"host":"kubernetes-dashboard.127.0.0.1.nip.io","http":{"paths":[{"backend":{"service":{"name":"kubernetes-dashboard","port":{"number":443}}},"path":"/","pathType":"Prefix"}]}}]}}

 kubernetes.io/ingress.class: public

 nginx.ingress.kubernetes.io/backend-protocol: HTTPS

 nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'

 nginx.ingress.kubernetes.io/ssl-passthrough: 'true'

 nginx.ingress.kubernetes.io/whitelist-source-range: '127.0.0.1/8,169.254.0.0/16,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16'

 managedFields:

 - manager: kubectl-client-side-apply

 operation: Update

 apiVersion: networking.k8s.io/v1

 time: '2022-09-01T13:07:52Z'

 fieldsType: FieldsV1

 fieldsV1:

 'f:metadata':

 'f:annotations':

 .: {}

 'f:kubectl.kubernetes.io/last-applied-configuration': {}

 'f:kubernetes.io/ingress.class': {}

 'f:nginx.ingress.kubernetes.io/backend-protocol': {}

 'f:nginx.ingress.kubernetes.io/force-ssl-redirect': {}

 'f:nginx.ingress.kubernetes.io/ssl-passthrough': {}

 'f:nginx.ingress.kubernetes.io/whitelist-source-range': {}

 'f:spec':

 'f:rules': {}

 - manager: nginx-ingress-controller

 operation: Update

 apiVersion: networking.k8s.io/v1

 time: '2022-09-01T13:08:36Z'

 fieldsType: FieldsV1

 fieldsV1:

 'f:status':

 'f:loadBalancer':

 'f:ingress': {}

 subresource: status

 selfLink: >-

 /apis/networking.k8s.io/v1/namespaces/kube-system/ingresses/kubernetes-dashboard-ingress

spec:

 rules:

 - host: kubernetes-dashboard.127.0.0.1.nip.io

 http:

 paths:

 - path: /

 pathType: Prefix

 backend:

 service:

 name: kubernetes-dashboard

 port:

 number: 443

status:

 loadBalancer:

 ingress:

                - ip: 127.0.0.1

 

Netterweise ist der Ingress gleich mit einer whitelist versehen. Man könnte das natürlich anpassen, aber das bleibt jedem selbst überlassen.

Abbildung 14: Kubernetes Dashboard - Login

Wenn man den Aufruft, wird man aufgefordert sich zu authentifizieren. Man kann das generierte Token verwenden, oder nimmt praktischerweise die bereits vorhandene lokale config-Datei.

 

Abbildung 15: Kubernetes Dashboard - Services

 

Danach kann man den Kubernetes-Cluster inspizieren.