Published on

AWS ECS Fargate에 nGrinder 구축하기

Authors
  • avatar
    Name
    윤종원
    Twitter

nGrinder?

nGrinder는 Naver에서 제공하는 성능 테스트 툴입니다. 직관적인 UI/UX로 많은 회사에서 사용하고 있는 성능 테스트 툴이지만 직접 구축해서 사용해야 합니다.

Architecture-29bb2

nGrinder는 웹 기반의 GUI를 제공해 성능 테스트를 시작하고, 결과를 확인할 수 있는 Controller와 성능 테스트를 진행할 때 Controller의 요청에 따라 실제 서버에 부하를 발생시키는 Agent로 구성되어있습 부하를 발생시키기 위해서 여러 개의 서버에 구축해야 합니다.

이 글에서는 다루지 않지만 성능 테스트의 대상이 되는 서버에 설치하는 Monitor도 있습니다. Monitor는 성능 테스트를 진행하는 동안 타겟 서버의 CPU, 메모리 등을 확인할 수 있게 해줍니다. 다만 Monitor를 설치하지 않아도 성능 테스트는 진행할 수 있으므로 이 글에서는 다루지 않습니다.

즉, nGrinder 시스템을 구축하기 위해서는 하나의 Controller와 여러 개의 Agent를 구축해야 합니다. 직접 서버에 war 파일을 다운받아서 구축할 수도 있는데 이 방법은 [공식 위키](https://github.com/naver/ngr에 직접 Controller와 Agent를 설치하면 간단한 성능 테스트 정도는 진행할 수 있습니다. 다만 아래와 같은 단점을 가질 수 있습니다.

  • 더 많은 부하를 만들어내기 위해서는 Agent의 수를 늘려야 합니다. 따라서 새로운 Agent가 필요할 때마다 매번 EC2에 Agent를 구축해야 합니다.
  • 성능 테스트는 365일 24시간 돌아가는 것이 아니기 때문에 항상 많은 Agent가 필요한 것은 아닙니다. 따라서 Agent는 성능 테스트가 필요할 때만 개수를 늘렸다가 성능 테스트가 끝나면 모두 종료하는 것이 비용적으로 좋습니다. 하지만 EC2에 직접 구축하면 이런 과정이 번거롭습니다.

결국 EC2에 직접 Agent를 구축하면 동적으로 Agent의 수를 조정하는 것이 불편합니다. 성능 테스트가 불편해지면 테스트를 덜 실행하게 되므로 편리하게 Agent를 동적으로 스케일링할 수 있게 구축하는 것이 중요합니다. AWS에서는 아래와 같은 방법들을 생각해볼 수 있습니다.

  • 오토 스케일링 그룹
  • AWS Beanstalk
  • AWS ECS

AWS Beanstalk의 경우 이동욱님의 블로그에 잘 정리되어 있습니다. 이 글에서는 AWS ECS Fargate에 nGrinder를 구축하는 방법을 알아보겠습니다.

ECS 클러스터 생성하기

2022년 1월 8일 기준으로 새로운 ECS 환경 콘솔의 모습으로 이후에 위 사진과 콘솔 UI가 달라질 수 있습니다.

클러스터는 ECS의 가장 기본적인 단위로 서비스태스크가 실행되는 곳이라고 생각하면 됩니다. 우리는 Controller 서비스Agent 서비스를 클러스터에 배포해서 nGrinder 환경을 구축한다고 생각하면 됩니다.

image.png

먼저 AWS ECS 서비스에 들어가서 클러스터 생성을 눌러줍니다.

image_3.png

클러스터 이름과 VPC는 상황에 맞게 설정해 줍니다. 이 글에서는 클러스터 이름으로 nGrinder을 사용하고 VPC의 경우 데모이므로 기본 VPC를 사용합니다.

image_2.png

인프라의 경우 이 글에서는 AWS Fargate를 사용하므로 EC2나 외부 인스턴스를 체크하지 않습니다. 생성 버튼을 눌러서 클러스터를 생성합니다.

image_4.png

조금 기다리면 클러스터가 생성됩니다. 이제 이 클러스터에 서비스를 배포하기 위해서 작업 정의를 생성해야 합니다.

Controller 구축

작업 정의 혹은 태스크 정의(Task Definition) 는 ECS의 최소 실행 단위인 태스크를 실행하기 위한 일종의 명세라고 생각하면 됩니다. 컨테이너에서 어떤 이미지를 실행할 것인지, CPU나 메모리는 얼마나 할당할 것인지, 어떤 포트를 할당할 것인지 등을 정의한다고 생각하면 됩니다.

태스크는 ECS의 최소 실행 단위로 하나 혹은 둘 이상의 컨테이너 묶음이라고 생각하면 됩니다. 정말 간단하게 생각하면 우리가 클러스터에 실행하려고 하는 각각의 서버를 의미한다고 생각해도 됩니다.

예를 들어 nGrinder Controller가 1개의 EC2 서버에 구축되어 있고 nGrinder Agent가 3개의 EC2 서버에 실행되고 있을 때 이를 ECS 클러스터로 옮기면 nGrinder Controller Task 1개, nGrinder Agent Task 3개가 생기게 됩니다.

따라서 Controller 태스크와 Agent 태스크를 실행하기 위해서 각각의 태스크 정의를 생성해야 합니다.

태스크 정의 생성

image_5.png
image_6.png

왼쪽 사이드 바에서 태스크 정의 메뉴를 누르고 새 태스크 정의 생성을 누릅니다.

image_7.png

태스크 정의 패밀리의 이름이나 컨테이너 이름은 원하는 이름을 적어주면 됩니다. 이 글에서는 클러스터 이름이 이미 ngrinder이므로 controller라는 이름을 사용합니다.

컨테이너 이미지 URI의 경우 ngrinder에서 공식적으로 제공하는 Controller 이미지인 ngrinder/controller를 사용합니다.

Controller의 경우 웹 페이지를 위한 80 포트, Agent가 접속하는 16001 포트, 성능 테스트를 진행할 때Controller와 Agent가 통신할 때 사용하는 12000~12000+ 포트를 사용합니다. 12000 번대 포트의 경우 동시에 진행하는 성능 테스트 수만큼 열어주면 됩니다.

환경 변수는 별도로 설정하지 않아도 됩니다.

image_8.png

이 글에서는 AWS Fargate를 사용하므로 AWS Fargate(서버리스) 를 선택합니다. 운영체제는 당연히 Linux/X86_64를 사용합니다.

태스크 크기의 경우 이 글에서는 2vCPU4 GB의 메모리를 사용하지만 이는 최적화된 값이 아닐 수 있습니다. 이 값은 언제든지 태스크 정의의 새로운 개정을 생성하면서 수정할 수 있으므로 성능 테스트를 하면서 적절한 값을 찾아서 설정하면 됩니다.

태스크 역할은 따로 부여하지 않으며 네트워크 모드는 AWS Fargate를 사용하므로 awsvpc를 사용하게 됩니다. 스토리지 또한 별도로 설정하지 않습니다.

image_9.png

모니터링 및 로깅의 경우 원하는 대로 설정하면 됩니다. 이 글에서는 Amazon CloudWatch를 통한 로그 수집만 사용합니다.

이렇게 모든 설정을 마친 뒤에 생성 버튼을 눌러주면 Controller에 대한 태스크 정의가 만들어집니다.

보안 그룹 생성

이 뒤에서 Controller를 외부에서 고정된 IP로 접속할 수 있게하기 위해서 로드 밸런서를 연결해야 합니다. 이 과정에서 보안 그룹을 설정해야 하는데 필요할 때 만드는 것보다 한번에 만들어놓고 연결하는 것이 편하니 먼저 보안 그룹을 생성하고 로드 밸런서를 생성하겠습니다.

image_16.png
image_17.png

EC2의 보안 그룹으로 이동해 보안 그룹 생성 버튼을 눌러줍니다.

image_18.png

먼저 Agent의 보안 그룹을 생성합니다. 이름이나 설명은 원하는 내용을 적으면 되며 이 글에서는 nGrinder-agent-sg를 사용합니다.

VPC의 경우 nGrinder 클러스터를 만들 때 사용했던 값을 사용합니다.

Agent의 경우 Controller나 Target에 연결할뿐 사용자 또는 다른 서버에서 Agent에 접속할 일이 없으므로 인바운드 규칙은 설정하지 않습니다. 아웃바운드 규칙의 경우 기본적으로 설정되어 있는 값을 사용합니다.

image_19.png

그 다음으로 Controller의 보안 그룹을 생성합니다. 여기서는 nGrinder-controller-sg라는 이름을 사용합니다. VPC 또한 nGrinder 클러스터의 VPC를 사용하면 됩니다.

인바운드 규칙의 경우 Controller 태스트 정의를 만들 때처럼 80, 12000-12000+, 16001 포트를 열어야 합니다. 이때 80 포트는 외부 사용자가 접속할 수 있도록 모든 IP에 대해서 열어주고 12000~12000+, `16001Grinder-agent-sg)에 대해서만 열어줍니다.

아웃바운드 규칙의 경우 기본적으로 설정되어 있는 값을 사용합니다.

image_20.png

그 다음으로 Controller에 연결할 로드 밸런서의 보안 그룹을 생성합니다. 여기서는 nGrinder-lb-sg라는 이름을 사용합니다. VPC 또한 nGrinder 클러스터의 VPC를 사용하면 됩니다.

인바운드 규칙의 경우 80 포트만 외부 사용자가 접속할 수 있도록 모든 IP에 대해서 열어줍니다.

아웃바운드 규칙의 경우 기본적으로 설정되어 있는 값을 사용합니다.

로드 밸런서 생성

Controller의 경우 성능 테스트를 위한 웹 GUI를 제공합니다. Controller의 IP는 매 배포때마다 달라지므로 이를 하나의 단일된 엔드포인트로 제공하기 위해서 로드 밸런서를 사용할 수 있습니다.

image_11.png
image_12.png

EC2 서비스 안에 있는 로드 밸런서로 이동해 로드 밸런서 생성 버튼을 눌러줍니다.

image_13.png

AWS는 3가지의 로드 밸런서를 제공합니다. 여기서는 Application Load Balancer를 사용합니다. Application Load Balancer 아래 있는 Create 버튼을 눌러줍니다.

image_14.png

이름은 원하는 이름을 설정하면 됩니다. 여기서는 nGrinder-lb라는 이름을 사용합니다.

이 로드 밸런서는 외부 사용자가 접속할 수 있어야 하므로 Internet-facing을 선택합니다. IP address type의 경우 IPv4를 사용합니다.

image_15.png

VPC와 서브넷의 경우 nGrinder 클러스터를 생성할 때 설정한 값을 사용하면 됩니다.

image_22.png

보안 그룹은 아까 생성한 로드 밸런서 보안 그룹(nGrinder-lb-sg)을 연결해 줍니다.

image_21.png

리스너의 경우 여기서 생성하는 리스너를 사용하지 않을 거지만 연결하지 않으면 로드 밸런서를 생성할 수 없으므로 우선 의미없는 리스너를 만들고 로드 밸런서를 생성한 뒤에 지워줄 겁니다.

리스너에는 타겟 그룹을 연결해야 하므로 Create target group 링크를 눌러 타겟 그룹을 생성합니다.

image_23.png

어차피 지울 타겟 그룹이므로 Target group name에 아무런 값을 채운 후 타겟 그룹을 생성합니다.

image_24.png

타겟 그룹에 포함될 인스턴스 또한 없으므로 Create target group 버튼을 눌러줍니다.

image_25.png

그리고 로드 밸런서에서 방금 만든 타겟 그룹을 연결합니다.

image_26.png

그리고 Create load balancer 버튼을 눌러 로드 밸런서를 생성합니다.

image_27.png

생성한 로드 밸런서의 리스너 메뉴로 들어가 방금 만든 리스너를 삭제합니다.

image_28.png

또한 타겟 그룹 메뉴에 들어가 만든 타겟 그룹을 선택하고 Actions 메뉴를 누른 뒤 Delete 버튼을 눌러 타겟 그룹을 삭제합니다.

서비스 생성

서비스태스크를 관리하기 위한 단위로 클러스터 내에 태스크가 지정된 수만큼 실행될 수 있도록 관리하는 책임을 가지고 있습니다. 이뿐만 아니라 실행중인 태스크들을 로드밸런서로 연걸하거나 서비스 디스커버리를 위해 AWS Cloud Map에 등록하는 등의 설정도 할 수 있습니다.

이 글에서는 Agent가 Controller의 IP를 찾기 위해서 서비스 검색 기능을 사용합니다. 다만 새로운 ECS 콘솔 환경에서 서비스를 생성할 때 이 메뉴가 사라져서 이전 콘솔 환경으로 전환해서 서비스를 생성합니다. 이 글을 작성하는 시점에는 이 메뉴가 없으나 이후에는 다시 생길 수도 있으니 상황에 맞게 진행하시면 될 것 같습니다.

이후에 Agent의 태스크 정의를 생성할 때 컨테이너가 실행될 때 설정하는 커맨드를 설정하는데 이 옵션 또한 새로운 콘솔 환경에서 사라져 이 뒤 모든 작업은 구형 콘솔에서 진행합니다.

image_10.png

왼쪽 사이드 바에서 새로운 ECS 환경 버튼을 클릭해 이전 콘솔 환경으로 전환합니다.

image_29.png

우리가 아까 생성했던 nGrinder 클러스터어 들어가서 서비스에 있는 생성 버튼을 눌러줍니다.

image_30.png

시작 유형으로 FARGATE를 선택하고 운영 체제 패밀리는 Linux를 사용합니다. 작업 정의의 경우 우리가 아까 생성한 controller를 선택하면 됩니다.

image_31.png

클러스터는 우리가 만든 nGrinder 클러스터를 선택하고 서비스 이름은 원하는 이름을 설정합니다. 여기서는 controller라는 이름을 사용합니다.

controller는 태스크를 1개만 실행할 것이므로 1로 설정하면 됩니다.

image_32.png

배포 유형의 경우 무중단 배포를 하기 위해서 블루/그린 배포를 선택해도 되지만 여기서는 롤링 업데이트를 사용합니다.

image_33.png

VPC와 서브넷은 Conroller를 배포할 VPC와 서브넷을 선택하면 됩니다. 보안 그룹은 아까 만든 Controller의 보안 그룹(nGrinder-controller-sg)을 선택합니다. 자동 할당 퍼블릭 IP는 ENABLED를 선택합니다.

image_34.png

로드 밸런서는 아까 만든 nGrinder-lb를 선택합니다.

image_35.png

컨테이너와 로드 밸런서를 연결하기 위해 컨트롤러의 80 포트를 선택한 뒤에 로드 밸런서에 추가 버튼을 누릅니다.

image_36.png

리스너 포트의 경우 새로 생성을 선택하고 포트는 80 포트를 사용하며 대상 그룹 이름은 적당한 이름을 사용하면 됩니다. 여기서는 nGrinder-controller-tg를 사용합니다.

image_37.png

Agent가 Controller를 새로 배포해도 자동으로 연결할 수 있도록 서비스 검색 통합 활성화 버튼을 눌러줍니다. 네임 스페이스의 경우 새로운 프라이빗 네임스페이스 생성을 선택하고 네임스페이스 이름은 적당한 값을 사용합니다. 여기서는 ngrinder라는 값을 사용합니다.

새로운 서비스 검색 서비스를 등록하는 것이므로 새로운 서비스 검색 서비스 생성을 선택하고 서비스 검색 이름에는 컨트롤러를 나타낼 수 있는 이름을 사용하면 됩니다. 여기서는 controller라는 값을 사용합니다.

DNS 레코드 유형의 경우 A 타입을 사용하고 TTL은 적당한 값을 사용하면 됩니다. 여기서는 60초를 사용합니다.

이렇게 서비스 검색을 설정하면 Controller를 새로 배포하더라도 Agent 설정 수정 없이 Agent가 새로운 Controller에 연결할 수 있습니다. 서비스 검색 통합 활성화를 사용하면 DNS를 통해 Controller의 IP를 얻을 수 있습니다. 이 DNS는 {서비스 검색 이름}.{네임스페이스 이름} 형태로 생성되는데 이 값을 Agent 태스크 정의를 만들 때 사용하므로 기억해둬야 합니다. 여기서는 controller.ngrinder가 됩니다.

image_38.png

오토 스케일링은 사용하지 않습니다. 이후에 서비스 생성 버튼을 누르면 Controller 서비스가 생성됩니다.

image_39.png

클러스터의 작업 목록에서 controller 작업이 실행되고 있는 것을 확인할 수 있습니다.

image_41.png

조금 기다리면 RUNNING 상태로 바뀌고 아까 만든 로드밸런서의 DNS로 nGrinder에 접속할 수 있습니다.

image_40.png

로드 밸런서가 nGrinder로 헬스 체크를 하는 과정에서 기본 URL /로 요청을 하면 302 응답을 줘서 헬스 체크에 실패하는 경우가 있습니다. 이런 경우 ECS는 태스크 실행에 실패한 것으로 보고 태스크 재시작을 반복하게 됩니다. 타겟 그룹 설정을 변경하면 됩니다.

image_42.png

아까 만든 타겟 그룹의 Health checks 설정에 가서 Edit 버튼을 누른 뒤

image_43.png

Success codes에 302 코드를 추가하면 됩니다.

Agent 구축

이제 Controller에 연결할 Agent를 구축하면 됩니다. Controller를 구축할 때처럼 먼저 태스크 정의를 만든 뒤 서비스를 생성하면 됩니다.

태스크 정의 생성

새로운 콘솔 환경에서 컨테이너 커맨드 설정이 사라져서 구 콘솔 환경에서 진행합니다.

image_44.png

작업 정의애서 새 작업 정의 생성 버튼을 누르면 태스크 정의 생성을 시작할 수 있습니다.

image_45.png

우리는 Fargate를 사용하므로 FARGATE를 선택하고 다음 단계로 넘어갑니다.

image_46.png

태스크 정의 이름은 적당한 이름을 설정하면 되며 이 글에서는 agent를 사용합니다.

태스크 역할은 없음을 선택하고 운영 체제 패밀리는 Linux를 선택합니다.

image_47.png

작업 실행 역할의 경우 Controller 태스크 정의를 생성할 때 자동으로 생성된 ecsTaskExecutionRole를 사용하면 됩니다. 만약 ecsTaskExecutionRole가 없다면 새 역할 생성을 선택합니다.

작업 메모리는 6GB, 작업 CPU는 2 vCPU를 사용합니다. 이 또한 최적의 값이 아닐 수 있으며 언제든지 수정할 수 있으므로 나중에 원한다면 수정하면 됩니다.

image_48.png

컨테이너 정의에서 Agent 이미지를 추가하기 위해 컨테이너 추가를 누릅니다.

image_49.png

컨테이너 이름은 적당한 이름을 설정하면 되며 이 글에서는 agent를 사용합니다. 이미지의 경우 ngrinder에서 제공하는 ngrinder/agent를 사용합니다.

Controller와 달리 Agent는 외부에서 Agent로 접속하지 않으므로 포트 매핑은 하지 않습니다.

image_50.png

아래 환경 메뉴에서 명령에 아까 Controller 서비스를 생성할 때 서비스 검색을 활성화하면서 생성한 DNS를 적어줘야 Agent가 Controller에 연결할 수 있습니다. 위에서 말했듯이 DNS는 {서비스 검그래서 **명령**에 DNS:포트번호를 적어주면 되는데 이 글에서는 controller.ngrinder:80`가 됩니다.

나머지 설정은 건드릴 부분이 없으므로 추가 버튼을 눌러 컨테이너를 추가해 줍니다. 그리고 생성 버튼을 눌러 Agent의 태스크 정의를 생성을 완료합니다.

서비스 생성

image_51.png

다시 nGrinder 클러스터로 이동해 서비스 메뉴에 있는 생성 버튼을 눌러 서비스 생성을 시작합니다.

image_52.png

시작 유형으로 FARGATE를 선택하고 작업 정의에서 방금 만든 agent를 선택합니다.

image_53.png

클러스터는 nGrinder 클러스터를 사용하고 서비스 이름은 적절한 이름을 사용하면 됩니다. 이 글에서는 agent를 사용합니다.

Agent는 Controller와 달리 여러 개의 태스크가 뜰 수 있으므로 작업 개수에 2를 설정합니다. 더 많은 Agent를 사용하고 싶다면 원하는 Agent 개수를 적어주면 됩니다.

image_54.png

Agent는 외부와 연결되지 않으므로 롤링 업데이트를 사용합니다.

image_55.png

VPC와 서브넷은 Conroller를 배포할 VPC와 서브넷을 선택하면 됩니다. 보안 그룹은 아까 만든 Controller의 보안 그룹(nGrinder-agent-sg)을 선택합니다. 자동 할당 퍼블릭 IP는 ENABLED를 선택합니다.

image_56.png

Agent는 외부와 연결되지 않으므로 로드 밸런서와 연결하지 않습니다.

image_57.png

Agent도 서비스 검색 통합 활성화를 활성화합니다. 네임스페이스는 Controller 서비스를 생성할 때 생성한 ngrinder 네임스페이스를 사용합니다. 서비스 검색 이름의 경우 적절한 이름을 설정하면 되는데 이. 여기서는 60초를 사용합니다.

결국 이 설정에 따르면 Agent는 agent.ngrinder라는 DNS로 접근할 수 있습니다만 이를 사용하지는 않습니다. 서비스 검색은 Agent가 Controller에 연결하기 위해서만 사용합니다.

image_58.png

원한다면 오토 스케일링을 활성화해도 되지만 이 글에서는 사용하지 않습니다.

이후 서비스 생성 버튼을 눌러 Agent 서비스를 생성합니다.

image_59.png

2개의 Agent 태스크가 실행되는 모습을 확인할 수 있습니다. 이후 마지막 상태가 RUNNING으로 바뀌면 nGrinder 웹 페이지에 접속해 Agent가 연결되었는지 확인하면 됩니다.

확인

image_60.png

nGrinder 웹 페이지에 접속하면 에이전트 관리에서 연결된 Agent를 확인할 수 있습니다.

image_61.png

정상적으로 Controller에 Agent가 연결된 것을 확인할 수 있습니다.

Agent 스케일링

만약 Agent 서버의 개수를 조정하고 싶다면 클러스터의 서비스 설정에서 조정할 수 있습니다.

image_62.png

nGrinder 클러스터에서 agent 서비스를 선택하고 업데이트 버튼을 눌러줍니다. 참고로 현재 실행중인 작업의 개수는 2인 것을 확인할 수 있습니다.

image_63.png
image_64.png

원하는 Agent 수만큼 작업 개수를 설정하고 Skip to review 버튼을 누르고 서비스 업데이트 버튼 을 눌러줍니다.

image_65.png

조금 기다리면 10개라는 작업 개수를 맞추기 위해서 8개의 새로운 Agent가 실행되는 것을 확인할 수 있습니다.

image_66.png

nGrinder 에이전트 관리에서도 수분 내로 10개의 Agent가 연결되는 것을 확인할 수 있습니다.

정리

AWS ECS에 nGrinder를 구축하는 방법이 정리된 글이 없기에 글을 한번 작성해봤습니다. 개인적으로는 오토 스케일링 그룹이나 AWS Beanstalk보다 훨씬 편하게 구축하고 스케일링할 수 있는 방법이라고 생각합니다.

만약 AWS ECS Fargate에 대해 익숙하지 않다면 이 글을 참고하면 좋을 것 같습니다. 혹시나 글에 잘못된 내용이 있다면 댓글로 남겨주세요!

로드 밸런서에 여러 개의 Controller 포트를 매핑하는 방법을 찾지 못해 AWS Cloud Map을 사용했는데 혹시 다른 방법이 있으면 댓글로 알려주시면 감사하겠습니다.