본문 바로가기
won2dev-log
HomeArchiveTagsCategoriesAboutProjects
HomeArchiveTagsCategoriesAboutProjects
won2dev-logwon2dev-logwon2dev-log

비전공 개발자의 로그 | won2dev-log

Navigation
  • Home
  • Archive
  • About
  • Projects
Categories
  • Docs
  • TIL
  • Project
  • Automation
  • Git · GitHub
더보기
Tags
  • TIL
  • Java
  • Spring
  • Backend
  • n8n
더보기
About

기록을 거름 삼아 공유는 성장을 만든다.

LicensePrivacy
© won2dev 2026. All rights reserved.
Home›Project›AI 에이전트에게 부하테스트를 맡겼더니, 테스트 환경을 직접 만들고 버그까지 찾아냈다
Project

AI 에이전트에게 부하테스트를 맡겼더니, 테스트 환경을 직접 만들고 버그까지 찾아냈다

won2dev·2026년 05월 30일
#MSA#k6#CI/CD#Docker
AI 에이전트에게 부하테스트를 맡겼더니, 테스트 환경을 직접 만들고 버그까지 찾아냈다
"MSA 프로젝트를 진행하면서 재미있었던 것들만 추려서 쓰는 글이라, 이번 건 안 쓰면 아쉬울 것 같았다."

프로젝트 코드: GitHub


먼저, 버그부터

테스트는 두 개의 시나리오로 나눠서 진행했다.

시나리오 A: 주문 생성 (SAGA / 쓰기 테스트)

이미지

주문 생성이 계속 503으로 터졌다.

처음엔 Gateway 화이트리스트 누락 문제라고 봤는데, 파고들수록 더 근본적인 원인이 나왔다.

모든 마이크로서비스는 CustomPreAuthFilter로 X-Gateway-Secret 헤더를 검증한다. 이 값이 없으면 무조건 403을 뱉는 구조인데, Feign Client는 Eureka를 통해 서비스끼리 직접 통신하기 때문에 Gateway를 거치지 않는다. 즉 Gateway가 붙여주던 X-Gateway-Secret 헤더가 Feign 요청에는 없었고, company-service 입장에서는 비정상적인 직접 접근으로 판단해 403을 던진 거다. order-service는 그 실패를 COMPANY_SERVICE_UNAVAILABLE로 처리했고, 외부에서는 503으로 보였다.

해결은 두 가지였다. Feign 요청 시 X-Gateway-Secret을 자동으로 주입하는 GatewayFeignInterceptor를 추가하고, 내부 API 경로 /api/v1/internal/**는 SecurityConfig에서 permitAll로 열어줬다. Feign을 사용하는 서비스 간 호출 전체에 동일하게 적용했다.

코드 자체엔 문제가 없고, 인프라 구성 레이어에서 터지는 이슈라 통합 테스트로는 잡기 어렵다. 외부에서 실제로 쏴봐야 보이는 종류였다.


시나리오 B: 로그인 + 주문 목록 조회 (읽기 테스트)

이미지

동시 사용자 50명, 2분간 지속. 1,676건 전부 성공. 평균 응답 1.43초, p95 1.65초.

테스트 규모가 아주 큰 수준은 아니지만, MSA 환경에서 로그인 → 조회 플로우가 외부 트래픽 기준으로 전부 정상 수행된다는 건 충분히 검증했다. 게이트웨이의 인증 처리도 이 부하에서는 안정적이었다.

참고로 이번 테스트에서는 단순 조회 성능 측정 외에도 로그인, 주문 생성(SAGA), 서비스별 읽기/쓰기 성능 측정, 헤더 전파 검증, 데이터 정합성 검증, 배송 서비스 장애 상황 검증 등을 함께 진행했다. 본 글에서는 그중 대표적인 사례만 정리했다.


근데 이 테스트를 한 게 AI 에이전트다

그냥 k6 스크립트만 실행한 게 아니다.

Manus AI는 Computer Use 방식의 실행형 에이전트라, 자체 샌드박스에서 직접 명령을 실행한다. 여기서 흐름이 이렇게 됐다.

  1. Swagger JSON 분석 — 게이트웨이에서 뽑아둔 각 서비스 API 명세를 읽고, 서비스 간 Feign 호출 경로와 SAGA 로직을 직접 파악
  2. DB 시딩 — 샌드박스에서 PostgreSQL 클라이언트를 설치하고, 원격 DB에 직접 접속해서 고정 UUID 기반의 허브·업체·상품 데이터를 주입. 권한 매핑도 직접 수정
  3. k6 스크립트 작성 및 실행 — 위에서 파악한 SAGA 흐름에 맞게 시나리오를 구성하고, 그 샌드박스에서 우리 배포 서버로 직접 트래픽 발생

"AI가 부하테스트를 했다"는 것보다, "AI가 테스트 환경을 직접 구축했다"는 게 더 정확한 표현이다.

그리고 이 샌드박스가 우리 서버 외부에 있으니까, 여기서 쏘는 트래픽은 실질적으로 외부 사용자 트래픽이다. 로컬에서 localhost로 쏘는 것과는 다른 얘기다.


AI한테 DB 접근을 허용하는 게 위험하지 않냐

사실 이 부분이 좀 걸릴 수 있다.

위험할 수 있다. AI가 DB에 직접 접근하면, 잘못된 쿼리를 실행하거나 데이터를 건드릴 수 있다.

근데 이건 결국 프롬프트와 하네스 설계 문제다. 테스트 전용 DB를 따로 두고, 접근 가능한 작업을 명확히 정의하면 리스크를 충분히 제어할 수 있다. 이번에도 운영 DB가 아닌 테스트 환경에서 진행했다.

AI를 다 신뢰할 필요는 없다. 근데 AI를 사용해서 정확한 검증을 할 수 있다면, 이번처럼 통합 테스트 코드로는 못 잡는 문제도 찾아낼 수 있다. AI 자체를 신뢰하는 게 아니라, AI가 만든 결과를 검증 도구로 활용하는 거다. 그 줄타기를 잘 하는 게 포인트다.


이 테스트를 가능하게 만든 환경

CI/CD 구성

이번 프로젝트에서 CI/CD를 처음으로 직접 CD까지 이어붙여봤다. GitHub Actions 기반.

CI가 끝나면 서버에서 git pull을 받고, 그 자리에서 직접 빌드해서 Docker 이미지를 만드는 방식이다. 도커 허브에 이미지를 올리지 않는다.

이유는 단순하다. 이미지를 허브에 올리면 워크플로우 스텝이 하나 더 필요하고, 이미지가 외부에 노출된다. 지금 서버 사양이 충분해서 서버에서 직접 빌드하는 게 더 간단하고 보안상으로도 낫다고 판단했다.

물론 이미지를 허브에 올리는 방식이 나쁜 건 아니다. 멀티 서버 환경이거나 빌드 시간이 부담되는 경우엔 그쪽이 맞다. 각 상황에 따라 다른 거다.

Docker Compose 파일을 2개로 나눈 이유

Compose 파일이 인프라용(docker-compose.infra.yml)이랑 애플리케이션용(docker-compose.yml) 두 개다.

인프라 파일에는 PostgreSQL, Redis, Keycloak, Zipkin 같은 것들이 들어간다. 이 서비스들은 배포할 때마다 재시작할 필요가 없다. Keycloak은 재시작하면 세션이나 realm 설정이 날아갈 수도 있고.

애플리케이션은 매 배포마다 내려갔다 올라와야 하고, 인프라는 한 번 올리면 건드리지 않는다. 이 두 사이클이 달라서 나눴다.

DB를 Docker가 아니라 서버에 직접 설치하는 방법도 있다. 그것도 충분히 합리적이다. 환경 재현성이 중요한지, 운영 안정성이 더 중요한지에 따라 선택이 달라진다. 정답은 없다.

Swagger 정적 파일로 문서화

게이트웨이 띄운 상태에서 각 서비스 OpenAPI JSON을 받아뒀다.

bash
curl http://localhost:8080/user/v3/api-docs       -o user-service.json
curl http://localhost:8080/company/v3/api-docs    -o company-service.json
curl http://localhost:8080/hub/v3/api-docs        -o hub-service.json
curl http://localhost:8080/order/v3/api-docs      -o order-service.json
curl http://localhost:8080/delivery/v3/api-docs   -o delivery-service.json
curl http://localhost:8080/user/v3/api-docs       -o user-service.json
curl http://localhost:8080/company/v3/api-docs    -o company-service.json
curl http://localhost:8080/hub/v3/api-docs        -o hub-service.json
curl http://localhost:8080/order/v3/api-docs      -o order-service.json
curl http://localhost:8080/delivery/v3/api-docs   -o delivery-service.json

이걸 Swagger Editor에 올리면 서버 안 띄워도 UI로 볼 수 있다. 팀원 누구나 JSON 파일만 있으면 API 문서를 확인할 수 있어서 편하다.

그리고 이번엔 이 JSON 파일들이 Manus가 서비스 간 호출 관계를 파악하는 재료가 됐다. 그냥 문서화 용도로만 쓴 게 아니라, AI가 직접 읽고 테스트 시나리오를 생성하는 데 활용됐다는 게 재미있었다.


정리

"외부 트래픽이랑 내부 테스트는 다르다"는 생각에서 시작했는데, 실제로 달랐다.

AI를 써서 테스트를 자동화한 게 포인트가 아니다. AI가 외부 관점에서 환경을 구축하고 트래픽을 쏘니까, 코드 리뷰나 통합 테스트에서 안 보이는 인프라 레이어 이슈가 드러났다는 게 포인트다.

다음에는 쿠버네티스 환경에서도 같은 방식으로 검증해볼 생각이다.

공유하기
다음 글 JWT는 Stateless가 장점인데, 왜 Redis까지 붙였나

목차

  • 먼저, 버그부터
  • 근데 이 테스트를 한 게 AI 에이전트다
  • AI한테 DB 접근을 허용하는 게 위험하지 않냐
  • 이 테스트를 가능하게 만든 환경
  • CI/CD 구성
  • Docker Compose 파일을 2개로 나눈 이유
  • Swagger 정적 파일로 문서화
  • 정리

카테고리

Project

태그

#MSA#k6#CI/CD#Docker

최근 글

JWT는 Stateless가 장점인데, 왜 Redis까지 붙였나Keycloak을 처음 쓰면서 배운 것들 — 그게 뭔지도 모르고 시작했다MSA에서 트랜잭션은 왜 어려운가 — 분산 트랜잭션과 Saga PatternFK는 포인터다 — 주문 시스템에서 스냅샷이 필요한 이유Kafka 입문 — 메시징 큐가 왜 필요한가