Home 도커로 nGrinder 설치하기
Post
Cancel

도커로 nGrinder 설치하기

nGrinder란?

네이버에서 진행한 오픈 소스 프로젝트로 서버의 부하 테스트를 위한 도구

"nGrinder_Architecture"

  • 스크립트를 통한 시나리오 기반 테스트
  • 부하 테스트 : 시스템의 응답 성능과 한계치를 파악하기 위한 테스트
    • 부하 테스트 도구 : nGrinder, k6, Apache JMeter, Gatling, Locust 등
  • 동시 접속자 수, 요청 간격, 최대 Throughput 등 부하를 조정
  • 부하 테스트 서버 스케일 아웃을 지원하는 등 충분한 부하 → agent를 이용하여 충분한 부하 줄 수 있다.
  • controller 와 agent로 이루어져 있음

controller

  • 웹 기반 gui 시스템
  • 에이전트(agent) 관리
  • 부하테스트 실시 및 모니터링
  • 부하 시나리오 작성 테스트 내역 저장하고 재사용

agent

  • 부하를 발생시키는 대상, 주체
  • controller의 지휘를 받음
  • controller 한 대당 agent 여러 대

도커로 설치

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
version: "3"
services:
  mysql:
    container_name: mysql
    image: mysql:latest
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
    volumes:
      - ./data:/var/lib/mysql
    command:
      - '--character-set-server=utf8mb4'
      - '--collation-server=utf8mb4_unicode_ci'
    ports:
      - "3307:3306"

  backend:
    container_name: backend
    image: ${SPRING_BOOT_IMAGE}
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: ${MYSQL_URL}
      SPRING_DATASOURCE_USERNAME: ${MYSQL_USER}
      SPRING_DATASOURCE_PASSWORD: ${MYSQL_PASSWORD}
      SPRING_JPA_HIBERNATE_DDL_AUTO: update
    depends_on:
      - mysql

  controller:
    container_name: nGrinder_controller
    image: ngrinder/controller
    ports:
      - "9000:80"
      - "16001:16001"
      - "12000-12009:12000-12009"
  agent:
    container_name: nGrinder_agent
    image: ngrinder/agent
    links:
      - controller

발생 오류

  • script 생성 후 validate 시 항상 실패

    "validate 실패"

  • 원인 : controller와 agent의 버전 문제, 도커로 사용한다면 3.5.6부터 latest까지는 피할 것

  • validate 시 백엔드 서버 연결 실패

    "백엔드 연결 실패"

  • 원인 : 127.0.0.1:8080으로 연결 시도, agent 컨테이너에서 backend 컨테이너로 접속하기 위해서는 도커 내부 IP로 접속해야함 → compose에서 네트워크 설정을 통해 backend의 IP 주소를 설정하고 그 IP로 요청

해결

  • 테스트 성공 확인

    validate 결과

    "validate 성공"

    performance test 결과

    "부하 테스트 성공"

script.groovy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import static net.grinder.script.Grinder.grinder
import static org.junit.Assert.*
import static org.hamcrest.Matchers.*
import net.grinder.script.GTest
import net.grinder.script.Grinder
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess
import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
// import static net.grinder.util.GrinderUtils.* // You can use this if you're using nGrinder after 3.2.3
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith

import org.ngrinder.http.HTTPRequest
import org.ngrinder.http.HTTPRequestControl
import org.ngrinder.http.HTTPResponse
import org.ngrinder.http.cookie.Cookie
import org.ngrinder.http.cookie.CookieManager

/**
* A simple example using the HTTP plugin that shows the retrieval of a single page via HTTP.
*
* This script is automatically generated by ngrinder.
*
* @author admin
*/
@RunWith(GrinderRunner)
class TestRunner {

	public static GTest test1
	public static HTTPRequest request
	public static Map<String, String> headers = [:]
	public static Map<String, Object> params = [:]
	public static List<Cookie> cookies = []

	@BeforeProcess
	public static void beforeProcess() {
		HTTPRequestControl.setConnectionTimeout(300000)
		test1 = new GTest(1, "GET /api/v1/books/{bookId}")
		request = new HTTPRequest()
		grinder.logger.info("before process.")
	}

	@BeforeThread
	public void beforeThread() {
		test1.record(this, "test1")
		grinder.statistics.delayReports = true
		grinder.logger.info("before thread.")
	}

	@Before
	public void before() {
		request.setHeaders(headers)
		CookieManager.addCookies(cookies)
		grinder.logger.info("before. init headers and cookies")
	}

	@Test
	public void test1() {
		HTTPResponse response = request.GET("http://172.16.1.5:8080/api/v1/books/1", params)

		if (response.statusCode == 301 || response.statusCode == 302) {
			grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", response.statusCode)
		} else {
			assertThat(response.statusCode, is(200))
		}
	}
}

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
version: "3"
services:
  mysql:
    container_name: mysql
    image: mysql:latest
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
    volumes:
      - ./data:/var/lib/mysql
    command:
      - '--character-set-server=utf8mb4'
      - '--collation-server=utf8mb4_unicode_ci'
    ports:
      - "3307:3306"
    networks: # 네트워크 설정
      - default_bridge

  backend:
    container_name: backend
    image: ${SPRING_BOOT_IMAGE}
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: ${MYSQL_URL}
      SPRING_DATASOURCE_USERNAME: ${MYSQL_USER}
      SPRING_DATASOURCE_PASSWORD: ${MYSQL_PASSWORD}
      SPRING_JPA_HIBERNATE_DDL_AUTO: update
    depends_on:
      - mysql
    networks: # 네트워크 설정
      default_bridge:
        ipv4_address: 172.16.1.5 # 사용할 백엔드 IP 주소 설정

  controller:
    container_name: nGrinder_controller
    image: ngrinder/controller:3.5.5 # 버전 설정
    ports:
      - "9000:80"
      - "16001:16001"
      - "12000-12009:12000-12009"
    networks: # 네트워크 설정
      - default_bridge
  agent:
    container_name: nGrinder_agent
    image: ngrinder/agent:3.5.5 # 버전 설정
    links:
      - controller
    networks: # 네트워크 설정
      - default_bridge


networks: # 도커 내부 네트워크 설정
  default_bridge:
    ipam:
      driver: default
      config:
        - subnet: 172.16.1.0/24

다음

  • 부하 테스트 전 알아야 할 것들에 대해 정리

참고

This post is licensed under CC BY 4.0 by the author.