paint-brush
Kuma Meshes Frontal – Alles, was Sie wissen müssenby@jesperancinha
640
640

Kuma Meshes Frontal – Alles, was Sie wissen müssen

João Esperancinha27m2024/04/13
Read on Terminal Reader

Um schnell mit dem Erlernen von Kuma beginnen zu können, benötigen wir vor allem einen Cluster. Außerdem benötigen wir einen Befehl, um den Status unserer Pods in Kubernetes (auch bekannt als k8s) herauszufinden.
featured image - Kuma Meshes Frontal – Alles, was Sie wissen müssen
João Esperancinha HackerNoon profile picture
0-item
1-item

Kuma Meshes frontal – Ein Leitfaden für Anfänger

Um schnell mit dem Erlernen Kuma beginnen zu können, benötigen wir vor allem einen Cluster. Außerdem benötigen wir einen Befehl, um den Status unserer Pods in Kubernetes (auch bekannt als k8s ) herauszufinden, wir müssen Kuma installieren können und schließlich müssen wir auch in der Lage sein, einige Kuma Befehle auszugeben.


Damit ist umständlich gesagt, dass wir 4 wichtige Befehle installieren müssen, um alles für Kuma vorzubereiten. Diese Befehle sind:

  • kind - Dies wird in Docker auch als Kubernetes bezeichnet. Dies ist ein Befehl, der die Last der Erstellung von Inhalten nur mit kubectl nutzt.


  • kubectl – Wahrscheinlich das am häufigsten erwartete Tool auf dieser Liste, wenn Sie bereits mit der Arbeit mit k8s vertraut sind. So können wir Befehle an unseren k8s Cluster senden.


  • helm – Helm ermöglicht uns die Ausführung einiger sehr praktischer Skripte, die unter anderem die Installation der Kuma Steuerebene ermöglichen.


  • kumactl – Wir werden diesen Befehl in diesem Handbuch nicht sehr oft verwenden, aber es ist wichtig zu wissen, wie man ihn verwendet.


In dieser Anleitung erfahren Sie, wie Sie dies in Ubuntu tun. All dies wurde in einem Ubuntu System getestet. Wenn Sie an einer Anleitung zur Installation unter Mac-OS oder Windows oder einem anderen Betriebssystem interessiert sind, das Sie möglicherweise haben, geben Sie mir bitte auf meinem YouTube-Kanal JESPROTECH Community Bescheid.


I. Installieren der Befehle


Bildbeschreibung


Art ( k8s ) in Docker

Um kind zu installieren, müssen wir diese Befehle eingeben:

 [ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64 chmod +x ./kind sudo mv ./kind /usr/local/bin/kind


Es ist wichtig zu beachten, dass der Befehl kind in /usr/local/bin/kind installiert wird. Dies kann je nach System unterschiedlich sein, sogar innerhalb von Linux-Distributionen.


Installieren von Zertifikaten und GPG-Schlüsseln

Sowohl helm als auch kubectl Befehle müssen mit bestimmten GPG Schlüsseln installiert werden. So können wir sie zu unserem lokalen Repository unserer Linux- apt Distribution hinzufügen:

 sudo apt-get install -y apt-transport-https ca-certificates curl gpg curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list sudo apt-get update



kubectl

Die Installation von Kubectl ist sehr einfach, sobald der vorherige Schritt abgeschlossen ist:

 sudo apt-get install -y kubelet kubeadm kubectl


Die Befehle kubelet , kubeadm und kubectl sind nicht obligatorisch, aber es ist eine gute Idee, sie zu installieren.


Helm

Wie Sie vielleicht schon vermutet haben, ist helm jetzt auch sehr einfach zu installieren:

 sudo apt-get install -y helm

kuma

Die Installation Kuma kann etwas umständlich sein, da sie einen manuellen Schritt umfasst. Zuerst müssen wir unsere Abhängigkeiten herunterladen:

 cd ~ || exit; curl -L https://kuma.io/installer.sh | VERSION=2.6.1 sh -


Stellen Sie sicher, dass Sie sich in Ihrem HOME Ordner befinden, bevor Sie diesen Befehl ausführen. Es ist wichtig, Kuma an einem Ort zu installieren, an dem es leicht zugänglich und leicht zu finden ist, falls wir uns beispielsweise entscheiden, es zu entfernen.


Wenn wir damit fertig sind, ist es auch sehr wichtig, den bin Ordner zu unserem PATH hinzuzufügen:

 export PATH=~/kuma-2.6.1/bin:$PATH;


Wenn Sie diese Zeile am Ende oder irgendwo dazwischen in Ihr Startskript einfügen, wird dieser Vorgang vereinfacht. Ihr Startskript kann eine der folgenden Formen haben: .bashrc , .zshrc , .profile und möglicherweise auch eine andere.


k9s

Auch die Installation k9s unterscheidet sich erheblich von anderen Anwendungen. In diesem Fall können wir entweder pacman oder brew für Linux verwenden. Ich habe brew hauptsächlich für Mac-OS verwendet und es unter Linux kaum jemals benötigt, aber in diesem Fall ist es dringend erforderlich. Um dies zu tun, müssen wir Brew zunächst wie folgt installieren:

 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"


Sobald die Brew-Installation abgeschlossen ist, müssen wir nur noch k9s (" kanines ") installieren:

 brew install derailed/k9s/k9s


Dabei muss unbedingt Folgendes berücksichtigt werden (und Sie werden es wahrscheinlich bemerken, wenn Sie k9s zum ersten Mal installieren und ausführen): k9s stürzt ab, wenn ein von ihm überwachter Cluster entfernt und/oder hinzugefügt wird.


II. Erstellen des Clusters

 kind create cluster --name=wlsm-mesh-zone kubectl cluster-info --context kind-wlsm-mesh-zone


Der erste Befehl erstellt einen Cluster mit dem Namen wlsm-mesh-zone . Dies ist nur ein Cluster, den wir zur Installation von Kuma verwenden werden. Der zweite Befehl wird verwendet, um den Status des Clusters zu überprüfen.


III. Erstellen eines lokalen Docker-Verzeichnisses

Wie ich bereits erwähnt habe, können wir ganz einfach ein Docker-Register erstellen. So einfach es auch klingen mag, es zu erstellen, das Skript dafür ist eine Handvoll. Am besten kopieren und fügen Sie einfach das Skript ein, das bereits auf der Website verfügbar ist. Hier können wir dieses Skript herunterladen:

 #!/bin/sh # Original Source # https://creativecommons.org/licenses/by/4.0/ # https://kind.sigs.k8s.io/docs/user/local-registry/ set -o errexit # 1. Create registry container unless it already exists reg_name='kind-registry' reg_port='5001' if [ "$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" != 'true' ]; then docker run \ -d --restart=always -p "127.0.0.1:${reg_port}:5000" --network bridge --name "${reg_name}" \ registry:2 fi # 2. Create kind cluster with containerd registry config dir enabled # TODO: kind will eventually enable this by default and this patch will # be unnecessary. # # See: # https://github.com/kubernetes-sigs/kind/issues/2875 # https://github.com/containerd/containerd/blob/main/docs/cri/config.md#registry-configuration # See: https://github.com/containerd/containerd/blob/main/docs/hosts.md cat <<EOF | kind create cluster --config=- kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 containerdConfigPatches: - |- [plugins."io.containerd.grpc.v1.cri".registry] config_path = "/etc/containerd/certs.d" EOF # 3. Add the registry config to the nodes # # This is necessary because localhost resolves to loopback addresses that are # network-namespace local. # In other words: localhost in the container is not localhost on the host. # # We want a consistent name that works from both ends, so we tell containerd to # alias localhost:${reg_port} to the registry container when pulling images REGISTRY_DIR="/etc/containerd/certs.d/localhost:${reg_port}" for node in $(kind get nodes); do docker exec "${node}" mkdir -p "${REGISTRY_DIR}" cat <<EOF | docker exec -i "${node}" cp /dev/stdin "${REGISTRY_DIR}/hosts.toml" [host."http://${reg_name}:5000"] EOF done # 4. Connect the registry to the cluster network if not already connected # This allows kind to bootstrap the network but ensures they're on the same network if [ "$(docker inspect -f='{{json .NetworkSettings.Networks.kind}}' "${reg_name}")" = 'null' ]; then docker network connect "kind" "${reg_name}" fi # 5. Document the local registry # https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ConfigMap metadata: name: local-registry-hosting namespace: kube-public data: localRegistryHosting.v1: | host: "localhost:${reg_port}" help: "https://kind.sigs.k8s.io/docs/user/local-registry/" EOF



Dieses Skript befindet sich imStammordner des Projekts . Und um die lokale Docker-Registrierung zu installieren, müssen wir nur dieses Bash-Skript ausführen.


IV. Wie der Code erstellt wurde

Zu dem Code, den ich als Beispiel für diesen Blogbeitrag bereitgestellt habe, gibt es vielleicht noch viel zu sagen. In diesem Fall konzentrieren wir uns jedoch nur auf einige wichtige Aspekte. Beginnen wir mit demListener-Dienst, gehen zum Collector und dann zurDatenbank . Wenn wir die Dienste lokal ausführen oder sogar eine docker-compose -Konfiguration verwenden, um die Container zum Laufen zu bringen, verwenden wir normalerweise die DNS-zugewiesenen Namen, die automatisch als Containername oder als Name zugewiesen werden, den wir mit hostname konfigurieren.


Bei k8s gibt es außerdem einen Satz von Regeln, die die Hostnamen im gesamten Cluster verfügbar machen. Schauen wir uns die Listener- und Collector-Beispiele an:


Listener-Beispiel

Der Listener ist eine in Java mit dem Spring framework entwickelte Anwendung. Wie bei allen auf diese Weise erstellten Anwendungen gibt es auch hier eine Datei application.properties :

 spring.application.name=wlsm-listener-service server.port=8080 spring.main.web-application-type=reactive spring.webflux.base-path=/app/v1/listener wslm.url.collector=http://localhost:8081/api/v1/collector


Von all diesen Eigenschaften ist die Eigenschaft wslm.url.collector die wichtigste, auf die wir uns im Moment konzentrieren sollten. Mit der default können wir diesen Dienst lokal ausführen, ohne eine Containerumgebung verwenden zu müssen. Im k8s Cluster müssen wir jedoch auf den collector zugreifen können, und dafür haben wir ein prod Profil mit der Definitionsdatei application-prod.properties :

 wslm.url.collector=http://wlsm-collector-deployment.wlsm-namespace.svc.cluster.local:8081/api/v1/collector


Diese Eigenschaft versucht, den Host wlsm-collector-deployment.wlsm-namespace.svc.cluster.local zu erreichen. Diese Datei folgt dieser Konfiguration:

<Service Name>.<Namespace>.svc.cluster.local

Wir haben 5 durch Punkte getrennte Elemente. Die letzten drei sind statisch und die ersten beiden hängen von der Maschine ab, die wir erreichen möchten. Auf der linken Seite platzieren wir den Dienstnamen, gefolgt vom Namespace. Dies ist wichtig, um zu verstehen, wie die Container innerhalb des Clusters miteinander verbunden sind.


Der interessante Teil des Codes ist natürlich der Controller und der Dienst. Der Controller sieht folgendermaßen aus:

 @RestController @RequestMapping public class ListenerController { private final ListenerService listenerService; ListenerController(ListenerService listenerService) { this.listenerService = listenerService; } @GetMapping("info") public String info() { return "Listener Service V1"; } @PostMapping("create") public Mono<AnimalLocationDto> sendAnimalLocation( @RequestBody AnimalLocationDto animalLocationDto) { return listenerService.persist(animalLocationDto); } }


Und so sieht der Service aus:

 @Service public class ListenerService { @Value("${wslm.url.collector:http://localhost:8080}") private String collectorUrl; private final WebClient client = WebClient.create(collectorUrl); HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(); List<AnimalLocationDto> cache = hazelcastInstance.getList("data"); public Mono<AnimalLocationDto> persist(AnimalLocationDto animalLocationDto) { cache.add(animalLocationDto); return client.post() .uri(collectorUrl.concat("/animals")) .contentType(MediaType.APPLICATION_JSON) .bodyValue(animalLocationDto) .retrieve() .bodyToMono(AnimalLocationDto.class); } }


Wie Sie vielleicht schon bemerkt haben, ist diese erste Anwendung, wie alle mit dem Spring Framework in diesem Repository implementierten Anwendungen, reaktiv und sie alle verwenden netty statt tomcat . Im Moment können wir die Verwendung von hazelcast in diesem Code ignorieren. Dies wird für spätere Versionen dieses Projekts verwendet.


Collector-Beispiel

Der Collector funktioniert an dieser Stelle genauso wie der Listener. Seine einzige Aufgabe besteht derzeit darin, Daten vom Listener an die Datenbank weiterzuleiten. Dazu muss der Collector nur genau wissen, wo sich die Datenbank befindet. Lassen Sie uns dieselbe Analyse für die application.properties file of this project durchführen:

 spring.application.name=wlsm-collector-service server.port=8081 spring.main.web-application-type=reactive spring.webflux.base-path=/api/v1/collector spring.r2dbc.url=r2dbc:postgresql://localhost:5432/wlsm spring.r2dbc.username=admin spring.r2dbc.password=admin spring.data.r2dbc.repositories.naming-strategy=org.springframework.data.relational.core.mapping.BasicRelationalPersistentEntityNamingStrategy spring.data.r2dbc.repositories.naming-strategy.table=org.springframework.data.relational.core.mapping.SnakeCaseNamingStrategy spring.data.r2dbc.repositories.naming-strategy.column=org.springframework.data.relational.core.mapping.SnakeCaseNamingStrategy


Diese Eigenschaften sind das Minimum, das erforderlich ist, um den Dienst zum Laufen zu bringen. Allerdings nur, um ihn lokal ausführen zu können. Und für diesen Dienst haben wir auch prod Profildatei, die wir uns hier in application-prod.properties ansehen können:

 spring.r2dbc.url=r2dbc:postgresql://wlsm-database-deployment.wlsm-namespace.svc.cluster.local:5432/wlsm


Die Datenbankverbindung bezieht sich in diesem Fall auf den Host der Datenbank:

wlsm-database-deployment.wlsm-namespace.svc.cluster.local


Das folgt wiederum der gleichen Analyse, die wir zuvor gesehen haben. Links sehen wir den Dienstnamen, gefolgt vom Namespace, der am Ende mit svc.cluster.local angehängt wird.


Und für diesen Dienst verwenden wir auch einen Controller und einen Dienst. Der Controller sieht folgendermaßen aus:

 @RestController @RequestMapping class CollectorController( val collectorService: CollectorService ) { @PostMapping("animals") suspend fun listenAnimalLocation(@RequestBody animalLocationDto: AnimalLocationDto): AnimalLocationDto = run { collectorService.persist(animalLocationDto) animalLocationDto } }


Und so sieht der Service aus:

 @Service class CollectorService( val applicationEventPublisher: ApplicationEventPublisher ) { fun persist(animalLocationDto: AnimalLocationDto) = applicationEventPublisher.publishEvent(AnimalLocationEvent(animalLocationDto)) }


Der Dienst verwendet einen Ereignis-Publisher namens applicationEventPublisher , der einer Ereignis-Streaming-Architektur folgt, die später in diesem Ereignis-Listener behandelt wird. Wir können leicht erkennen, dass er r2dbc verwendet, um die Paradigmen der reaktiven Architekturimplementierung beizubehalten:

 @Service class EventHandlerService( val animalLocationDao: AnimalLocationDao ) { @EventListener fun processEvent(animalLocationEvent: AnimalLocationEvent){ println(animalLocationEvent) runBlocking(Dispatchers.IO) { animalLocationDao.save(animalLocationEvent.animalLocationDto.toEntity()) } } }



V. Skripte bereitstellen

Das Bereitstellen ist bei k8s normalerweise eine sehr unkomplizierte Aufgabe. Es ist jedoch auch wichtig, einen Blick auf die für unsere Dienste erforderliche Konfiguration zu werfen. Schauen wir uns beispielsweise die Listener-Implementierung an:

 apiVersion: v1 kind: Namespace metadata: name: wlsm-namespace labels: kuma.io/sidecar-injection: enabled --- apiVersion: apps/v1 kind: Deployment metadata: name: wlsm-listener namespace: wlsm-namespace spec: replicas: 1 selector: matchLabels: app: wlsm-listener template: metadata: labels: app: wlsm-listener spec: containers: - name: wlsm-listener-service image: localhost:5001/wlsm-listener-service:latest imagePullPolicy: Always ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: wlsm-listener-deployment namespace: wlsm-namespace spec: selector: app: wlsm-listener ports: - protocol: TCP appProtocol: http port: 8080


Diese Konfiguration besteht aus drei Blöcken. Der erste Block ist der Namespace-Block. Die Namespace-Konfiguration ist entscheidend, damit Kuma die Envoy-Sidecars einfügen kann, die es zum Anwenden von Richtlinien benötigt. Ohne einen definierten Namespace kann kuma dies nicht tun. Außerdem müssen wir bei der Konfiguration von Kuma darauf achten, dass der Namespace das richtige Label enthält, das Kuma erkennt:

kuma.io/sidecar-injection: enabled.


Die Namespace-Definition mit der richtigen Bezeichnung ist wichtig, damit Kuma funktioniert. Im zweiten Block finden wir die Definition des Deployments. So definieren wir, wie das Deployment unseres Pods in unserem Kubernetes-Cluster aussehen soll. Hier ist es wichtig, sich auf das image , die imagePullPolicy und den containerPort zu konzentrieren. Das Image ist das vollständige Tag des von uns verwendeten Docker-Images.


Der Port, der für unser mit kind erstelltes Docker-Register konfiguriert wird, ist 5001 und dieser ist im Tag für unser Image enthalten. Er funktioniert als Tag, aber auch als Verbindung zu unserem Docker-Register. Auf diese Weise können wir die Images abrufen und unseren Container erstellen, der in unserer Kubernetes-Umgebung ausgeführt werden kann.


Aber um Images verwenden zu können, müssen wir sie natürlich erstellen. Schauen wir uns dazu an, wie das im listener Beispiel und im database Beispiel gemacht wird. Das Docker-Image für den listener wird wie folgt definiert:

 FROM eclipse-temurin:21-jdk-alpine WORKDIR /root ENV LANG=C.UTF-8 COPY entrypoint.sh /root COPY build/libs/wlsm-listener-service.jar /root/wlsm-listener-service.jar ENTRYPOINT ["/root/entrypoint.sh"]


Das Ganze beginnt mit einem Basisimage namens eclipse-temurin:21-jdk-alpine . Danach kopieren wir einfach das JAR, das beim Erstellen des Projekts erstellt wurde, und erstellen dann eine Kopie davon in unserem Image. Zuvor kopieren wir auch entrypoint.sh in den Container und definieren den ENTRYPOINT um ihn zu verwenden. Der entrypoint ruft das JAR einfach wie folgt auf:

 #!/usr/bin/env sh java -jar -Dspring.profiles.active=prod wlsm-listener-service.jar


Der database ist ganz anders, da er einige Open Source-Skripte verwendet, die online verfügbar sind:

 FROM postgres:15 COPY . /docker-entrypoint-initdb.d COPY ./multiple /docker-entrypoint-initdb.d/multiple ENV POSTGRES_USER=admin ENV POSTGRES_PASSWORD=admin ENV POSTGRES_MULTIPLE_DATABASES=wlsm EXPOSE 5432


Dieses Skript erstellt eine Kopie der folgenden Datei und des folgenden Ordners im Docker-Init-Verzeichnis: create-multiple-postgresql-databases.sh und multiple . Abschließend definieren wir einfach die in diesen Skripten verwendeten Variablen, um unsere Datenbank und Benutzername/Passwort-Kombinationen zu definieren.


Die Datenbank wird nach folgendem Schema erstellt:

 CREATE TABLE families( id uuid DEFAULT gen_random_uuid(), name VARCHAR(100), PRIMARY KEY(id) ); CREATE TABLE genuses( id uuid DEFAULT gen_random_uuid(), name VARCHAR(100), PRIMARY KEY(id) ); CREATE TABLE species( id uuid DEFAULT gen_random_uuid(), common_name VARCHAR(100), family uuid, genus uuid, PRIMARY KEY(id), CONSTRAINT fk_species FOREIGN KEY(family) REFERENCES families(id), CONSTRAINT fk_genus FOREIGN KEY(genus) REFERENCES genuses(id) ); CREATE TABLE animal ( id uuid DEFAULT gen_random_uuid(), name VARCHAR(100), species_id uuid, PRIMARY KEY(id), CONSTRAINT fk_species FOREIGN KEY(species_id) REFERENCES species(id) ); CREATE TABLE animal_location ( id uuid DEFAULT gen_random_uuid(), animal_id uuid, latitude BIGINT, longitude BIGINT, PRIMARY KEY(id), CONSTRAINT fk_animal FOREIGN KEY(animal_id) REFERENCES animal(id) );


Als Datenbeispiel registrieren wir ein Tier mit dem Namen piquinho . Piquinho ist einfach der Name eines Albatrosses, der um die Welt reist und an dem ein Sensor befestigt ist. Wir lesen die Daten, die der Sensor uns sendet. Es gibt zwei Tabellen, die Arten definieren. Das sind die Arten und die Gattungen, die Arten definieren. Dies sind die Tabellen families und genuses .


Die Tabelle species gibt an, zu welcher Art das Tier gehört. Abschließend definieren wir in der gleichnamigen Tabelle ein animal , in dem Art und Name des Tieres eingetragen werden. Die Datenbank sieht dann so aus:
Bildbeschreibung

Um unser Projekt zu erstellen, die Bilder zu erstellen und es zu starten, können wir die folgenden Befehle ausführen, die im Makefile verfügbar sind:

 make make create-and-push-images make k8s-apply-deployment


Das erste make ist nur ein gradle build Befehl. Der zweite Befehl verwendet die Variable:

 MODULE_TAGS := aggregator \ collector \ listener \ management \ database


laufen:

 docker images "*/*wlsm*" --format '{{.Repository}}' | xargs -I {} docker rmi {} @for tag in $(MODULE_TAGS); do \ export CURRENT=$(shell pwd); \ echo "Building Image $$image..."; \ cd "wlsm-"$$tag"-service"; \ docker build . --tag localhost:5001/"wlsm-"$$tag"-service"; \ docker push localhost:5001/"wlsm-"$$tag"-service"; \ cd $$CURRENT; \ done


Dies durchläuft einfach jedes Modul und verwendet einen standardmäßigen generischen Befehl, der sich je nach in den MODULE_TAGS angegebenem Wert ändert, um die Bilder zu erstellen und sie in das lokale Register auf Port 5001 zu übertragen. Mit derselben Strategie können wir dann den dritten Befehl verwenden, um unsere Pods bereitzustellen. Dieser dritte Befehl verwendet eine andere Schleife, die wie folgt aussieht:

 @for tag in $(MODULE_TAGS); do \ export CURRENT=$(shell pwd); \ echo "Applying File $$tag..."; \ cd "wlsm-"$$tag"-service"; \ kubectl apply -f $$tag-deployment.yaml --force; \ cd $$CURRENT; \ done


In diesem Fall wird jedes Bereitstellungsskript auf jeden einzelnen Dienst angewendet. Wenn wir den Befehl kubectl get pods --all-namespaces ausführen, sollten wir diese Ausgabe erhalten:

 NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-76f75df574-dmt5m 1/1 Running 0 5m21s kube-system coredns-76f75df574-jtrfr 1/1 Running 0 5m21s kube-system etcd-kind-control-plane 1/1 Running 0 5m38s kube-system kindnet-7frts 1/1 Running 0 5m21s kube-system kube-apiserver-kind-control-plane 1/1 Running 0 5m36s kube-system kube-controller-manager-kind-control-plane 1/1 Running 0 5m36s kube-system kube-proxy-njzvl 1/1 Running 0 5m21s kube-system kube-scheduler-kind-control-plane 1/1 Running 0 5m36s kuma-system kuma-control-plane-5f47fdb4c6-7sqmp 1/1 Running 0 17s local-path-storage local-path-provisioner-7577fdbbfb-5qnxr 1/1 Running 0 5m21s wlsm-namespace wlsm-aggregator-64fc4599b-hg9qw 1/1 Running 0 4m23s wlsm-namespace wlsm-collector-5d44b54dbc-swf84 1/1 Running 0 4m23s wlsm-namespace wlsm-database-666d794c87-pslzp 1/1 Running 0 4m22s wlsm-namespace wlsm-listener-7bfbcf799-f44f5 1/1 Running 0 4m23s wlsm-namespace wlsm-management-748cf7b48f-8cjh9 1/1 Running 0 4m23s


Was wir hier an dieser Stelle beachten sollten, ist die Präsenz der kuma-control-plane , des kube-controller-manager und aller Dienste, die in unserem eigenen benutzerdefinierten wlsm-namespace ausgeführt werden. Unser Cluster ist von der Außenwelt isoliert, und um auf die verschiedenen Ports zugreifen zu können, müssen wir für jeden Pod, auf den wir zugreifen möchten port-forwarding erstellen. Dazu können wir diese Befehle in separaten Registerkarten ausführen:

Wir können uns das auch ansehen, indem wir uns k9s ansehen:

Bildbeschreibung

 kubectl port-forward svc/wlsm-collector-deployment -n wlsm-namespace 8081:8081 kubectl port-forward svc/wlsm-listener-deployment -n wlsm-namespace 8080:8080 kubectl port-forward svc/wlsm-database-deployment -n wlsm-namespace 5432:5432 kubectl port-forward svc/kuma-control-plane -n kuma-system 5681:5681


VI. Ausführen der Anwendung

Um die Anwendung auszuführen, sollten wir alle Ports öffnen. Wenn alle geöffnet sind, sollte auf unseren Bildschirmen ungefähr Folgendes angezeigt werden:

Bildbeschreibung

Wir können uns über localhost und Port 5432 mit der Datenbank verbinden. Die Verbindungszeichenfolge ist diese: jdbc:postgresql://localhost:5432/wlsm . Und um darauf zuzugreifen, verwenden wir dann die Benutzername/Passwort-Kombination admin / admin .


Bevor wir einen Test durchführen, müssen wir zunächst die ID von Piquinho ermitteln. Dazu verwenden wir Intellij-Datenbanktools wie dieses:

Bildbeschreibung

Im Stammordner des Projekts befindet sich eine Datei namens test-requests.http . Dies ist eine Scratch-Datei zum Erstellen von REST-Anfragen für unsere offenen Ports:

 ### GET http://localhost:8080/app/v1/listener/info ### POST http://localhost:8080/app/v1/listener/create Content-Type: application/json { "animalId": "2ffc17b7-1956-4105-845f-b10a766789da", "latitude": 52505252, "longitude": 2869152 } ### POST http://localhost:8081/api/v1/collector/animals Content-Type: application/json { "animalId": "2ffc17b7-1956-4105-845f-b10a766789da", "latitude": 52505252, "longitude": 2869152 }


Um diese Datei verwenden zu können, müssen wir nur die ID ersetzen, in diesem Beispiel von 2ffc17b7-1956-4105-845f-b10a766789da durch d5ad0824-71c0-4786-a04a-ac2b9a032da4 . In diesem Fall können wir Anfragen vom Collector oder vom Listener aus stellen. Beide Anfragen sollten funktionieren, und wir sollten anschließend diese Art von Antwort pro Anfrage sehen:

 { "animalId": "d5ad0824-71c0-4786-a04a-ac2b9a032da4", "latitude": 52505252, "longitude": 2869152 } Response file saved. > 2024-04-12T001024.200.json Response code: 200 (OK); Time: 7460ms (7 s 460 ms); Content length: 91 bytes (91 B)


Da beide Ports geöffnet sind und sie zu diesem Zeitpunkt denselben Payload-Typ verwenden, können wir dieselben Anfragen an den Listener und den Collector stellen. Nachdem wir diese beiden Anfragen gestellt haben, sollten wir Ergebnisse in der Tabelle animal_locations finden:

Bildbeschreibung

Dies bestätigt nur, dass der Cluster ordnungsgemäß ausgeführt wird. Jetzt können wir Richtlinien mit unserem Kuma-Mesh testen.

VII. MeshTrafficPermission - Teil I

MeshTrafficPermission ist eine der Funktionen, die wir in Kuma auswählen können, und es ist wahrscheinlich die am häufigsten verwendete.


Aber zuerst wollen wir uns kurz die Kuma-Kontrollebene ansehen. Wenn alle Weiterleitungen aktiviert sind, können wir einfach zu localhost:5681/gui gehen und unsere Kuma-Netze visualisieren. Auf der Hauptseite sollten wir etwa Folgendes sehen:

Bildbeschreibung

Im Moment gibt es nicht viel zu sehen, aber wenden wir jetzt die MeshTrafficPermission an:

 echo "apiVersion: kuma.io/v1alpha1 kind: MeshTrafficPermission metadata: namespace: kuma-system name: mtp spec: targetRef: kind: Mesh from: - targetRef: kind: Mesh default: action: Allow" | kubectl apply -f -


Sobald wir dies anwenden, sollten wir eine Antwort wie diese erhalten: meshtrafficpermission.kuma.io/mtp created .

VIII. Maschenware

Die Anwendung des Mesh ändert nicht viel an der Einrichtung unseres Clusters. Es ermöglicht uns jedoch, Richtlinien für die Verkehrsführung einzurichten.


Es gibt viele Dinge, aus denen wir wählen können, aber eine der offensichtlichsten ist mTLS. Es wird auch als gegenseitiges TLS bezeichnet und bedeutet kurz gesagt, dass Zertifikate gegenseitig akzeptiert und validiert werden, um die Identität zwischen den Parteien festzustellen und verschlüsselten Datenverkehr herzustellen.


Mit dieser einfachen Mesh Konfiguration kann dies automatisch für uns erledigt werden:

 echo "apiVersion: kuma.io/v1alpha1 kind: Mesh metadata: name: default spec: mtls: enabledBackend: ca-1 backends: - name: ca-1 type: builtin" | kubectl apply -f -


Nach der Anwendung dieser Richtlinie wird möglicherweise eine Warnung wie diese angezeigt:

Warning: resource meshes/default is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.

Im Moment können wir diese Warnung ignorieren.

IX MeshTrafficPermission - Teil II

Jetzt kommt der spaßige Teil. Als Erstes deaktivieren wir den gesamten Datenverkehr zwischen allen Pods:

 echo " apiVersion: kuma.io/v1alpha1 kind: MeshTrafficPermission metadata: namespace: wlsm-namespace name: mtp spec: targetRef: kind: Mesh from: - targetRef: kind: Mesh default: action: Deny" | kubectl apply -f -


Und nachdem wir die Bestätigungsnachricht meshtrafficpermission.kuma.io/mtp configured erhalten haben, erhalten wir beim Versuch, eine Anfrage mithilfe einer der Portweiterleitungen zu stellen, Folgendes:

 HTTP/1.1 500 Internal Server Error Content-Type: application/json Content-Length: 133 { "timestamp": "2024-04-12T07:09:26.718+00:00", "path": "/create", "status": 500, "error": "Internal Server Error", "requestId": "720749ce-56" } Response file saved. > 2024-04-12T090926.500.json Response code: 500 (Internal Server Error); Time: 10ms (10 ms); Content length: 133 bytes (133 B)


Das bedeutet, dass der gesamte Datenverkehr zwischen den Pods blockiert wird. Wir verfügen nun über ein internes System, das vor möglichen böswilligen Akteuren innerhalb unserer Organisation geschützt ist, haben aber jetzt auch den Datenverkehr zwischen allen Pods blockiert. mTLS ist also eine tolle Sache, aber den gesamten Datenverkehr zu blockieren, ist es überhaupt nicht.


Um dies zu perfektionieren, müssen Sie lediglich Ausnahmen von der DENY ALL-Regel machen. Dazu benötigen wir eine Richtlinie, die den Datenverkehr zwischen dem Listener und dem Collector sowie zwischen dem Collector und der Datenbank zulässt. Beginnen wir mit dem Datenverkehr zwischen dem Collector und der Datenbank:

 echo " apiVersion: kuma.io/v1alpha1 kind: MeshTrafficPermission metadata: namespace: kuma-system name: wlsm-database spec: targetRef: kind: MeshService name: wlsm-database-deployment_wlsm-namespace_svc_5432 from: - targetRef: kind: MeshService name: wlsm-collector-deployment_wlsm-namespace_svc_8081 default: action: Allow" | kubectl apply -f -


In diesem Fall ermöglichen wir den Datenverkehr vom targetRef Sammler zur targetRef Datenbank. Wenn Sie das nicht wissen, ist es vielleicht wichtig zu wissen, wie Kuma den name interpretiert, der ebenso wie die hostname auch für funktionale Zwecke verwendet wird.


Die allgemeine Art und Weise zum Erstellen dieser name sieht folgendermaßen aus:

<service name>_<namespace>_svc_<service port>


In diesem Fall ist das Trennzeichen ein Unterstrich. Durch die Erstellung eines Namens auf diese Weise weiß Kuma genau, was zulässig ist. Wenn wir in diesem Fall diese Richtlinie anwenden, können wir Anfragen an den Collector senden, nachdem wir diese Antwort erhalten haben: meshtrafficpermission.kuma.io/wlsm-database created .


Und wenn Sie diese erstellen, sollte die Antwort jetzt 200 sein und bestätigen, dass der Standortdatensatz an den Collector gesendet wurde:

 POST http://localhost:8081/api/v1/collector/animals HTTP/1.1 200 OK Content-Type: application/json Content-Length: 91 { "animalId": "a3a1bc1c-f284-4876-a84f-f75184b6998f", "latitude": 52505252, "longitude": 2869152 } Response file saved. > 2024-04-12T091754.200.json Response code: 200 (OK); Time: 1732ms (1 s 732 ms); Content length: 91 bytes (91 B)


Da wir jedoch noch keine Ausnahmen für den Datenverkehr zwischen Listener und Collector definiert haben, führt eine Anfrage auf diese Weise zu folgendem Ergebnis:

 HTTP/1.1 500 Internal Server Error Content-Type: application/json Content-Length: 133 { "timestamp": "2024-04-12T07:18:54.149+00:00", "path": "/create", "status": 500, "error": "Internal Server Error", "requestId": "e8973d33-62" } Response file saved. > 2024-04-12T091854-1.500.json Response code: 500 (Internal Server Error); Time: 10ms (10 ms); Content length: 133 bytes (133 B)


Und das ist natürlich zu erwarten. Wenden wir nun eine andere Richtlinie für diesen Datenverkehr an:

 echo " apiVersion: kuma.io/v1alpha1 kind: MeshTrafficPermission metadata: namespace: kuma-system name: wlsm-collector spec: targetRef: kind: MeshService name: wlsm-collector-deployment_wlsm-namespace_svc_8081 from: - targetRef: kind: MeshService name: wlsm-listener-deployment_wlsm-namespace_svc_8080 default: action: Allow" | kubectl apply -f -


Damit ist es nun möglich, Anfragen vom Listener an den Collector auszuführen:

 POST http://localhost:8080/app/v1/listener/create HTTP/1.1 200 OK Content-Type: application/json Content-Length: 91 { "animalId": "a3a1bc1c-f284-4876-a84f-f75184b6998f", "latitude": 52505252, "longitude": 2869152 } Response file saved. > 2024-04-12T092039-2.200.json Response code: 200 (OK); Time: 14ms (14 ms); Content length: 91 bytes (91 B)

X - MeshFaultInjection

Abschließend und nur um ein weiteres Feature als Beispiel zu nennen: Wir können auch ein weiteres Feature namens MeshFaultInjection verwenden, das bei der Durchführung von Tests mit Kuma sehr nützlich sein kann. Wir können beispielsweise potenzielle Probleme innerhalb unseres Meshs simulieren und prüfen, ob die Fehlerbehandlung korrekt durchgeführt wird.


Wir können auch andere Dinge überprüfen, beispielsweise wie von uns konfigurierte Leistungsschalter auf fehlerhafte Verbindungen oder Anfragen mit hoher Rate reagieren.


Also, versuchen wir es. Eine Möglichkeit, MeshFaultInjection anzuwenden, ist wie folgt:

 echo " apiVersion: kuma.io/v1alpha1 kind: MeshFaultInjection metadata: name: default namespace: kuma-system labels: kuma.io/mesh: default spec: targetRef: kind: MeshService name: wlsm-collector-deployment_wlsm-namespace_svc_8081 from: - targetRef: kind: MeshService name: wlsm-listener-deployment_wlsm-namespace_svc_8080 default: http: - abort: httpStatus: 500 percentage: 50" | kubectl apply -f -


Mit dieser Richtlinie geben wir an, dass der vom Listener ausgehende und zum Collector eingehende Datenverkehr eine Erfolgschance von 50 % hat. Die Anfrageergebnisse sind unvorhersehbar, daher können wir nach der Anwendung dieser Richtlinie mit Fehlern oder erfolgreichen Anfragen an den Listener-Endpunkt rechnen.

 POST http://localhost:8080/app/v1/listener/create HTTP/1.1 500 Internal Server Error Content-Type: application/json Content-Length: 133 { "timestamp": "2024-04-12T07:28:00.008+00:00", "path": "/create", "status": 500, "error": "Internal Server Error", "requestId": "2206f29e-78" } Response file saved. > 2024-04-12T092800.500.json Response code: 500 (Internal Server Error); Time: 8ms (8 ms); Content length: 133 bytes (133 B)


 POST http://localhost:8080/app/v1/listener/create HTTP/1.1 200 OK Content-Type: application/json Content-Length: 91 { "animalId": "a3a1bc1c-f284-4876-a84f-f75184b6998f", "latitude": 52505252, "longitude": 2869152 } Response file saved. > 2024-04-12T092819.200.json Response code: 200 (OK); Time: 13ms (13 ms); Content length: 91 bytes (91 B)


Abschließend können wir nur aus Interesse einen Blick darauf werfen, wie unsere animal_location Tabelle jetzt aussieht:

Bildbeschreibung

XI - Fazit

Ich hoffe, Sie konnten diesem Artikel bis hierhin folgen und einen Cluster auf Ihrem Rechner zum Laufen bringen. Vielen Dank jedenfalls, dass Sie diesen Artikel gelesen haben und dass Sie sich etwas Zeit genommen haben, um Kuma besser zu verstehen und mehr darüber zu erfahren. Ich persönlich sehe darin einen großartigen Nutzen und eine großartige Zukunft für Kuma da es uns ermöglicht, unser Netzwerk und unsere Umgebung viel feiner zu konfigurieren und zu steuern.


Die Enterprise-Version, Kong-Mesh , scheint ziemlich vollständig zu sein. Kuma ist Open Source und eignet sich hervorragend zum Testen und anscheinend auch für Unternehmen. Ich finde das Thema Meshes sehr interessant und denke, dass Kuma eine großartige Möglichkeit bietet, zu lernen, wie Meshes funktionieren und ein Gefühl dafür zu bekommen, wie wir den Datenfluss in unserem Netzwerk besser steuern können.


Wenn wir den Status unserer Dienste sehen möchten, können wir einfach zu unserer Kuma Kontrollebene an diesem localhost Speicherort gehen: http://localhost:5681/gui/meshes/default/services?page=1&size=50 :

Bildbeschreibung

In der Kuma-Steuerungsebene können wir uns auch die installierten Richtlinien ansehen, den Status unserer Pods überprüfen, überwachen, was im Hintergrund passiert, und uns ganz allgemein einen Überblick darüber verschaffen, was in unserem Mesh passiert und wie es konfiguriert ist. Ich lade Sie ein, einfach die Anwendung durchzugehen und zu prüfen, ob Sie den Status der von uns installierten Richtlinien überprüfen können. Die Kuma-Steuerungsebene, auch bekannt als GUI, ist genau darauf ausgelegt, dass unser Mesh leicht zu verstehen und zu verfolgen ist.

XII - Ressourcen

Ich habe auch ein Video darüber auf meinem JESPROTECH -YouTube-Kanal hier gemacht: