
안녕하세요, 자바파커입니다.
"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 외에 다른 도구 경험이 있다면 댓글로 공유해주세요!