5,99 €
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:
Seitenzahl: 313
Veröffentlichungsjahr: 2022
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.
