Kuma
hızlı bir şekilde öğrenmeye başlamak için ihtiyacımız olan en önemli şeylerden biri kümedir. Daha sonra Kubernetes'teki (aka k8s
) pod'larımızın durumunu öğrenmek için bir komuta da ihtiyacımız var, ayrıca Kuma
kurabilmemiz gerekiyor ve son olarak bazı Kuma
komutlarını da verebilmemiz gerekiyor.
Bu, her şeyi Kuma
hazır hale getirmek için 4 temel komutu kurmamız gerektiğini söylemenin uzun bir yolu. Bu komutlar şunlardır:
kind
- Bu aynı zamanda Docker'da Kubernetes olarak da bilinir. Bu, yalnızca kubectl
ile bir şeyler oluşturmanın ağırlığından yararlanan bir komuttur.
kubectl
- Zaten k8s
ile çalışmaya alışkınsanız, muhtemelen bu listede en çok beklenenlerden biri. k8s
kümemize bu şekilde komut verebiliriz.
helm
- Helm, diğerlerinin yanı sıra Kuma
kontrol düzleminin kurulumuna izin veren bazı çok kullanışlı komut dosyalarını çalıştırmamıza olanak tanır.
kumactl
- Bu kılavuzda bu komutu çok sık kullanmayacağız, ancak nasıl kullanılacağının farkında olmak önemlidir.
Bu kılavuz, bunu Ubuntu
nasıl yapacağınızı size bildirecektir. Bunların hepsi bir Ubuntu
sisteminde test edilmiştir. Bunu Mac-OS
, Windows
veya sahip olabileceğiniz başka bir işletim sistemine nasıl kuracağınıza dair bir kılavuzla ilgileniyorsanız, lütfen YouTube kanalım JESPROTECH
topluluğumdan bana ses verin.
k8s
)Kind'i kurmak için şu komutları vermemiz gerekiyor:
[ $(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
kind
komutunun /usr/local/bin/kind
dizinine kurulacağını unutmamak önemlidir. Bu, Linux dağıtımlarında bile sisteme göre değişiklik gösterebilir.
Belirli GPG
anahtarlarının varlığıyla hem helm
hem de kubectl
komutlarının yüklenmesi gerekir. Bunları Linux apt
dağıtımımızın yerel deposuna şu şekilde ekleyebiliriz:
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
Önceki adım tamamlandıktan sonra Kubectl
kurulumu çok kolaydır:
sudo apt-get install -y kubelet kubeadm kubectl
kubelet
, kubeadm
ve kubectl
komutları zorunlu değildir ancak bunları yüklemek iyi bir fikirdir.
Tahmin edebileceğiniz gibi helm
kurulumu da artık çok kolay:
sudo apt-get install -y helm
Kuma
kurulumu tek bir manuel adım içerdiğinden biraz hantal olabilir, ancak önce bağımlılıklarımızı indirmemiz gerekiyor:
cd ~ || exit; curl -L https://kuma.io/installer.sh | VERSION=2.6.1 sh -
Bu komutu vermeden önce HOME
klasörünüzde olduğunuzdan emin olun. Kuma
, örneğin kaldırmaya karar vermemiz durumunda, kolayca erişilebilecek ve kolayca görülebilecek bir yere kurulması önemlidir.
Bununla işimiz bittiğinde, bin
klasörünü PATH'imize eklemek de çok önemlidir:
export PATH=~/kuma-2.6.1/bin:$PATH;
Bu satırı başlangıç betiğinizin sonuna veya aradaki herhangi bir yere eklemek bu işlemi kolaylaştıracaktır. Başlangıç komut dosyanız bu .bashrc
, .zshrc
, .profile
dosyalarından herhangi biri olabilir ve muhtemelen başka bir biçim alabilir.
k9s
kurulumu da diğer uygulamalardan oldukça farklıdır. Bu durumda Linux
için ya pacman
ya da brew
kullanabiliriz. brew
çoğunlukla Mac-OS
için kullandım ve Linux'ta buna neredeyse hiç ihtiyaç duymadım, ancak bu durumda buna çok ihtiyaç var ve bunu yapmak için ilk önce Brew'i şu şekilde kurmamız gerekiyor:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Demleme kurulumu tamamlandıktan sonra tek yapmamız gereken k9s
(" kanines
") kurmak:
brew install derailed/k9s/k9s
Dikkate alınması gereken önemli bir nokta ve k9s
ilk kez kurup çalıştırmaya başladığınızda muhtemelen bunu fark edeceksiniz; izlediği bir küme kaldırılırsa ve/veya eklenirse k9s
çökecektir.
kind create cluster --name=wlsm-mesh-zone kubectl cluster-info --context kind-wlsm-mesh-zone
İlk komut wlsm-mesh-zone
adında bir küme oluşturur. Bu sadece Kuma'yı kurmak için kullanacağımız bir küme. İkinci komut kümenin durumunu kontrol etmek için kullanılır.
Daha önce de belirttiğim gibi docker kayıt defterini oldukça kolay bir şekilde oluşturabiliyoruz. Bunu oluşturmak kulağa kolay gelse de, bunu yapacak komut dosyası bir avuç dolusu. Bu nedenle yapılacak en iyi şey, web sitelerinde zaten mevcut olan türü kopyalayıp yapıştırmaktır. Buradan bu betiği indirebiliriz:
#!/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
Bu komut dosyasıprojenin kök klasöründe bulunabilir. Ve yerel docker kayıt defterini kurmak için yalnızca bu bash betiğini çalıştırmamız gerekiyor.
Bu blog yazısı için örnek olarak verdiğim kod hakkında söylenecek çok şey olabilir. Ancak bu durumda sadece birkaç önemli noktaya odaklanalım.Dinleyici hizmetinden toplayıcıya ve ardındanveritabanına başlayalım. Hizmetleri yerel olarak çalıştırdığımızda veya hatta kapsayıcıların çalışmasını sağlamak için docker-compose
yapılandırmasını kullandığımızda, genellikle kapsayıcı adı veya hostname
adı ile yapılandırdığımız ad olarak otomatik olarak atanan DNS ile ilişkilendirilen adları kullanırız.
k8s
ile ana bilgisayar adlarının küme genelinde kullanılabilir olmasını sağlayan bir dizi kural da vardır. Dinleyici ve toplayıcı örneklerine bir göz atalım:
Dinleyici, Spring framework
kullanarak Java
geliştirilmiş bir uygulamadır. Bu şekilde oluşturulan tüm uygulamalar gibi bir de application.properties
dosyası bulunur:
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
Tüm bu özellikler içerisinde şu an için üzerinde durulması gereken en önemli özellik wslm.url.collector
özelliğidir. default
konfigürasyon ile herhangi bir konteynerli ortam kullanmaya gerek kalmadan bu hizmeti local olarak çalıştırabiliyoruz. Ancak k8s
kümesinde collector
erişebilmemiz gerekiyor ve bunun için application-prod.properties
tanım dosyasına sahip bir prod
profilimiz var:
wslm.url.collector=http://wlsm-collector-deployment.wlsm-namespace.svc.cluster.local:8081/api/v1/collector
Bu özellik, wlsm-collector-deployment.wlsm-namespace.svc.cluster.local
ana bilgisayarına ulaşmaya çalışır. Bu dosya şu yapılandırmayı takip eder:
<Service Name>.<Namespace>.svc.cluster.local
Noktalarla ayrılmış 5 öğemiz var. Son üçü statiktir ve ilk ikisi ulaşmaya çalıştığımız makineye bağlıdır. Sol tarafa hizmet adını ve ardından ad alanını yerleştiriyoruz. Bu, konteynerlerin küme içinde birbirine nasıl bağlandığını anlamak önemlidir.
Kodun ilginç olan kısmı elbette denetleyici ve hizmettir. Denetleyici şuna benzer:
@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); } }
Ve hizmet şöyle görünüyor:
@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); } }
Fark etmiş olabileceğiniz gibi, bu ilk uygulama, bu depodaki Spring Framework
kullanılarak uygulanan tüm uygulamalar gibi reaktiftir ve hepsi tomcat
yerine netty
kullanır. Şimdilik bu koddaki hazelcast
kullanımını göz ardı edebiliriz. . Bu, bu projenin sonraki sürümleri için kullanılacaktır.
Bu noktada toplayıcı da dinleyiciyle tamamen aynı şekilde çalışır. Şimdilik tek görevi, verileri dinleyiciden veritabanına aktarmaktır ve bunu yapmak için toplayıcının yalnızca veritabanının tam olarak nerede olduğunu bilmesi gerekir. Aynı analizi application.properties file of this project
üzerinde de yapalım:
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
Bu özellikler, hizmetin devam etmesi için gereken minimum özelliklerdir. Ancak bu yalnızca yerel olarak çalıştırılabilir. Bu hizmet için ayrıca prod
profil dosyamız var ve buna buradaki application-prod.properties
dosyasından bakabiliriz:
spring.r2dbc.url=r2dbc:postgresql://wlsm-database-deployment.wlsm-namespace.svc.cluster.local:5432/wlsm
Bu durumda veritabanı bağlantısı veritabanının ana bilgisayarına atıfta bulunur:
wlsm-database-deployment.wlsm-namespace.svc.cluster.local
Bu da daha önce gördüğümüz analizin aynısını takip ediyor. Sol tarafta hizmet adını ve ardından bunu sonuna svc.cluster.local
ile ekleyen ad alanını görüyoruz.
Ve bu hizmet için ayrıca bir denetleyici ve bir hizmet kullanıyoruz. Denetleyici şuna benzer:
@RestController @RequestMapping class CollectorController( val collectorService: CollectorService ) { @PostMapping("animals") suspend fun listenAnimalLocation(@RequestBody animalLocationDto: AnimalLocationDto): AnimalLocationDto = run { collectorService.persist(animalLocationDto) animalLocationDto } }
Ve hizmet şöyle görünüyor:
@Service class CollectorService( val applicationEventPublisher: ApplicationEventPublisher ) { fun persist(animalLocationDto: AnimalLocationDto) = applicationEventPublisher.publishEvent(AnimalLocationEvent(animalLocationDto)) }
Hizmet, applicationEventPublisher
adı verilen ve daha sonra bu olay dinleyicisinde işlenecek bir olay akışı mimarisini takip eden bir olay yayıncısını kullanır; bunun reaktif mimari uygulama paradigmalarını korumak için r2dbc
kullandığını kolayca görebiliriz:
@Service class EventHandlerService( val animalLocationDao: AnimalLocationDao ) { @EventListener fun processEvent(animalLocationEvent: AnimalLocationEvent){ println(animalLocationEvent) runBlocking(Dispatchers.IO) { animalLocationDao.save(animalLocationEvent.animalLocationDto.toEntity()) } } }
Dağıtım normalde k8s
ile yapılacak çok basit bir iştir. Ancak hizmetlerimiz için gereken konfigürasyona da göz atmak önemlidir. Örneğin dinleyici uygulamasına bir göz atalım:
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
Bu konfigürasyonda üç blok bulunmaktadır. İlk blok ad alanı bloğudur. Ad alanı yapılandırması, Kuma'nın politikaları uygulamak için ihtiyaç duyduğu elçi sepetlerini enjekte edebilmesine olanak sağlamak açısından çok önemlidir. Tanımlanmış bir ad alanı olmadan kuma
bunu yapamaz. Kuma'yı yapılandırırken dikkat etmemiz gereken diğer husus ise namespace'in kuma'nın tanıyacağı uygun etiketi içermesi gerektiğidir:
kuma.io/sidecar-injection: enabled.
Doğru etikete sahip ad alanı tanımı Kuma'nın çalışması için hayati öneme sahiptir. İkinci blokta dağıtımın tanımını buluyoruz. Podumuzun dağıtımının Kubernetes kümemizde nasıl görüneceğini bu şekilde tanımlıyoruz. Burada odaklanılması gereken önemli şey image
, imagePullPolicy
ve containerPort
. İmaj, kullandığımız Docker imajının tam etiketidir.
kind
ile oluşturulan docker kayıt defterimiz için yapılandırılan port 5001'dir ve bu, imajımızın etiketine dahil edilmiştir. Bir etiket olarak çalışır, aynı zamanda Docker kayıt defterimize bağlantı olarak da çalışır. Bu şekilde görüntüleri çekebilir ve Kubernetes ortamımızda çalışacak konteynerimizi oluşturabiliriz.
Ancak elbette görüntüleri kullanabilmek için onları oluşturmamız gerekiyor ve bunun için listener
örneğinde ve database
örneğinde bunun nasıl yapıldığına bir göz atalım. listener
liman işçisi görüntüsü şu şekilde tanımlanır:
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"]
Bunların hepsi eclipse-temurin:21-jdk-alpine
adı verilen temel görüntüden başlar. Bundan sonra projeyi inşa ederek oluşturduğumuz jar'ı kopyalayıp imajımıza kopyalıyoruz. Bundan önce entrypoint.sh
dosyasını da konteynere kopyalıyoruz ve onu kullanacak ENTRYPOINT
tanımlıyoruz. entrypoint
basitçe kavanozu şu şekilde çağırır:
#!/usr/bin/env sh java -jar -Dspring.profiles.active=prod wlsm-listener-service.jar
database
hizmeti oldukça farklıdır çünkü açık kaynaklı ve çevrimiçi olarak erişilebilen birkaç komut dosyası kullanır:
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
Bu komut dosyası, aşağıdaki dosya ve klasörün docker başlangıç dizinine bir kopyasını oluşturur: create-multiple-postgresql-databases.sh
ve multiple
. Son olarak, veritabanımızı ve kullanıcı adı/şifre kombinasyonlarımızı tanımlamak için bu komut dosyalarında kullanılan değişkenleri basitçe tanımlarız.
Veritabanı aşağıdaki şema kullanılarak oluşturulur:
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) );
Veri örneği olarak bir hayvanı piquinho
adıyla kaydedeceğiz. Piquinho, basitçe dünyayı dolaşan, üzerine bir sensör takılı olan ve biz de sensörün bize gönderdiği verileri okuyan gezgin bir albatros'un adıdır. Türleri tanımlayan iki tablo vardır. Türü tanımlayan tür ve cinstir. Bunlar tablo families
ve genuses
.
Tablo species
hayvanın ait olduğu türü tanımlar. Son olarak hayvanın türünün ve adının kayıtlı olduğu aynı isimli tabloda bir animal
tanımlıyoruz. Veritabanı şuna benzer:
Görüntüleri oluşturmak, oluşturmak ve projemizi başlatmak için Makefile
bulunan aşağıdaki komutları çalıştırabiliriz:
make make create-and-push-images make k8s-apply-deployment
İlk make sadece bir gradle build
komutudur. İkinci komut değişkeni kullandı:
MODULE_TAGS := aggregator \ collector \ listener \ management \ database
koşmak:
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
Bu, her modülün üzerinden geçer ve görüntüleri oluşturmak ve bunları 5001 numaralı bağlantı noktasındaki yerel kayıt defterine göndermek için MODULE_TAGS
verilen değere göre değişen standart bir genel komut kullanır. Aynı stratejiyi izleyerek, daha sonra üçüncü komutu konuşlandırmak için kullanabiliriz. kapsüller. Bu üçüncü komut şuna benzeyen farklı bir döngü kullanır:
@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
Bu durumda, her dağıtım komut dosyasını hizmetlerin her birine uygular. kubectl get pods --all-namespaces
komutunu çalıştırırsak şu çıktıyı almamız gerekir:
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
Burada burada gözlemlememiz gereken şey kuma-control-plane
, kube-controller-manager
ve kendi özel wlsm-namespace
çalışan tüm servislerin varlığıdır. Kümemiz dışarıdan izole edilmiştir ve farklı bağlantı noktalarına erişebilmek için erişmek istediğimiz her pod için port-forwarding
oluşturmamız gerekir. Bunun için şu komutları ayrı sekmelerde verebiliriz:
Buna k9s
bakarak da bakabiliriz:
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
Uygulamayı çalıştırabilmek için tüm portları açmamız gerekiyor ve hepsi açıldığında ekranlarımızda şöyle bir şey görmeliyiz:
Veritabanına localhost
ve 5432
portunu kullanarak bağlanabiliyoruz. Bağlantı dizesi şudur: jdbc:postgresql://localhost:5432/wlsm
. Ve ona erişmek için admin
/ admin
kullanıcı adı/şifre kombinasyonunu kullanırız.
Herhangi bir test yapmadan önce yapmamız gereken ilk şey Piquinho
kimliğini bilmektir ve bunu Intellij veritabanı araçlarını aşağıdaki gibi kullanarak yapabiliriz:
Projenin kök klasöründe test-requests.http
adında bir dosya bulunmaktadır. Bu, açık bağlantı noktalarımıza karşı REST istekleri oluşturmaya yönelik bir karalama dosyasıdır:
### 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 }
Bu dosyayı kullanabilmek için, bu örnekte yalnızca kimliği 2ffc17b7-1956-4105-845f-b10a766789da
d5ad0824-71c0-4786-a04a-ac2b9a032da4
değiştirmemiz gerekiyor. Bu durumda koleksiyoncudan ya da dinleyiciden istekte bulunabiliriz. Her iki istek de çalışmalı ve daha sonra istek başına bu tür bir yanıt görmeliyiz:
{ "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)
Her iki port da açık olduğundan ve bu noktada aynı veri yükünü paylaştıklarından, dinleyiciye ve toplayıcıya aynı istekleri gerçekleştirebiliriz. Bu iki isteği yaptıktan sonra sonuçları animal_locations
tablosunda bulmalıyız:
Yani bu yalnızca kümenin doğru çalıştığını doğrular ve artık politikaları Kuma ağımızla test etmeye hazırız.
MeshTrafficPermission
Kuma'da seçebileceğimiz özelliklerden biri ve muhtemelen en çok kullanılanı.
Ama önce Kuma kontrol uçağını keşfetmek için biraz zaman ayıralım. Tüm yönlendirme işlemleri devam ederken localhost:5681/gui adresine gidebilir ve Kuma ağlarımızı görselleştirebiliriz. Ana sayfada şöyle bir şey görmeliyiz:
Şu anda görülecek pek bir şey yok ama şimdi MeshTrafficPermission
uygulayalım:
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 -
Bunu uyguladığımızda şöyle bir yanıt almamız gerekir: meshtrafficpermission.kuma.io/mtp created
.
Kümemizin kurulumu söz konusu olduğunda ağın uygulanması pek bir şeyi değiştirmez. Yaptığı şey, trafik yönlendirme politikaları oluşturmamıza izin vermektir.
Aralarından seçim yapabileceğimiz pek çok şey var ancak seçebileceğimiz en belirgin şeylerden biri mTLS.
Aksi halde karşılıklı TLS olarak anılan bu, çok kısa bir ifadeyle, taraflar arasında kimlik oluşturmak ve şifreli veri trafiği oluşturmak amacıyla sertifikaların karşılıklı olarak kabul edilmesi ve doğrulanması anlamına gelir.
Bu, bu basit Mesh
yapılandırmasını kullanarak bizim için otomatik olarak yapılabilir:
echo "apiVersion: kuma.io/v1alpha1 kind: Mesh metadata: name: default spec: mtls: enabledBackend: ca-1 backends: - name: ca-1 type: builtin" | kubectl apply -f -
Bu politikayı uyguladıktan sonra şuna benzer bir uyarıyla karşılaşabiliriz:
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.
Şimdilik bu uyarıyı görmezden gelebiliriz.
Şimdi işin eğlenceli kısmı geliyor ve yapacağımız ilk şey tüm bölmeler arasındaki tüm trafiği devre dışı bırakmak olacak:
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 -
meshtrafficpermission.kuma.io/mtp configured
onay mesajını aldıktan sonra, port yönlendirmelerden herhangi birini kullanarak herhangi bir istekte bulunmaya çalışırsak şunu elde ederiz:
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)
Bu, bölmeler arasındaki tüm trafiğin reddedildiği anlamına gelir. Şu anda sahip olduğumuz şey, kuruluşumuz içindeki olası kötü aktörlere karşı korunan bir dahili sistemdir, ancak artık tüm bölmeler arasındaki trafiği de engelledik. Yani mTLS
harika bir şey ama tüm trafiği engellemek hiç de öyle değil.
Bunu mükemmelleştirmenin yolu basitçe tümünü DENY
kuralına istisnalar yapmaktır ve bunu yapmak için dinleyici ile toplayıcı ve toplayıcı ile veritabanı arasındaki trafiğe izin verecek bir politikaya ihtiyacımız var. Toplayıcı ve veritabanı arasındaki trafikle başlayalım:
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 -
Bu durumda yaptığımız şey, veri trafiğinin targetRef
toplayıcıdan targetRef
veritabanına akmasına izin vermektir. Bunu bilmiyorsanız, Kuma'nın tıpkı hostname
oluşturma gibi işlevsel amaçlar için de kullanılan name
nasıl yorumladığını not etmek önemli olabilir.
Bu name
oluşturmanın genel yolu şu şekildedir:
<service name>_<namespace>_svc_<service port>
Bu durumda ayırıcı bir alt çizgidir ve bu şekilde bir ad oluşturmak Kuma
tam olarak neye izin verildiğini bilmesini sağlar. Bu durumda, bu politikayı uygularsak şu yanıtı aldıktan sonra toplayıcıya istek gönderebileceğiz: meshtrafficpermission.kuma.io/wlsm-database created
.
Ve bunları yaparken, konum kaydının toplayıcıya gönderildiğini doğrulayan yanıt artık 200
olmalıdır:
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)
Ancak dinleyici ile toplayıcı arasındaki trafiğe ilişkin istisnaları hâlâ tanımlamadık; dolayısıyla bu şekilde bir istekte bulunmak şu şekilde sonuçlanacaktır:
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)
Ve bu elbette bekleniyor. Şimdi bu veri trafiğine başka bir politika uygulayalım:
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 -
Artık dinleyiciden toplayıcıya isteklerin gerçekleştirilmesini mümkün kılıyoruz:
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)
Son olarak ve örnek olarak başka bir özellik vermek gerekirse, MeshFaultInjection
adlı başka bir özelliği de kullanabiliriz; bu, Kuma
ile testler yaparken çok faydalı olabilir. Ağımızdaki potansiyel sorunları simüle edebilir ve örneğin hata işlemenin doğru yapılıp yapılmadığını kontrol edebiliriz.
Ayrıca yapılandırmış olabileceğimiz devre kesicilerin hatalı bağlantılara veya yüksek hızlı isteklere nasıl tepki verebileceği gibi diğer şeyleri de kontrol edebiliriz.
Öyleyse deneyelim. MeshFaultInjection
uygulamanın bir yolu şudur:
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 -
Bu politika ile dinleyiciden giden ve toplayıcıya gelen trafiğin %50 başarı şansına sahip olacağını söylüyoruz. İstek sonuçları tahmin edilemez; bu nedenle, bu politikayı uyguladıktan sonra dinleyici uç noktasına hatalar veya başarılı istekler gelmesini bekleyebiliriz.
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)
Son olarak, ilgimizi çeken bir konu olarak, animal_location
tablomuzun şu an nasıl göründüğüne bir göz atabiliriz:
Umarım bu makaleyi buraya kadar takip edebilmişsinizdir ve makinenizde çalışan bir kümeye sahip olabilmişsinizdir. Yine de bu makaleyi okuduğunuz ve Kuma'yı anlamak ve hakkında daha fazla bilgi edinmek için biraz zaman ayırdığınız için teşekkür ederiz. Kişisel olarak bunun harika bir kullanım alanı olduğunu ve ağımızı ve çevremizi yapılandırmayı ve çok daha ayrıntılı bir şekilde kontrol altına almayı mümkün kıldığı için Kuma
için harika bir gelecek görüyorum.
Kurumsal versiyonu Kong-Mesh
oldukça eksiksiz görünüyor. Kuma açık kaynaktır. hem test için hem de kurumsal açıdan harika görünüyor. Ağlar konusunu çok ilginç buluyorum ve Kuma
ağların nasıl çalıştığını öğrenmek ve ağımızdaki veri akışını nasıl daha iyi kontrol edebileceğimiz konusunda fikir sahibi olmak için harika bir yol sağladığını düşünüyorum.
Hizmetlerimizin durumunu görmek istiyorsak, şu localhost
konumundaki Kuma
kontrol düzlemimize gidebiliriz: http://localhost:5681/gui/meshes/default/services?page=1&size=50 :
Kuma kontrol düzleminde ayrıca kurulu politikalara bakabilir, bölmelerimizin durumunu kontrol edebilir, arka planda neler olduğunu izleyebilir ve genel olarak ağımızda neler olup bittiğine ve bunların nasıl gerçekleştiğine dair genel bir bakışa sahip olabiliriz. yapılandırılmıştır. Sizi uygulamayı inceleyerek yüklediğimiz politikaların durumunu kontrol edip edemeyeceğinizi görmeye davet ediyorum. Kuma kontrol düzlemi, diğer adıyla GUI, Mesh'imizde anlaşılması ve takip edilmesi kolay olacak şekilde tasarlanmıştır.
Ayrıca JESPROTECH YouTube kanalımda da bununla ilgili bir video hazırladım: