Чтобы быстро начать изучать Kuma
, нам понадобится кластер. Затем нам также нужна команда, чтобы узнать статус наших подов в Kubernetes (она же k8s
), нам также нужно иметь возможность устанавливать Kuma
и, наконец, нам также нужно иметь возможность выдавать некоторые команды Kuma
.
Это длинный путь к тому, что нам нужно установить 4 основные команды, чтобы все было готово для Kuma
. Эти команды:
kind
— в Docker он также известен как Kubernetes. Это команда, которая позволяет создавать вещи только с помощью kubectl
.
kubectl
— Наверное, самый ожидаемый в этом списке, если вы уже привыкли работать с k8s
. Вот как мы можем подавать команды нашему кластеру k8s
.
helm
— Helm позволяет нам выполнять некоторые очень удобные скрипты, которые позволяют, среди прочего, устанавливать плоскость управления Kuma
.
kumactl
— в этом руководстве мы не будем часто использовать эту команду, но важно знать, как ее использовать.
Это руководство расскажет вам, как это сделать в Ubuntu
. Все это было протестировано в системе Ubuntu
. Если вас интересует руководство по установке этого приложения в Mac-OS
, Windows
или любой другой операционной системе, пожалуйста, сообщите мне об этом на моем канале YouTube в сообществе JESPROTECH
.
k8s
) в DockerЧтобы установить kind, нам нужно выполнить следующие команды:
[ $(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
будет установлена в ваш /usr/local/bin/kind
. Это может варьироваться в зависимости от системы, даже в пределах дистрибутивов Linux.
Команды helm
и kubectl
необходимо устанавливать при наличии определенных ключей GPG
. Вот как мы можем добавить их в наш локальный репозиторий нашего apt
Linux:
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
очень проста после выполнения предыдущего шага:
sudo apt-get install -y kubelet kubeadm kubectl
Команды kubelet
, kubeadm
и kubectl
не являются обязательными, но их рекомендуется установить.
Как вы уже догадались, helm
теперь очень легко установить:
sudo apt-get install -y helm
Установка Kuma
может быть немного громоздкой, поскольку она включает в себя один шаг вручную, но сначала нам нужно загрузить наши зависимости:
cd ~ || exit; curl -L https://kuma.io/installer.sh | VERSION=2.6.1 sh -
Перед вводом этой команды убедитесь, что вы находитесь в своей папке HOME
. Важно установить Kuma
в таком месте, где он будет легко доступен и легко заметен, если мы, например, решим его удалить.
Как только мы закончим с этим, также очень важно добавить папку bin
в нашу PATH:
export PATH=~/kuma-2.6.1/bin:$PATH;
Добавление этой строки в конец или где-нибудь между вашим стартовым сценарием облегчит этот процесс. Ваш сценарий запуска может быть любым из этих .bashrc
, .zshrc
, .profile
и, возможно, принимать другую форму.
Установка k9s
также сильно отличается от других приложений. В этом случае мы можем использовать либо pacman
, либо brew
для Linux
. Я использовал brew
в основном для Mac-OS
и почти никогда не нуждался в нем в Linux, но в данном случае он очень нужен, поэтому для начала нам нужно установить Brew следующим образом:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
После завершения установки Brew все, что нам нужно сделать, это установить k9s
(« kanines
»):
brew install derailed/k9s/k9s
Важно принять во внимание одну вещь, и вы, вероятно, заметите это после установки и запуска k9s
в первый раз: это то, что k9s
выйдет из строя, если кластер, который он контролирует, будет удален и/или добавлен.
kind create cluster --name=wlsm-mesh-zone kubectl cluster-info --context kind-wlsm-mesh-zone
Первая команда создает кластер с именем wlsm-mesh-zone
. Это всего лишь кластер, который мы будем использовать для установки Kuma. Вторая команда используется для проверки состояния кластера.
Как я упоминал ранее, мы можем довольно легко создать реестр докеров. Как бы легко это ни звучало, скрипта для этого очень мало. Итак, лучше всего просто скопировать и вставить тот вариант, который уже доступен на их веб-сайте. Здесь мы можем скачать этот скрипт :
#!/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
Этот скрипт можно найти в корневойпапке проекта . А для установки локального реестра докера нам нужно всего лишь запустить этот bash-скрипт.
Можно многое сказать о коде, который я привел в качестве примера для этой статьи в блоге. Однако в данном случае давайте просто сосредоточимся на нескольких ключевых аспектах. Начнем отслужбы прослушивания к сборщику , а затем кбазе данных . Когда мы запускаем службы локально или даже используем конфигурацию docker-compose
для запуска контейнеров, обычно мы используем имена, присвоенные DNS, которые автоматически назначаются в качестве имени контейнера или имени, которое мы настраиваем с помощью hostname
.
В k8s
также существует набор правил, которые делают имена хостов доступными во всем кластере. Давайте посмотрим на примеры слушателей и сборщиков:
Слушатель — это приложение, разработанное на Java
с использованием Spring framework
. Как и все приложения, созданные таким образом, существует также файл 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
Из всех этих свойств наиболее важным на данный момент является свойство wslm.url.collector
. С конфигурацией default
мы можем запускать эту службу локально без необходимости использования какой-либо контейнерной среды. Однако в кластере k8s
нам необходимо иметь доступ к collector
, и для этого у нас есть профиль prod
с файлом определения application-prod.properties
:
wslm.url.collector=http://wlsm-collector-deployment.wlsm-namespace.svc.cluster.local:8081/api/v1/collector
Это свойство пытается связаться с хостом wlsm-collector-deployment.wlsm-namespace.svc.cluster.local
. Этот файл имеет следующую конфигурацию:
<Service Name>.<Namespace>.svc.cluster.local
У нас есть 5 элементов, разделенных точками. Последние три статичны, а первые два зависят от машины, к которой мы пытаемся обратиться. Слева мы помещаем имя службы, а затем пространство имен. Это важно для понимания того, как контейнеры связаны друг с другом внутри кластера.
Часть кода, на которую интересно взглянуть, — это, конечно же, контроллер и сервис. Контроллер выглядит так:
@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); } }
А выглядит услуга так:
@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); } }
Как вы, возможно, уже заметили, это первое приложение, как и все приложения, реализованные с использованием Spring Framework
в этом репозитории, является реактивным, и все они используют netty
вместо tomcat
. На данный момент мы можем игнорировать использование hazelcast
в этом коде. . Это будет использоваться в последующих версиях этого проекта.
На этом этапе сборщик работает точно так же, как и слушатель. На данный момент его единственная обязанность — передавать данные от прослушивателя в базу данных, и для этого сборщику нужно только точно знать, где находится база данных. Давайте проведем тот же анализ application.properties file of this project
:
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
Эти свойства являются минимумом, необходимым для запуска службы. Однако это предназначено только для возможности запуска его локально. И для этого сервиса у нас также есть файл профиля prod
, и мы можем посмотреть его в application-prod.properties
здесь:
spring.r2dbc.url=r2dbc:postgresql://wlsm-database-deployment.wlsm-namespace.svc.cluster.local:5432/wlsm
Соединение с базой данных в данном случае относится к хосту базы данных:
wlsm-database-deployment.wlsm-namespace.svc.cluster.local
Это снова следует за тем же анализом, который мы видели раньше. Слева мы видим имя службы, за которым следует пространство имен, к которому в конце добавляется svc.cluster.local
.
И для этого сервиса мы также используем контроллер и сервис. Контроллер выглядит так:
@RestController @RequestMapping class CollectorController( val collectorService: CollectorService ) { @PostMapping("animals") suspend fun listenAnimalLocation(@RequestBody animalLocationDto: AnimalLocationDto): AnimalLocationDto = run { collectorService.persist(animalLocationDto) animalLocationDto } }
А выглядит услуга так:
@Service class CollectorService( val applicationEventPublisher: ApplicationEventPublisher ) { fun persist(animalLocationDto: AnimalLocationDto) = applicationEventPublisher.publishEvent(AnimalLocationEvent(animalLocationDto)) }
Служба использует издатель событий, который называется applicationEventPublisher
, который следует архитектуре потоковой передачи событий, которая позже обрабатывается в этом прослушивателе событий, и мы легко можем видеть, что он использует r2dbc
для сохранения парадигм реализаций реактивной архитектуры:
@Service class EventHandlerService( val animalLocationDao: AnimalLocationDao ) { @EventListener fun processEvent(animalLocationEvent: AnimalLocationEvent){ println(animalLocationEvent) runBlocking(Dispatchers.IO) { animalLocationDao.save(animalLocationEvent.animalLocationDto.toEntity()) } } }
Развертывание k8s
обычно является очень простой задачей. Однако также важно взглянуть на конфигурацию, необходимую для наших сервисов. Например, давайте посмотрим на реализацию прослушивателя:
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
В этой конфигурации три блока. Первый блок — это блок пространства имен. Конфигурация пространства имен имеет решающее значение для того, чтобы Kuma могла внедрить дополнительные функции посланника, необходимые для применения политик. Без определенного пространства kuma
не сможет этого сделать. Еще одна вещь, на которую нам нужно обратить внимание при настройке kuma, это то, что пространство имен должно содержать правильную метку, которую Kuma распознает:
kuma.io/sidecar-injection: enabled.
Определение пространства имен с правильной меткой жизненно важно для работы Kuma. Во втором блоке мы находим определение развертывания. Вот как мы определяем, как будет выглядеть развертывание нашего модуля в нашем кластере Kubernetes. Здесь важно сосредоточиться на image
, imagePullPolicy
containerPort
. Изображение — это полный тег образа Docker, который мы используем.
Порт, который настраивается для нашего реестра докеров, созданного с помощью kind
— 5001, и он включен в тег нашего образа. Он работает как тег, а также как соединение с нашим реестром Docker. Таким образом, мы сможем извлечь образы и создать контейнер для запуска в нашей среде Kubernetes.
Но, конечно, чтобы иметь возможность использовать изображения, нам нужно их создавать, и для этого давайте посмотрим, как это делается в примере listener
и в примере database
. Образ докера для listener
определяется следующим образом:
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"]
Все начинается с базового образа под названием eclipse-temurin:21-jdk-alpine
. После этого мы просто копируем jar, созданный при сборке проекта, а затем копируем его в наш образ. Перед этим мы также копируем entrypoint.sh
в контейнер и определяем ENTRYPOINT
для ее использования. entrypoint
просто вызывает банку следующим образом:
#!/usr/bin/env sh java -jar -Dspring.profiles.active=prod wlsm-listener-service.jar
Служба database
совершенно другая, поскольку она использует несколько сценариев с открытым исходным кодом, доступных в Интернете:
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
Этот скрипт создает копию следующего файла и папки в каталоге инициализации Docker: create-multiple-postgresql-databases.sh
и multiple
. Наконец, мы просто определяем переменные, используемые в этих сценариях, для определения нашей базы данных и комбинаций имени пользователя и пароля.
База данных создается по следующей схеме:
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) );
И в качестве примера данных мы зарегистрируем одно животное по имени piquinho
. Пикиньо — это просто имя путешествующего альбатроса, который путешествует по всему миру, к которому прикреплен датчик, и мы читаем данные, которые датчик отправляет нам. Есть две таблицы, определяющие виды. Именно вид и род определяют вид. Это таблицы families
и genuses
.
Таблица species
определяет вид, к которому принадлежит животное. Наконец, мы определяем animal
в одноименной таблице, где регистрируются вид и название животного. База данных выглядит следующим образом:
Чтобы собрать, создать образы и запустить наш проект, мы можем запустить следующие команды, доступные в Makefile
:
make make create-and-push-images make k8s-apply-deployment
Первый make — это просто команда gradle build
. Вторая команда использовала переменную:
MODULE_TAGS := aggregator \ collector \ listener \ management \ database
бежать:
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
Это просто проходит через каждый модуль и использует стандартную общую команду, которая изменяется в зависимости от значения, указанного в MODULE_TAGS
, для создания образов и отправки их в локальный реестр через порт 5001. Следуя той же стратегии, мы можем затем использовать третью команду для развертывания нашего стручки. Третья команда использует другой цикл, который выглядит следующим образом:
@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
В этом случае он применяет каждый сценарий развертывания к каждой службе. Если мы запустим команду kubectl get pods --all-namespaces
, мы должны получить такой вывод:
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
На этом этапе нам следует наблюдать наличие kuma-control-plane
, kube-controller-manager
и всех служб, работающих в нашем собственном wlsm-namespace
. Наш кластер изолирован снаружи, и чтобы иметь доступ к различным портам, нам необходимо создать port-forwarding
для каждого модуля, к которому мы хотим получить доступ. Для этого мы можем выдать эти команды на отдельных вкладках:
Мы также можем взглянуть на это, взглянув на k9s
:
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
Чтобы запустить приложение, нам следует открыть все порты, и когда они все будут открыты, мы должны увидеть на наших экранах что-то вроде этого:
Мы можем подключиться к базе данных, используя localhost
и порт 5432
. Строка подключения такая: jdbc:postgresql://localhost:5432/wlsm
. И для доступа к нему мы затем используем комбинацию имени пользователя и пароля admin
/ admin
.
Первое, что нам нужно сделать, прежде чем проводить какой-либо тест, — это узнать идентификатор Piquinho
, и мы можем сделать это с помощью таких инструментов базы данных Intellij:
В корневой папке проекта есть файл test-requests.http
. Это рабочий файл для создания запросов REST к нашим открытым портам:
### 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 }
Чтобы иметь возможность использовать этот файл, нам нужно всего лишь заменить идентификатор, в этом примере, с 2ffc17b7-1956-4105-845f-b10a766789da
на d5ad0824-71c0-4786-a04a-ac2b9a032da4
. В этом случае мы можем делать запросы от сборщика или от слушателя. Оба запроса должны работать, и впоследствии мы должны увидеть такой ответ на каждый запрос:
{ "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)
Поскольку оба порта открыты и на данный момент они имеют один и тот же тип полезной нагрузки, мы можем выполнять одни и те же запросы к прослушивателю и сборщику. После выполнения этих двух запросов мы должны найти результаты в таблице animal_locations
:
Итак, это подтверждает только то, что кластер работает правильно, и теперь мы готовы протестировать политики с нашей сеткой Kuma.
MeshTrafficPermission
— одна из функций, которые мы можем выбрать в Kuma, и она, вероятно, наиболее используемая.
Но сначала давайте рассмотрим плоскость управления Кумы. Включив всю переадресацию, мы можем просто перейти по адресу localhost:5681/gui и визуализировать наши сетки Kuma. На главной странице мы должны увидеть что-то вроде этого:
На данный момент смотреть особо нечего, но давайте теперь применим MeshTrafficPermission
:
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 -
Применив это, мы должны получить такой ответ: meshtrafficpermission.kuma.io/mtp created
.
Применение сетки мало что меняет в настройке нашего кластера. Что он делает, так это позволяет нам настраивать политику маршрутизации трафика.
Есть много вещей, из которых мы можем выбирать, но одна из самых очевидных вещей, которые мы можем выбрать, — это mTLS.
В противном случае его называют взаимным TLS, что вкратце означает, что сертификаты взаимно принимаются и проверяются для установления личности между сторонами и установления зашифрованного трафика данных.
Это можно сделать автоматически, используя следующую простую конфигурацию Mesh
:
echo "apiVersion: kuma.io/v1alpha1 kind: Mesh metadata: name: default spec: mtls: enabledBackend: ca-1 backends: - name: ca-1 type: builtin" | kubectl apply -f -
После применения этой политики мы можем увидеть такое предупреждение:
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.
На данный момент мы можем игнорировать это предупреждение.
Теперь самое интересное: первое, что мы собираемся сделать, это отключить весь трафик между всеми модулями:
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
, если мы попытаемся сделать какой-либо запрос, используя любую переадресацию портов, мы получим:
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)
Это означает, что весь трафик между модулями блокируется. Сейчас у нас есть внутренняя система, защищенная от возможных злоумышленников внутри нашей организации, но мы также заблокировали трафик между всеми модулями. Итак, mTLS
— это отличная вещь, но блокировка всего трафика — это совсем не так.
Чтобы сделать это идеально, нужно просто сделать исключения из правила DENY
all, а для этого нам нужна политика, которая разрешает трафик между прослушивателем и сборщиком, а также сборщиком и базой данных. Начнем с трафика между сборщиком и базой данных:
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 -
В данном случае мы позволяем трафику данных течь от сборщика targetRef
к базе данных targetRef
. Если вы этого не знаете, возможно, важно обратить внимание на то, как Kuma интерпретирует name
, которое, как и создание hostname
, также используется для функциональных целей.
Общий способ создания этих name
выглядит следующим образом:
<service name>_<namespace>_svc_<service port>
В данном случае разделителем является подчеркивание, и создание имени таким образом позволяет Kuma
точно знать, что разрешено. В этом случае, если мы применим эту политику, мы сможем отправлять запросы сборщику после получения этого ответа: meshtrafficpermission.kuma.io/wlsm-database created
.
И при их создании ответ теперь должен быть 200
подтверждающий, что запись о местоположении отправлена сборщику:
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)
Однако мы все еще не определили исключения для трафика между прослушивателем и сборщиком, поэтому выполнение запроса таким образом приведет к следующему:
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)
И это, конечно, ожидаемо. Давайте теперь применим другую политику для этого трафика данных:
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 -
Делаем возможным выполнение запросов от слушателя к коллектору:
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)
Наконец, просто чтобы привести еще одну функцию в качестве примера, мы также можем использовать другую функцию под названием MeshFaultInjection
, которая может быть очень полезна при выполнении тестов с помощью Kuma
. Мы можем смоделировать потенциальные проблемы в нашей сетке и проверить, например, правильно ли выполняется обработка ошибок.
Мы также можем проверить другие вещи, например, как настроенные нами автоматические выключатели могут реагировать на ошибочные соединения или высокоскоростные запросы.
Итак, давайте попробуем. Один из способов применения MeshFaultInjection
выглядит следующим образом:
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 -
С помощью этой политики мы говорим, что трафик, исходящий от прослушивателя и входящий к коллектору, будет иметь 50% вероятность успеха. Результаты запроса непредсказуемы, поэтому после применения этой политики мы можем ожидать ошибок или успешных запросов к конечной точке прослушивателя.
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)
Наконец, просто ради интереса, мы можем посмотреть, как сейчас выглядит наша таблица animal_location
:
Я надеюсь, что вы до сих пор читали эту статью и смогли запустить кластер на своем компьютере. В любом случае спасибо за прочтение этой статьи и за то, что вы потратили немного времени, чтобы понять и узнать больше о Куме. Лично я вижу в этом большое применение и большое будущее для Kuma
поскольку он позволяет настраивать и осуществлять гораздо более детальный контроль над нашей сетью и нашей средой.
Его корпоративная версия Kong-Mesh
кажется вполне законченной. Кума имеет открытый исходный код. и, кажется, это отлично подходит для тестирования, а также для предприятий. Я нахожу тему сеток очень интересной и думаю, что Kuma
предоставляет отличный способ узнать, как работают сетки, и понять, как мы можем лучше контролировать поток данных в нашей сети.
Если мы хотим увидеть состояние наших сервисов, мы можем просто перейти на нашу плоскость управления Kuma
в этом расположении localhost
: http://localhost:5681/gui/meshes/default/services?page=1&size=50 :
В плоскости управления Kuma мы также можем просмотреть установленные политики, проверить состояние наших модулей, отслеживать, что происходит в фоновом режиме, и в целом просто получить представление о том, что происходит в нашей сетке и как это происходит. настроен. Я предлагаю вам просто зайти в приложение и посмотреть, сможете ли вы проверить состояние установленных нами политик. Плоскость управления Kuma, также известная как графический интерфейс, создана специально для того, чтобы ее было легко понять и отслеживать нашу сетку.
Я также снял видео об этом на своем канале JESPROTECH на YouTube прямо здесь: