paint-brush
Kuma Meshes 정면 대결 - 알아야 할 모든 것~에 의해@jesperancinha
562 판독값
562 판독값

Kuma Meshes 정면 대결 - 알아야 할 모든 것

~에 의해 João Esperancinha27m2024/04/13
Read on Terminal Reader

너무 오래; 읽다

쿠마 학습을 빠르게 시작하려면 가장 중요한 것 중 하나가 클러스터입니다. 그런 다음 Kubernetes(k8s라고도 함)에서 Pod의 상태를 확인하는 명령도 필요합니다.
featured image - Kuma Meshes 정면 대결 - 알아야 할 모든 것
João Esperancinha HackerNoon profile picture
0-item
1-item

쿠마 메시 정면 대결 - 초보자용 가이드

Kuma 학습을 빠르게 시작하려면 가장 중요한 것 중 하나가 클러스터입니다. 그런 다음 Kubernetes(일명 k8s )에서 포드의 상태를 확인하기 위한 명령도 필요하고, Kuma 설치할 수도 있어야 하며, 마지막으로 몇 가지 Kuma 명령을 실행할 수도 있어야 합니다.


이는 Kuma 에 대한 모든 준비를 완료하려면 4가지 필수 명령을 설치해야 한다는 말을 길게 표현한 것입니다. 이러한 명령은 다음과 같습니다.

  • kind - Docker에서는 Kubernetes라고도 합니다. 이는 kubectl 만으로 무언가를 생성하는 무게를 활용하는 명령입니다.


  • kubectl - 이미 k8s 작업에 익숙하다면 이 목록에서 가장 기대되는 것일 것입니다. 이것이 k8s 클러스터에 명령을 내리는 방법입니다.


  • helm - Helm을 사용하면 특히 Kuma 제어 평면 설치를 허용하는 몇 가지 매우 편리한 스크립트를 실행할 수 있습니다.


  • kumactl - 이 가이드에서는 이 명령을 자주 사용하지 않을 것이지만, 사용 방법을 알고 있는 것이 중요합니다.


이 가이드는 Ubuntu 에서 이를 수행하는 방법을 알려줄 것입니다. 이 모든 것은 Ubuntu 시스템에서 테스트되었습니다. Mac-OS , Windows 또는 기타 운영 체제에 이 제품을 설치하는 방법에 대한 가이드에 관심이 있으시면 제 YouTube 채널 JESPROTECH 커뮤니티 에서 알려주세요.


I. 명령 설치


이미지 설명


Docker의 종류( k8s )

종류를 설치하려면 다음 명령을 실행해야 합니다.

 [ $(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 배포판 내에서도 시스템마다 다를 수 있습니다.


인증서 및 GPG 키 설치

특정 GPG 키가 있는 상태에서 helmkubectl 명령을 모두 설치해야 합니다. 다음은 Linux apt 배포판의 로컬 저장소에 추가하는 방법입니다.

 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

이전 단계가 완료되면 Kubectl 설치는 매우 쉽습니다.

 sudo apt-get install -y kubelet kubeadm kubectl


kubelet , kubeadmkubectl 명령은 필수는 아니지만 설치하는 것이 좋습니다.


지배

이미 짐작하셨겠지만 이제 helm 은 설치도 매우 쉽습니다.

 sudo apt-get install -y helm

쿠마

Kuma 설치에는 하나의 수동 단계가 필요하기 때문에 다소 번거로울 수 있지만 먼저 종속성을 다운로드해야 합니다.

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


이 명령을 실행하기 전에 HOME 폴더에 있어야 합니다. 예를 들어 Kuma를 제거하기로 결정한 경우 쉽게 접근할 수 있고 쉽게 발견할 수 있는 장소에 Kuma 설치하는 것이 중요합니다.


이 작업이 끝나면 bin 폴더를 PATH에 추가하는 것도 매우 중요합니다.

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


이 줄을 시작 스크립트의 끝이나 사이에 추가하면 이 프로세스가 쉬워집니다. 시작 스크립트는 .bashrc , .zshrc , .profile 중 하나일 수 있으며 다른 형식을 취할 수도 있습니다.


k9s

k9s 설치도 다른 응용 프로그램과 상당히 다릅니다. 이 경우 Linuxpacman 또는 brew 사용할 수 있습니다. 나는 주로 Mac-OS 에서 brew 사용했고 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 충돌한다는 것입니다.


II. 클러스터 생성

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


첫 번째 명령은 wlsm-mesh-zone 이라는 클러스터를 생성합니다. 이것은 Kuma를 설치하는 데 사용할 클러스터입니다. 두 번째 명령은 클러스터의 상태를 확인하는 데 사용됩니다.


III. 로컬 Docker 레지스트리 생성

앞서 언급했듯이 도커 레지스트리를 아주 쉽게 만들 수 있습니다. 만드는 것이 쉽다고 생각될 수도 있지만 이를 수행하는 스크립트는 몇 개 되지 않습니다. 따라서 가장 좋은 방법은 웹사이트에서 이미 제공되는 종류를 복사하여 붙여넣는 것입니다. 여기에서 이 스크립트를 다운로드할 수 있습니다.

 #!/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



이 스크립트는프로젝트의 루트 폴더 에서 찾을 수 있습니다. 그리고 로컬 Docker 레지스트리를 설치하려면 이 bash 스크립트만 실행하면 됩니다.


IV. 코드가 생성된 방법

이 블로그 게시물의 예제로 제공한 코드에 대해 할 말이 많을 수 있습니다. 그러나 이 경우에는 몇 가지 주요 측면에만 초점을 맞추겠습니다.리스너 서비스 부터 수집기 ,데이터베이스 까지 시작해 보겠습니다. 서비스를 로컬로 실행하거나 docker-compose 구성을 사용하여 컨테이너를 작동시킬 때 일반적으로 컨테이너 이름 또는 hostname 으로 구성한 이름으로 자동 할당되는 DNS 속성 이름을 사용합니다.


k8s 에는 클러스터 전체에서 호스트 이름을 사용할 수 있게 만드는 일련의 규칙도 있습니다. 리스너 및 컬렉터 예제를 살펴보겠습니다.


리스너 예

리스너는 Spring framework 사용하여 Java 로 개발된 애플리케이션입니다. 이런 방식으로 생성된 모든 애플리케이션과 마찬가지로 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 액세스할 수 있어야 하며 이를 위해 정의 파일 application-prod.properties 가 있는 prod 프로필이 있습니다.

 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개의 요소가 있습니다. 마지막 3개는 정적이며 처음 2개는 우리가 도달하려는 시스템에 따라 다릅니다. 왼쪽에는 서비스 이름과 네임스페이스를 배치합니다. 이는 클러스터 내에서 컨테이너가 서로 어떻게 연결되어 있는지 이해하는 것이 중요합니다.


살펴보고 흥미로운 코드 부분은 물론 컨트롤러와 서비스입니다. 컨트롤러는 다음과 같습니다.

 @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 사용하여 구현된 모든 애플리케이션과 마찬가지로 이 첫 번째 애플리케이션은 반응적이며 모두 tomcat 대신 netty 사용합니다. 지금은 이 코드에서 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()) } } }



V. 스크립트 배포

배포는 일반적으로 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 , imagePullPolicycontainerPort 입니다. 이미지는 우리가 사용하는 Docker 이미지의 전체 태그입니다.


kind 로 생성된 docker 레지스트리에 대해 구성되는 포트는 5001이며 이는 이미지의 태그에 포함됩니다. 이는 태그로 작동할 뿐만 아니라 Docker 레지스트리에 대한 연결로도 작동합니다. 이렇게 하면 이미지를 가져와서 Kubernetes 환경에서 실행할 컨테이너를 만들 수 있습니다.


하지만 물론 이미지를 사용하려면 이미지를 생성해야 합니다. 이를 위해 listener 예제와 database 예제에서 이것이 어떻게 수행되는지 살펴보겠습니다. listener 의 Docker 이미지는 다음과 같이 정의됩니다.

 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 단순히 다음과 같이 jar를 호출합니다.

 #!/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 init 디렉터리에 create-multiple-postgresql-databases.shmultiple 파일과 폴더의 복사본을 만듭니다. 마지막으로 데이터베이스와 사용자 이름/비밀번호 조합을 정의하기 위해 해당 스크립트에 사용되는 변수를 정의합니다.


데이터베이스는 다음 스키마를 사용하여 생성됩니다.

 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 라는 이름으로 동물 한 마리를 등록하겠습니다. 피퀴뉴(Piquinho)는 단순히 센서가 부착되어 세계를 여행하는 여행하는 알바트로스의 이름이며, 우리는 센서가 우리에게 보내는 데이터를 읽고 있습니다. 종을 정의하는 두 개의 테이블이 있습니다. 그것이 종을 정의하는 종과 속입니다. 이들은 테이블 familiesgenuses .


테이블 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


6. 애플리케이션 실행

애플리케이션을 실행하려면 모든 포트를 열어야 하며, 포트가 모두 열리면 화면에 다음과 같은 내용이 표시되어야 합니다.

이미지 설명

localhost 및 포트 5432 사용하여 데이터베이스에 연결할 수 있습니다. 연결 문자열은 jdbc:postgresql://localhost:5432/wlsm 입니다. 그리고 이에 접근하기 위해 admin / admin 의 사용자 이름/비밀번호 조합을 사용합니다.


테스트를 수행하기 전에 가장 먼저 해야 할 일은 Piquinho 의 ID를 아는 것입니다. 다음과 같은 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 }


이 파일을 사용하려면 ID를 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 - 1부

MeshTrafficPermission 은 Kuma에서 선택할 수 있는 기능 중 하나이며 아마도 가장 많이 사용되는 기능일 것입니다.


하지만 먼저 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.

지금은 이 경고를 무시해도 됩니다.

IX MeshTrafficPermission - 2부

이제 재미있는 부분이 나옵니다. 가장 먼저 할 일은 모든 포드 간의 모든 트래픽을 비활성화하는 것입니다.

 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)


이는 Pod 간의 모든 트래픽이 거부된다는 의미입니다. 현재 우리가 가지고 있는 것은 조직 내의 잠재적인 악의적 행위자로부터 보호되는 내부 시스템이지만 이제 모든 포드 간의 트래픽도 차단했습니다. 따라서 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가 hostname 생성과 마찬가지로 기능적 목적으로도 사용되는 name 어떻게 해석하는지 주목하는 것이 중요할 것입니다.


이러한 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)

X - MeshFaultInjection

마지막으로 또 다른 기능을 예로 제공하기 위해 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 테이블이 어떻게 보이는지 살펴보겠습니다.

이미지 설명

XI - 결론

지금까지 이 기사를 따르고 컴퓨터에서 클러스터를 실행할 수 있었기를 바랍니다. 어쨌든 이 기사를 읽고 Kuma에 대해 좀 더 이해하고 배우기 위해 시간을 내주셔서 감사합니다. 저는 개인적으로 네트워크와 환경을 훨씬 더 세밀하게 구성하고 제어할 수 있게 되므로 이 기능의 활용도가 매우 높으며 Kuma 의 미래도 밝다고 봅니다.


엔터프라이즈 버전인 Kong-Mesh 는 꽤 완성도가 높아 보입니다. 쿠마는 오픈 소스입니다. 테스트용으로도 좋고 기업용으로도 좋은 것 같습니다. 저는 메시라는 주제가 매우 흥미롭다고 생각하며, Kuma 메시의 작동 방식을 배우고 네트워크 내에서 데이터 흐름을 더 잘 제어할 수 있는 방법에 대한 느낌을 얻을 수 있는 좋은 방법을 제공한다고 생각합니다.


서비스 상태를 보려면 다음 localhost 위치에 있는 Kuma 제어 평면으로 이동하면 됩니다: http://localhost:5681/gui/meshes/default/services?page=1&size=50 :

이미지 설명

Kuma 제어 플레인에서는 설치된 정책을 살펴보고, 포드 상태를 확인하고, 백그라운드에서 무슨 일이 일어나고 있는지 모니터링할 수 있으며, 일반적으로 메시에서 무슨 일이 일어나고 있는지, 어떻게 진행되는지에 대한 개요를 볼 수 있습니다. 구성되어 있습니다. 신청서를 검토하여 우리가 설치한 정책의 상태를 확인할 수 있는지 확인하시기 바랍니다. GUI라고도 불리는 Kuma 제어 평면은 메쉬를 이해하고 후속 조치를 취하기 쉽도록 정확하게 만들어졌습니다.

XII - 자원

또한 바로 여기 JESPROTECH YouTube 채널에 이에 대한 비디오를 만들었습니다.