본문 바로가기

웹서비스 개발

JMeter + Docker로 성능 테스트하기 — 설치 없이 바로 실행하는 부하 테스트 가이드

안녕하세요, 자바파커입니다.

"API 배포 전에 성능 테스트 좀 돌려봐야 하는데, JMeter 설치부터 귀찮습니다."

솔직히 저도 그랬습니다. JMeter는 강력한 도구지만, Java 설치 → JMeter 다운로드 → 환경변수 설정 → 플러그인 설치... 시작하기까지가 꽤 번거롭습니다. 팀원마다 환경이 달라서 "제 PC에서는 되는데요?"라는 말도 자주 나오고요.

결론부터 말씀드리면 — Docker 하나면 이 문제가 해결됩니다. docker run 한 줄이면 JMeter가 바로 실행되고, Docker Compose로 분산 테스트까지 가능합니다. 오늘은 Docker 기반 JMeter 성능 테스트를 처음부터 끝까지 정리해보겠습니다.


왜 JMeter + Docker인가?

먼저 왜 Docker로 JMeter를 실행해야 하는지 정리하겠습니다.

기존 방식 Docker 방식
Java + JMeter 직접 설치 docker run 한 줄로 실행
팀원마다 버전·환경 다름 동일한 이미지로 환경 통일
분산 테스트 구성 복잡 Docker Compose로 간단 스케일링
CI/CD 연동 시 설치 스크립트 필요 이미지 pull만 하면 끝
테스트 후 정리 필요 컨테이너 종료 시 자동 정리

핵심은 재현 가능한 환경입니다. 누가, 어디서, 언제 실행해도 동일한 조건에서 테스트할 수 있습니다.


1단계: Docker로 JMeter 바로 실행하기

Docker 이미지 선택

2026년 현재 주요 JMeter Docker 이미지를 비교하면:

이미지 JMeter 버전 특징
justb4/jmeter 5.5 가장 인기 있지만 2022년 이후 업데이트 안 됨
qainsights/jmeter 5.6.3 최신 버전, multi-arch, 비root
커스텀 빌드 원하는 버전 플러그인 포함 가능

추천: qainsights/jmeter:5.6.3 또는 직접 Dockerfile 작성

가장 간단한 실행

# 테스트 계획 실행 + HTML 리포트 생성
docker run --rm \
  -v $(pwd)/tests:/jmeter/tests \
  -v $(pwd)/results:/jmeter/results \
  qainsights/jmeter:5.6.3 \
  -n -t /jmeter/tests/test-plan.jmx \
  -l /jmeter/results/results.jtl \
  -e -o /jmeter/results/html-report

각 옵션의 의미:

옵션 설명
--rm 테스트 끝나면 컨테이너 자동 삭제
-v 호스트의 테스트 파일과 결과 디렉토리 마운트
-n Non-GUI 모드 (Docker에서는 필수)
-t 테스트 계획 파일 (.jmx)
-l 결과 로그 파일 (.jtl)
-e -o HTML 리포트 자동 생성

주의: JMeter GUI는 Docker에서 사용하지 않습니다. GUI는 로컬에서 테스트 계획(.jmx)을 만들 때만 사용하고, 실행은 항상 Non-GUI 모드(-n)로 합니다.

폴더 구조

my-project/
├── tests/
│   ├── test-plan.jmx          # JMeter 테스트 계획
│   ├── test-data.csv          # 테스트 데이터 (선택)
│   └── user.properties        # 추가 설정 (선택)
├── results/                   # 테스트 결과 (자동 생성)
│   ├── results.jtl
│   └── html-report/
│       └── index.html         # 브라우저로 열어서 확인
└── docker-compose.yml

2단계: 테스트 계획 (.jmx) 작성하기

JMeter GUI에서 만드는 게 가장 편하지만, 구조를 이해하면 수정이 쉬워집니다. REST API 테스트 기본 구조를 정리하겠습니다.

핵심 컴포넌트

Test Plan (테스트 계획)
├── Thread Group (사용자 시뮬레이션)
│   ├── HTTP Request Defaults (공통 설정)
│   ├── HTTP Header Manager (헤더)
│   ├── HTTP Request — GET /api/users
│   │   ├── Response Assertion (응답 검증)
│   │   └── JSON Extractor (값 추출)
│   ├── HTTP Request — POST /api/users
│   └── Summary Report (결과 요약)

