본문 바로가기
DevOps

스케일링 가능한 Ngrinder 환경 구축하기 (feat. AWS Beanstalk)

by 향로 (기억보단 기록을) 2021. 6. 18.
반응형

네이버의 Ngrinder는 대표적인 성능 부하 테스트 도구입니다.
개인적으로는 다른 테스트 도구들에 비해서 설치 과정이 조금 번거롭다는 단점에 비해 사용성과 UI/UX가 너무 직관적이라는 장점으로 인해서 오랫동안 애정하고 있는 제품인데요.

설치형을 지원하다보니 동적으로 Agent 수를 늘리고싶을때마다 설치된 이미지로 서버를 재생성하는 방식으로 늘리는게 참 불편했습니다.
이럴 경우 AWS를 통해서는 보통 2가지 방법으로 해결할 수 있는데,

  • 오토스케일링 그룹
  • Beanstalk

등 동적으로 동일한 서버 환경을 편하게 증설할 수 있습니다.

이번 시간에는 AWS Beanstalk을 이용하여 스케일링 가능한 Ngrinder 환경 구축하기를 진행해보겠습니다.

1. EC2에 Controller 설치하기

가장 먼저 Ngrinder의 Agent를 관리하고, 성능 테스트 전체를 관리하는 Controller를 EC2에 설치해보겠습니다.

architecture

Ngrinder의 release 페이지를 가보시면 현재 사용 가능한 버전들을 볼 수 있는데요.

현재 3.5.5가 최신이니, 3.5.5 버전을 사용하겠습니다.

당연한 얘기지만, AWS EC2에서 진행됩니다.
AWS EC2환경을 먼저 구축하고 해당 서버에서 SSH 접속후 진행해주세요.

아래처럼 war 파일을 우클릭하여 링크주소를 복사합니다.

controller1

복사한 링크 주소를 wget으로 다운 받습니다.

wget https://github.com/naver/ngrinder/releases/download/ngrinder-3.5.5-20210430/ngrinder-controller-3.5.5.war

다운받은 war를 실행하기 편하도록 버전명을 제거한 이름으로 변경하겠습니다.

link를 하셔도 무방합니다.

mv ngrinder-controller-3.5.5.war ngrinder-controller.war

해당 war를 세션 종료 방지 & 백그라운드 실행을 위해 nohup & 으로 실행하겠습니다.

nohup java -jar ngrinder-controller.war >/dev/null 2>&1 &

(만약 잘 실행이 안된다면 java -jar ngrinder-controller.war 만 수행해서 console로 로그를 확인해서 수정후 다시 nohup &으로 실행하시면 됩니다.)

명령어 실행 후, Java 프로세스를 확인해봅니다.

ps -ef | grep java

아래와 같이 실행한 war 프로세스가 잘 보인다면 성공입니다.

ec2-user  2601  2528 21 15:06 pts/0    00:00:00 java -jar ngrinder-controller.war
ec2-user  2614  2528  0 15:06 pts/0    00:00:00 grep --color=auto java

실행이되면 8080 포트로 해당 웹 사이트를 접근할 수 있습니다.

controller2

초기 ID/PW는 admin/admin 입니다.

로그인까지 확인되시면 바로 Controller쪽 설정은 끝났습니다.

2. Security Group 생성

Ngrinder의 정상적인 연동을 위해선 Agent가 Controller에 접근이 가능해야만 하는데요.
그래서 둘 간의 통신을 위한 보안그룹을 별도로 생성합니다.

서로 다른 EC2간의 통신에 대한 내용은 기존 포스팅을 참고하시면 좋습니다.

NGRINDER_AGENT

sg1
  • agent 전용 보안그룹에는 별도의 인바운드가 없어도 됩니다.
  • agent의 ssh 접근을 위한 보안그룹인 NGRINDER_AGENT 외에 별도로 관리하시길 추천드립니다.
    • ex) EC2_SSH 등의 보안그룹을 별도로 만들어서 agent EC2에 2개의 보안그룹을 둘다 추가하셔도 좋습니다.

