[k8s/스프링/테스트] 미니큐브를 사용하여 로컬 환경에서 스프링 웹 애플리케이션 성능 테스트 및 실시간 모니터링

목적

  • 도커 컨테이너 기술과 컨테이너 오케스트레이션 시스템인 k8s를 사용하여 로컬 컴퓨터 상의 격리된 공간 상에서 애플리케이션을 성능 테스트할 수 있도록 로컬 테스트 환경을 구성한다.
  • 파드의 리소스를 선언적으로 손쉽게 변경하여 성능 테스트 시 리소스에 따른 애플리케이션의 처리량 한계점, 애플리케이션 간 병목 현상을 확인한다.
  • 실제 외부 API 서비스는 시뮬레이션 툴이나 목 서버로 대체하여 격리된 공간 상에서 특정 애플리케이션을 대상으로만 성능 테스트를 수행한다.
  • 카오스 엔지니어링 도구를 사용하여 장애 상황에 대한 가설을 수립하고 실험하여 시스템의 안정성과 회복성을 높인다.


과정

  1. 미니큐브(Minikube) 설치 및 실행
    1. 미니큐브 설치: https://minikube.sigs.k8s.io/docs/start/

    2. 미니큐브 실행 (쿠버네티스 이미지 다운로드 및 도커 컨테이너 생성, 클러스터 시작)

       minikube start
              
       # 리소스 설정
       minikuve start --cpus=3 --memory=4096
      
    3. 메트릭 서버 애드온 활성화

       minikube addons enable metrics-server
      
    4. 대시보드 애드온 활성화 및 실행

       minikube addons ebable dashboard
       minikube dashboard
      
    5. kubectl 설정

       alias kubectl="minikube kubectl --"
      
  2. 헬름(Helm) 설치 및 실행
    1. 헬름 설치: https://helm.sh/docs/intro/install/

    2. 리포지토리 추가

       helm repo add bitnami https://charts.bitnami.com/bitnami
      
    3. 설치 가능한 차트 리스트 확인

       # 허브에서 검색
       helm search hub
      
       # 특정 리포지토리에서 검색
       helm search repo bitnami
      
    4. 차트(패키지) 설치

       helm install <릴리스명> <차트명>
      
      • 차트(chart)는 k8s 클러스터 내 애플리케이션, 서비스 등을 실행하기 위한 모든 리소스 정의를 포함하고 있다. 차트 설치 명령어를 실행하면 헬름은 자동으로 연결된 k8s 클러스터에 자동으로 차트를 설치하고, 각 차트에 대한 새 릴리스를 생성한다.
    5. 차트 삭제

       helm delete <릴리스명>
      
      • 차트를 삭제하면 차트와 연결된 모든 k8s 구성 요소를 제거되고 릴리스가 삭제된다.
  3. 스프링 부트 애플리케이션 구성
    1. 스프링 부트 액추에이터 모듈 의존성 추가

    2. 마이크로미터 모듈(프로메테우스) 의존성 추가

    3. 애플리케이션 속성 설정

      • 스프링 부트 액추에이터 엔드포인트 설정 변경

          management:
            endpoints:
               web:
                 exposure:
                   include: "prometheus"
        
        • 기본적으로 /actuator/prometheus 엔드포인트는 사용할 수 없으며 노출 설정해야 한다.
      • 애플리케이션명 설정

          spring:
            application:
              name: 애플리케이션명
          management:
            metrics:
              tags:
                application: ${spring.application.name} 
        
        • 대시보드가 서로 다른 애플리케이션을 구별하기 위해 job 태그를 사용하는 대신 모든 메트릭에 적용되는 공통 태그인 application 태그를 사용하는 경우 management.metrics.tags.application 속성을 지정한다.
  4. 미니큐브의 도커 데몬 구성 변경

    • 환경 변수 설정 (터미널에서 미니큐브 내부의 도커 데몬을 사용하도록 설정)

        eval $(minikube -p minikube docker-env)
      
        # 환경 변수 설정 초기화
        eval $(minikube -p minikube docker-env -u)
      
      • minikube docker-env 명령어는 도커 CLI가 미니큐브 내부의 도커 엔진(데몬)을 가리키도록 하기 위한 여러 환경 변수명과 값, 그리고 관련 정보를 제공한다. eval 명령어 실행을 통해 로컬 OS의 환경 변수를 설정하여 도커 CLI가 사용하는 관련 환경 변수를 변경한다. 이를 통해 도커 이미지를 사용하여 미니큐브 클러스터 내부에 곧바로 애플리케이션을 빌드할 수 있을 뿐만 아니라 도커 CLI의 모든 명령어를 실행할 수 있다. 그래들 플러그인이나 테스트컨테이너 등의 개발 도구가 로컬 도커 데몬과 통신하는 대신 미니큐브가 제공하는 도커 데몬과 통신하도록 하기 위해서는 위 설정이 필수적이다.
    • 위 설정 대신 미니큐브에 직접 로컬 도커 이미지 로드할 수도 있다.

      minikube image load <이미지명:태그명>
      
      • 동일한 이미지명:태그명의 이미지를 새로 로드할 경우 기존 이미지를 삭제 후 로드해야 한다.

      • 도커 이미지 확인

          minikube images ls
        
  5. 스프링 애플리케이션 도커 이미지 생성 및 미니큐브 클러스터에 로드 (그래들 플러그인이 제공하는 bootBuildImage 태스크 사용)
    1. minikube docker-env 명령어 실행

       minikube docker-env
      
       export DOCKER_TLS_VERIFY=1
       export DOCKER_HOST=tcp://127.0.0.1:7602
       export DOCKER_CERT_PATH=C:\Users\유저명\.minikube\certs
       export MINIKUBE_ACTIVE_DOCKERD="minikube"
      
      • 위 명령어 실행 결과 출력되는 환경 변수명과 값을 기반으로 그래들 bootBuildImage 태스크의 docker 프로퍼티를 설정한다. 도커 컨텍스트의 정보를 보여주는 docker context inspect 명령어를 사용하여 도커 데몬 정보, 쿠버네티스 정보 등을 확인할 수도 있다.
    2. bootBuildImage 태스크의 docker 프로퍼티 정의

       tasks.named("bootBuildImage") {
         docker {
           host = "tcp://127.0.0.1:7602"
           tlsVerify = true
           certPath = "C:\Users\user\.minikube\certs"
         }
       }
      
      • docker 프로퍼티는 도커 데몬 연결 정보이다. bootBuildImage 태스크는 컨테이너 이미지 빌드를 위해 도커 데몬에 대한 접근이 필요하다. 기본적으로 로컬 연결을 통해 도커 데몬과 통신하지만 미니큐브 클러스터 내 도커 데몬과 통신하기 위해 위와 같이 설정한다.
  6. 클러스터에 애플리케이션 배포 및 DNS 설정
    1. 디플로이먼트 생성 (클러스터 내 노드에 인스턴스 생성)

       kubectl create deployment <디플로이먼트명> --image=<이미지명:태그명>
      
       apiVersion: v1
       kind: Deployment
       metadata:
         namespace: default
         name: 디플로이먼트명
       spec:
         template:
         spec:
           containers:
             - name: 컨테이너명
               image: 이미지명:태그명
      
    2. 서비스를 사용하여 클러스터 내 디플로이먼트 노출 (클러스터 외부에서 클러스터 내부의 애플리케이션에 접근할 수 있도록 셜정)
      1. NodePort 서비스 사용

         kubectl expose deployment <컨테이너명> --type=NodePort --port=<포트>
        
        • NodePort 접근 설정

          minikube service <서비스명> --url
          
      2. LoadBalancer 서비스 사용

         kubectl expose deployment <컨테이너명> --type=LoadBalancer --port=<포트>
        
        • LoadBalancer 접근 설정

          minikube tunnel
          
      3. CluterIP 서비스를 사용하는 경우 포트포워딩 설정

         kubectl port-forward service/<디플로이먼트명> <외부포트:내부포트>
        
    3. DNS 설정
      1. 클러스터 외부 DNS 설정: 다음 방법 중 하나를 사용하여 클러스터 내부의 애플리케이션이 클러스터 외부의 DNS 서버에 접근하여 도메인 쿼리를 할 수 있도록 만든다.
        1. 도커 데몬 설정 (/etc/docker/deamon.json 파일 설정): 전역 설정
           {
             "dns": ["dns서버ip"],
             "dns-search": ["검색도메인문자열"]
           }
          
        2. 디플로이먼트 설정 (dnsConfig 설정): 생성 및 관리되는 모든 파드에 대해 설정

           apiVersion: v1
           kind: Deployment
           metadata:
             namespace: default
             name: 디플로이먼트명
           spec:
             template:
               spec:
                 dnsPolicy: ClusterFirst
                 dnsConfig:
                   nameservers:
                   - DNS서버IP
                   searches:
                   - 검색도메인
          
        3. 파드 내 설정 (dnsConfig 설정): 특정 파드에 대한 설정

           apiVersion: v1
           kind: Pod
           metadata:
             namespace: default
             name: 파드명
           spec:
             dnsPolicy: ClusterFirst
             dnsConfig:
               nameservers:
               - DNS서버IP
               searches:
               - 검색도메인
          
      2. CoreDNS를 사용한 클러스터 내부 DNS 설정
        1. 디플로이먼트 설정

           apiVersion: v1
           kind: Deployment
           metadata:
             namespace: default
             name: 디플로이먼트명
           spec:
             template:
               spec:
                 hostname: 호스트명
                 subdomain: 서브도메인명
          
  7. 프로메테우스 설치 및 구성
    1. prom/prometheus 도커 이미지 다운로드, 클러스터에 컨테이너 배포 및 실행
    2. 프로메테우스 속성 설정
      • 설정 파일을 직접 수정하여 설정

          scrape_configs:
            - job_name: "spring"
              metrics_path: "/actuator/prometheus"
              static_configs:
                - targets: ["HOST:PORT"]
        
        • /etc/prometheus/prometheus.yml 설정 파일을 직접 수정한다.
      • 컨피그맵을 사용하여 설정 파일 마운팅

        1. 디플로이먼트 설정

           spec:
             template:
               spec:
                 containers:
                   - name: prometheus
                     volumeMounts:
                       - mountPath: /etc/grafana
                         name: prometheus-config-volume
                 volume: 
                   - name: prometheus-config-volume
                     configMap:
                       name: prometheus-config
          
        2. 컨피그맵 설정

           data:
             prometheus.yml: |-
               global:
                 scrape_interval: 5s
                 evaluation_interval: 5s
               scrape_configs:
                 - job_name: "spring"
                   metrics_path: "/actuator/prometheus"
                   static_configs:
                     - targets: ["HOST:PORT"]
          
  8. 그라파나 설치 및 구성
    1. grafana/grafana-oss 도커 이미지 다운로드, 클러스터에 컨테이너 배포 및 실행
    2. 그라파나 대시보드(localhost:3000) 접속
      • 초기 로그인 정보: admin/admin
    3. 프로메테우스를 데이터 소스로 추가 및 구성
      • Connections - Connect data - Data souces - Add data source - Prometheus 추가
    4. 대시보드 설정
  9. 그라파나 k6 설치 및 구성
    1. grafana/k6 도커 이미지 다운로드, 클러스터에 컨테이너 배포 및 실행
    2. 스크립트 파일 작성

       import http from 'k6/http';
       import { sleep } from 'k6';
      
       export default function () {
         http.get('https://test.k6.io');
         sleep(1);
       }
      
  10. 그라파나 k6를 통한 부하 테스트 및 모니터링
    1. 테스트 실행

       $ docker run --rm -i grafana/k6 run - <script.js
      
    2. 가상 유저 추가하기

       import http from 'k6/http';
       import { sleep } from 'k6';
              
       export const options = {
         vus: 10,
         duration: '30s',
       };
              
       export default function () {
         http.get('http://test.k6.io');
         sleep(1);
       }
      
  11. 호버플라이(HoverFly) 설치 및 실행
    1. 헬름 차트 검색 및 설치

       helm repo add incubator https://charts.helm.sh/incubator
       helm search repo hoverfly
       helm install hoverfly incubator/hoverfly
      
      • 호버플라이 차트를 설치하면 기본값으로 CluterIP 타입의 서비스가 생성되며 호버플라이 서버는 프록시 서버로 동작한다.
      • 프록시 서버가 응답을 캡처하도록 하기 위해 LoadBalancer 타입의 서비스를 생성하려면 차트 설치 시 다음과 같이 파라미터를 전달한다.

        helm install <릴리스명> \
          --set service.type='LoadBalancer' incubator/hoverfly
        
    2. 로컬에 호버플라이 CLI 설치 (다운로드)

    3. 로컬 CLI로 원격 호버플라이 인스턴스 제어 설정 (가이드)

    4. 호버플라이 모드를 캡처(Capture)로 설정

    5. 호버플라이 프록시를 사용하여 응답 캡쳐

      1. 실제 API 서비스의 응답 캡쳐

         curl --proxy http://localhost:8500 <외부API서비스>
        
        • 기본 설정된 8500 포트를 사용하여 프록시 서버가 실제 API 서비스의 응답을 캡쳐하도록 한다.
      2. 시뮬레이션 내보내기

         hoverctl -t remote export simulation.json
        
        • 응답 캡처가 완료되면 캡처된 응답을 json 파일로 내보낸다. 웹 서버가 아닌 프록시 서버로 동작할 때 위 명령어를 실행한다.
    6. 호버플라이 서버를 웹 서버로 재기동

       spec:
         template:
           spec:
             containers:
               env:
                 - name: FLAGS
                   value: '-webserver'
      
      • 서버를 직접 재기동하는 대신 디플로이먼트 yaml 파일을 변경한다. FLAGS 환경 변수의 값을 -webserver로 설정한다. 서버를 웹 서버로 기동하면 캡처 모드로 설정은 불가능하다.
    7. 캡처한 응답 시뮬레이션 불러오기 및 시뮬레이션

       hoverctl -t remote import simulation.json
      
      • 캡처한 외부 API와 동일한 엔드포인트 URL을 사용하여 응답을 시뮬레이션을 하도록 한다.
      • 호버플라이 서버를 웹 서버로 기동한 후 위 명령어를 실행해야 한다.
    8. 캡처한 응답 시뮬레이션 삭제

       hoverctl -t remote delete
      


클러스터 내에서 로컬 머신의 프로세스에 접근


랜처 데스크탑

로컬 환경에서 컨테이너를 관리하고 쿠버네티스를 통한 컨테이너 오케스트레이션 환경을 구축하기 위해 미니큐브 대신 랜처 데스크탑(Rancher Desktop)을 사용할 수 있다. 랜처 데스크탑은 도커 데몬과 도커 CLI를 내장하고 있으며 컨테이너 이미지의 빌드 및 실행, 원격 저장소에 대한 이미지의 풀, 푸시를 지원한다. 랜처 데스크탑이 제공하는 컨테이너 엔진에는 containerd와 dockerd(moby)가 있으며 기본적으로 dockerd를 사용한다.

랜처 데스크탑에는 경량 쿠버네티스인 k3s가 내장되어 있어 로컬 환경에서 컨테이너 오케스트레이션 플랫폼으로도 사용 가능하다. 쿠버네티스 클러스터의 정보를 확인하고 관리하기 위한 UI인 클러스터 대시보드도 제공한다.


쿠버네티스 환경에서 오퍼레이터 패턴을 사용한 테스트 자동화

오퍼레이터(operator)란 사용자 리소스 정의(custom resource definition, CRD)를 사용하여 애플리케이션 및 관련 컴포넌트를 관리하는 쿠버네티스의 소프트웨어 익스텐션이다. 오퍼레이터 패턴은 쿠버네티스 자체가 제공하는 것 이상의 작업을 자동화한다. 쿠버네티스 코드 자체를 수정하지 않고도 컨트롤러를 하나 이상의 사용자 정의 리소스에 연결하여 클러스터의 동작을 확장할 수 있다. 오퍼레이터는 사용자 정의 리소스의 컨트롤러 역할을 하는 쿠버네티스 API의 클라이언트이다. 오퍼레이터는 쿠버네티스 API를 사용하여 클러스터의 리소스와 상호 작용한다.

오퍼레이터는 쿠버네티스 API를 사용하여 사용자 리소스와 상호작용하고 테스트를 자동화할 수 있다. 여러 애플리케이션으로 구성된 백엔드 시스템을 자동화하려면 각 애플리케이션을 관리하고 모니터링하는 오퍼레이터를 개발해야 한다. 오퍼레이터를 사용하면 여러 애플리케이션의 상태를 모니터링하고 제어하며 필요한 경우 복구 작업을 수행할 수 있다. 또한 테스트 스크립트를 실행함으로써 테스트를 자동화할 수 있다.


참고

Comments