Thread Group 설정 — 부하 패턴 결정

Thread Group은 몇 명의 가상 사용자가, 얼마 동안, 어떤 패턴으로 요청을 보낼지 결정합니다.

설정 의미 예시
Number of Threads 동시 사용자 수 50
Ramp-Up Period 모든 사용자가 시작되기까지 걸리는 시간 10초
Duration 테스트 총 시간 60초

팁: 변수화하면 Docker에서 유연하게 사용할 수 있습니다.

<!-- jmx 파일 내부 -->
<intProp name="ThreadGroup.num_threads">${__P(threads,10)}</intProp>
<stringProp name="ThreadGroup.duration">${__P(duration,60)}</stringProp>

이렇게 하면 Docker 실행 시 값을 주입할 수 있습니다:

docker run --rm ... qainsights/jmeter:5.6.3 \
  -n -t /jmeter/tests/test-plan.jmx \
  -Jthreads=100 \
  -Jduration=300

-Jthreads=100.jmx 내부의 ${__P(threads,10)}을 100으로 오버라이드합니다. 기본값은 10이므로, 값을 안 넘기면 10명의 가상 사용자로 실행됩니다.


3단계: 커스텀 Docker 이미지 만들기

프로젝트에서 반복적으로 사용한다면, 플러그인과 설정을 포함한 커스텀 이미지를 만드는 게 편합니다.

FROM eclipse-temurin:17-jre-alpine

ARG JMETER_VERSION=5.6.3
ENV JMETER_HOME=/opt/apache-jmeter-${JMETER_VERSION}
ENV PATH=${JMETER_HOME}/bin:${PATH}
ENV HEAP="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m"

# JMeter 설치
RUN apk add --no-cache curl unzip bash \
    && curl -L https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-${JMETER_VERSION}.tgz \
       | tar xzf - -C /opt \
    && rm -rf ${JMETER_HOME}/docs ${JMETER_HOME}/printable_docs

# 플러그인 매니저 설치
RUN curl -L -o ${JMETER_HOME}/lib/ext/jmeter-plugins-manager.jar \
    https://jmeter-plugins.org/get/ \
    && curl -L -o ${JMETER_HOME}/lib/cmdrunner-2.3.jar \
    https://repo1.maven.org/maven2/kg/apc/cmdrunner/2.3/cmdrunner-2.3.jar \
    && java -cp ${JMETER_HOME}/lib/ext/jmeter-plugins-manager.jar \
       org.jmeterplugins.repository.PluginManagerCMDInstaller

# 자주 쓰는 플러그인 설치
RUN ${JMETER_HOME}/bin/PluginsManagerCMD.sh install \
    jpgc-casutg,jpgc-tst,jpgc-graphs-basic,jpgc-json,jpgc-perfmon

WORKDIR /jmeter
ENTRYPOINT ["jmeter"]
# 빌드
docker build -t my-jmeter:5.6.3 .

# 실행
docker run --rm -v $(pwd)/tests:/jmeter/tests -v $(pwd)/results:/jmeter/results \
  my-jmeter:5.6.3 -n -t /jmeter/tests/test-plan.jmx \
  -l /jmeter/results/results.jtl -e -o /jmeter/results/html-report

포함한 플러그인 설명

플러그인 용도
jpgc-casutg 유연한 부하 패턴 (Stepping, Ultimate Thread Group)
jpgc-tst 초당 요청수(TPS) 정밀 제어
jpgc-graphs-basic 응답 시간, TPS 그래프
jpgc-json JSON 응답 추출·검증
jpgc-perfmon 서버 CPU/메모리/디스크 모니터링

4단계: Docker Compose로 분산 테스트

한 대의 컨테이너로는 충분한 부하를 만들기 어려울 수 있습니다. Docker Compose로 마스터 1대 + 슬레이브 N대 구조를 쉽게 만들 수 있습니다.

# docker-compose.yml
services:
  jmeter-slave-1:
    image: qainsights/jmeter:5.6.3
    container_name: jmeter-slave-1
    entrypoint: jmeter-server
    command: -Jserver.rmi.ssl.disable=true
    expose:
      - "1099"
      - "50000"
    networks:
      - jmeter-net

  jmeter-slave-2:
    image: qainsights/jmeter:5.6.3
    container_name: jmeter-slave-2
    entrypoint: jmeter-server
    command: -Jserver.rmi.ssl.disable=true
    expose:
      - "1099"
      - "50000"
    networks:
      - jmeter-net

  jmeter-master:
    image: qainsights/jmeter:5.6.3
    container_name: jmeter-master
    volumes:
      - ./tests:/jmeter/tests
      - ./results:/jmeter/results
    environment:
      - HEAP=-Xms1g -Xmx2g
    command: >
      -n -t /jmeter/tests/test-plan.jmx
      -l /jmeter/results/results.jtl
      -e -o /jmeter/results/html-report
      -R jmeter-slave-1,jmeter-slave-2
      -Jserver.rmi.ssl.disable=true
    depends_on:
      - jmeter-slave-1
      - jmeter-slave-2
    networks:
      - jmeter-net

networks:
  jmeter-net:
    driver: bridge
# 실행
docker compose up

# 슬레이브 5대로 스케일링
docker compose up --scale jmeter-slave-1=5 -d

분산 테스트 핵심 포인트

  • -R 옵션: 슬레이브 호스트명을 쉼표로 구분하여 지정
  • -Jserver.rmi.ssl.disable=true: Docker 내부 네트워크에서는 SSL 불필요
  • 포트 1099, 50000: RMI 통신에 필요한 포트
  • 네트워크: Docker 네트워크 안에서 서비스명으로 통신 (DNS 자동 해석)
  • 슬레이브에서 Thread 50개 설정 + 슬레이브 4대 = 총 200명의 가상 사용자

5단계: HTML 리포트 확인하기

테스트가 끝나면 results/html-report/index.html을 브라우저로 열면 됩니다.

# 테스트 실행 후 결과 확인
open results/html-report/index.html    # macOS
start results/html-report/index.html   # Windows

HTML 리포트에 포함되는 주요 지표:

지표 설명 기준 예시
Average Response Time 평균 응답 시간 < 200ms
90th Percentile 90%의 요청이 이 시간 이내 < 500ms
Error Rate 실패한 요청 비율 < 1%
Throughput 초당 처리 요청 수 (TPS) 목표에 따라 다름

기존 .jtl 파일에서 리포트 재생성

docker run --rm -v $(pwd):/jmeter qainsights/jmeter:5.6.3 \
  -g /jmeter/results/results.jtl \
  -o /jmeter/results/html-report-v2

-g 옵션으로 이미 생성된 .jtl 파일에서 리포트만 다시 만들 수 있습니다.


6단계: CI/CD 파이프라인에 연동하기

Docker 기반이라 CI/CD 연동이 매우 간단합니다.

GitHub Actions 예시

name: Performance Test

on:
  workflow_dispatch:
    inputs:
      threads:
        description: '동시 사용자 수'
        default: '10'
      duration:
        description: '테스트 시간 (초)'
        default: '60'

jobs:
  load-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run JMeter
        run: |
          docker run --rm \
            -v ${{ github.workspace }}/tests:/jmeter/tests \
            -v ${{ github.workspace }}/results:/jmeter/results \
            qainsights/jmeter:5.6.3 \
            -n -t /jmeter/tests/api-test.jmx \
            -l /jmeter/results/results.jtl \
            -e -o /jmeter/results/html-report \
            -Jthreads=${{ github.event.inputs.threads }} \
            -Jduration=${{ github.event.inputs.duration }}

      - name: Upload Report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: jmeter-report
          path: results/html-report/

      - name: Check Error Rate
        run: |
          ERROR_RATE=$(tail -n +2 results/results.jtl | \
            awk -F',' '{total++; if($8=="false") errors++} END {printf "%.2f", (errors/total)*100}')
          echo "Error rate: ${ERROR_RATE}%"
          if (( $(echo "$ERROR_RATE > 5.0" | bc -l) )); then
            echo "::error::Error rate ${ERROR_RATE}% exceeds 5% threshold"
            exit 1
          fi

포인트: workflow_dispatch로 수동 트리거하면서 사용자 수와 시간을 파라미터로 넘길 수 있습니다. 에러율이 5%를 넘으면 파이프라인이 실패합니다.


실전 팁 — 자주 하는 실수와 해결법