이렇게 만들어진 agent 보안그룹을 controller 보안그룹의 인바운드로 추가하면 됩니다.

NGRINDER_CONTROLLER

sg2sg3
  • 80 포트는 wget을 통해 agent가 controller의 agent 설치 파일을 다운 받기 위해 추가합니다.

그리고 이렇게 만들어진 보안 그룹은 각 서버에 추가하겠습니다.

  • Controller는 1에서 구축되었으니, 바로 추가하시면 됩니다.
  • Agent는 아래에서 Beanstalk 환경 진행시 같이 추가합니다.

3. Beanstalk에 Agent 설치하기

자 이제 동적으로 서버를 스케일링 할 수 있는 Beanstalk에 Agent를 설치해볼텐데요.

3-1. Agent 설치 링크 가져오기

먼저 Agent 설치 파일 다운로드 링크를 받아와야 합니다.
Agent는 Controller 페이지에서 직접 제공합니다.

Controller에서 우측 상단 프로필을 클릭후 Agent Management를 선택합니다.

controller3

그럼 아래와 같이 Download 링크가 나오는데 이를 우클릭하여 링크주소복사를 합니다.

controller4

이렇게 가져온 링크는 아래 Beanstalk config 파일에서 사용할 예정이니, 별도 텍스트 파일에 복사해놓으시면 됩니다.

3-2. Beanstalk 설정하기

AWS Beanstalk에 대해서 어느정도 사용해본적이 있다고 가정하고 진행합니다.

본인의 환경에 맞게 Beanstalk을 생성하시면 되는데, 하나만 기존과 다르게 진행해주시면 되는데요.

eb1

Agent의 보안그룹으로 2. Security Group 생성에서 생성했던 NGRINDER_AGENT 보안그룹만 하나더 추가해주시면 됩니다.

eb-sg

(다른 보안그룹 없이 이것만 하라는 의미가 아니라, 이것도 함께 추가입니다.)

  • 이 보안그룹이 추가되어야만 Controller가 Agent를 인식할 수 있습니다.

기본적인 Beanstalk 환경이 구성되었다면, 이제 Config 파일을 만들어보겠습니다.

3-3. Beanstalk config

모든 코드는 Github 에 있습니다.

Agent에 사용될 프로젝트는 다음과 같은 구조를 가집니다.

📦 ngrinder-in-action
├─ .ebextensions
│  ├─ 01-appstart.config
│  ├─ 02-system-tuning.config
│  └─ 03-timezone.config
├─ .gitignore
├─ .platform
│  └─ nginx
│     └─ nginx.conf
├─ Procfile
├─ deploy.sh
├─ README.md

각각의 파일은 다음과 같습니다.

.ebextensions/01-appstart.config

files:
    "/sbin/appstart" :
        mode: "000755"
        owner: webapp
        group: webapp
        content: |
            #!/usr/bin/env bash
            COLLECTOR="collector ip" 
            AGENT_FILE_HOST="agent download link"
            wget ${AGENT_FILE_HOST} -P /var/app/current
            tar -xvf /var/app/current/ngrinder-agent-*.tar

            killall java
            /var/app/current/ngrinder-agent/run_agent.sh -ch ${COLLECTOR}
  • agent 파일을 실행할 appstart 스크립트를 생성합니다.
  • collector ip는 private ip를 등록합니다.
  • AGENT_FILE_HOST 에는 3-1 에서 가져온 Agent 링크를 넣습니다.
  • Agent의 실행 자체는 크게 어렵지 않습니다.
    • 다운 받은 agnet.tar 파일의 압축을 풀고 (tar -xvf) 이를 run_agent.sh 로 실행만 하면 됩니다.
    • -ch ${COLLECTOR} 는 Agent가 데이터를 보낼 Controller의 위치를 지정하는 옵션입니다.
    • 기본값은 localhost라서 외부에 연결할 경우 이번처럼 ch 옵션을 사용하면 됩니다.

.ebextensions/02-system-tuning.config

files:
  "/etc/security/limits.conf":
    content: |
      *           soft    nofile          65535
      *           hard    nofile          65535

commands:
  01:
    command: "echo \"10240 65535\" > /proc/sys/net/ipv4/ip_local_port_range"
  02:
    command: "sysctl -w \"net.ipv4.tcp_timestamps=1\""
  03:
    command: "sysctl -w \"net.ipv4.tcp_tw_reuse=1\""
  04:
    command: "echo \"net.ipv4.tcp_max_tw_buckets=2000000\" >> /etc/sysctl.conf"
  10:
    command: "sysctl -p"

.ebextensions/03-timezone.config

commands:
  01remove_local:
    command: "rm -rf /etc/localtime"
  02link_seoul_zone:
    command: "ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime"
  • 성능 테스트시 시간 오차를 방지하기 위해 타임존을 KST로 변환합니다.

.platform/nginx/nginx.conf

user                    nginx;
error_log               /var/log/nginx/error.log warn;
pid                     /var/run/nginx.pid;
worker_processes        auto;
worker_rlimit_nofile    65535;

events {
    use epoll;
    worker_connections  1024;
}

http {
  include       /etc/nginx/mime.types;
  default_type  application/octet-stream;

  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

  include       conf.d/*.conf;

  map $http_upgrade $connection_upgrade {
      default     "upgrade";
  }

  server {
        listen        80 default_server;

        # (1) health check
        location / {
            return 200 'ok';
        }

        access_log    /var/log/nginx/access.log main;

        client_header_timeout 60;
        client_body_timeout   60;
        keepalive_timeout     60;
        gzip                  off;
        gzip_comp_level       4;

        # Include the Elastic Beanstalk generated locations
        include conf.d/elasticbeanstalk/healthd.conf;
  }
}

(1) location /

  • Beanstalk의 Load Balancer Health Check 기본 주소가 / 입니다.
  • Ngrinder의 Agent가 Health Check 대상이 되기 보다는 Nginx에서 바로 /로 200 응답을 주게 하여 Health Check를 통과하도록 구성합니다.
  • Agent는 별도로 API 응답을 할 용도가 아니기 때문에 이런 기본적인 헬스체크에 대해서는 Nginx에서 처리합니다.

이렇게 구성이 다되셨으면 실제로 배포를 진행해보겠습니다.

4. 배포하기

3-3. Beanstalk config 에서 설정한 내용 그대로 배포용 zip 파일을 만들면 되는데요.
매번 수동으로 쉘 명령어를 치기보다는 빠르게 스크립트를 만들어서 진행합니다.

deploy.sh

#!/usr/bin/env bash

DIR=deploy

if [ -d "$DIR" ]; then rm -Rf $DIR; fi

mkdir $DIR
cp -r .ebextensions ./deploy/
cp -r .platform ./deploy/
cp -r Procfile ./deploy/
cd deploy
zip -r agent.zip .
mv agent.zip ../

작성이 다 되시면 chmod +x ./deploy.sh실행권한을 줍니다.
그리고 스크립트를 실행해보시면 아래와 같이 차례로 명령어가 수행되어 agent.zip 파일이 생성됩니다.

$ ./deploy.sh
adding: .ebextensions/ (stored 0%)
adding: .ebextensions/03-timezone.config (deflated 31%)
adding: .ebextensions/02-system-tuning.config (deflated 52%)
adding: .ebextensions/01-appstart.config (deflated 47%)
adding: Procfile (stored 0%)
adding: .platform/ (stored 0%)
adding: .platform/nginx/ (stored 0%)
adding: .platform/nginx/nginx.conf (deflated 54%)

이렇게 생성된 zip 파일을 수동으로 Beanstalk에 배포해봅니다.

upload1

여기서 파일 선택으로 해당 agent.zip 파일을 선택해서 배포를 합니다.

upload2

정상적으로 배포가 되시면 다음과 같이 Success 상태를 확인할 수 있습니다.

upload3

최종적으로 Controller의 Agent Management에서도 Agent가 표기 되면 성공입니다!

upload4

Github Action으로 설정이 변경될때마다 배포하는 방법도 추후 포스팅하겠습니다.

반응형