1. "리포트 디렉토리가 이미 있습니다" 오류

ERROR: org.apache.jmeter.JMeter: An error occurred: 
Cannot write to '/jmeter/results/html-report' as folder is not empty

해결: -o 경로는 비어있거나 존재하지 않아야 합니다. 매번 삭제하거나 타임스탬프를 붙이세요.

# 실행 전 삭제
rm -rf results/html-report

# 또는 타임스탬프 사용
-o /jmeter/results/report-$(date +%Y%m%d-%H%M%S)

2. 메모리 부족 (OutOfMemoryError)

# JVM 힙 사이즈 설정
docker run --rm \
  -e HEAP="-Xms2g -Xmx4g" \
  --memory=6g --cpus=2 \
  ...

경험칙: 컨테이너당 가상 사용자 250~500명 정도가 적당합니다. 그 이상은 슬레이브를 늘리세요.

3. Docker 네트워크에서 대상 서비스 접근

테스트 대상이 같은 Docker 네트워크에 있다면 서비스명으로 접근 가능합니다:

services:
  my-api:
    image: my-api:latest
    networks:
      - jmeter-net

  jmeter-master:
    # ...
    command: >
      -n -t /jmeter/tests/test.jmx
      -Jhost=my-api -Jport=8080
    networks:
      - jmeter-net

4. Windows 환경에서 볼륨 마운트

Windows에서는 $(pwd) 대신 절대 경로를 사용하세요:

# PowerShell
docker run --rm `
  -v ${PWD}/tests:/jmeter/tests `
  -v ${PWD}/results:/jmeter/results `
  qainsights/jmeter:5.6.3 ...

# CMD
docker run --rm ^
  -v %cd%/tests:/jmeter/tests ^
  -v %cd%/results:/jmeter/results ^
  qainsights/jmeter:5.6.3 ...

정리 — 전체 워크플로우

1. 테스트 계획 작성    →  JMeter GUI (로컬)에서 .jmx 파일 생성
2. Docker로 실행      →  docker run / docker compose up
3. 리포트 확인        →  results/html-report/index.html
4. CI/CD 연동        →  GitHub Actions / Jenkins에서 자동 실행
5. 분산 테스트        →  Docker Compose로 슬레이브 스케일링

Docker 기반 JMeter의 가장 큰 장점은 "환경 문제 없이 누구나 동일한 테스트를 실행할 수 있다"는 것입니다. 팀 전체가 같은 이미지를 쓰면 "제 PC에서는 되는데요?" 문제가 사라집니다.


FAQ — 자주 묻는 질문

Q. JMeter GUI를 Docker에서 쓸 수 있나요?

기술적으로는 X11 포워딩으로 가능하지만, 권장하지 않습니다. GUI는 로컬에 설치해서 테스트 계획(.jmx)만 만들고, 실행은 Docker에서 Non-GUI 모드로 하는 게 표준적인 방식입니다.

Q. Gatling이나 k6 대신 JMeter를 써야 하는 이유가 있나요?

JMeter는 GUI로 테스트를 만들 수 있어서 코딩 없이 시작할 수 있다는 게 가장 큰 장점입니다. Gatling(Scala)이나 k6(JavaScript)는 코드로 시나리오를 작성해야 합니다. 반면 대규모 테스트에서는 k6이 메모리 효율이 더 좋습니다. 팀의 기술 스택과 요구사항에 맞게 선택하면 됩니다.

Q. 분산 테스트에서 슬레이브를 몇 대까지 늘릴 수 있나요?

Docker Compose 기준으로 한 호스트에서 5~10대 정도가 현실적입니다. 그 이상은 호스트 자체의 CPU/메모리가 병목이 됩니다. 더 큰 규모가 필요하면 Kubernetes나 AWS ECS에서 슬레이브를 분산 배포하는 것을 고려하세요.


마무리

성능 테스트는 "나중에 해야지" 하다가 결국 배포 직전에 급하게 하는 경우가 많습니다. Docker로 JMeter 환경을 한 번 세팅해두면, 언제든 docker compose up 한 줄로 테스트를 실행할 수 있습니다.

여러분은 성능 테스트를 어떤 도구로 하고 계신가요? JMeter 외에 다른 도구 경험이 있다면 댓글로 공유해주세요!

SMALL