DevOps 2026.11.02 7 min read

기존 RCA 서비스를 Jenkins에 연결하고 377개에서 638개까지 검증 범위 넓히기

처음부터 전체 CI가 완성된 것은 아니었다. 첫 실행에서는 Java 테스트와 통합 JAR 패키징을 확인했고, 이후 Frontend와 Python, 격리 DB, 실행 이미지 검사까지 추가했다. 이 과정에서 테스트 숫자가 늘어난 이유와 각 실행이 실제로 증명한 범위를 함께 남겼다.

SSH Agent에서 짧은 검증 Pipeline이 성공한 뒤 실제 빌드 대상을 정해야 했다. 새 샘플 서비스를 만드는 대신 개발해 둔 RCA Platform을 연결했다. Java 서버, React 화면, Python Agent가 있는 프로젝트라서 빌드 자동화의 범위를 단계적으로 넓히기에도 적합했다.

처음부터 전체 CI가 완성된 것은 아니었다. 첫 실행에서는 Java 테스트와 통합 JAR 패키징을 확인했고, 이후 Frontend와 Python, 격리 DB, 실행 이미지 검사까지 추가했다. 이 과정에서 테스트 숫자가 늘어난 이유와 각 실행이 실제로 증명한 범위를 함께 남겼다.

프론트와 서버를 하나의 JAR로 만들었다

처음에는 프론트와 백엔드를 따로 배포하는 서비스처럼 생각한 부분이 있었다. 실제 빌드 로그를 보니 이 프로젝트는 React의 정적 파일을 Spring Boot JAR 안에 넣는 구성이었다. Maven의 frontend profile이 프론트를 빌드하고 결과를 Java 정적 리소스 경로에 복사한 뒤 실행 JAR를 만들었다.

초기 Jenkins Pipeline은 이 구조에 맞춰 Java 테스트와 통합 패키징을 분리했다. 당시 단계에서 사용한 명령의 핵심은 다음과 같았다.

Backend Test
  mvn -B -ntp -f web-console/pom.xml test

Integrated Package
  mvn -B -ntp -f web-console/pom.xml -Pfrontend -DskipTests package

두 번째 명령의 -DskipTests는 앞서 실행한 테스트를 패키징 중 다시 돌리지 않기 위한 설정이었다. 패키징 로그의 Tests are skipped 한 줄만 떼어 보면 테스트를 전혀 하지 않은 빌드처럼 보일 수 있었다. 같은 실행의 앞선 Test stage와 이어서 읽어야 했다.

이 코드는 초기 Jenkins UI Pipeline의 일부다. 이후 저장소의 ci/Jenkinsfile을 사용하는 최종 파이프라인과는 시점이 달랐다. 초기 설정을 최신 구현 전체처럼 소개하지 않고, 첫 빌드에서 확인한 동작을 설명하는 데 사용했다.

첫 결과는 377개 목록 중 skipped 4개였다

최초 업로드 로그에는 다음 Surefire 집계가 남았다.

Tests run: 377, Failures: 0, Errors: 0, Skipped: 4
BUILD SUCCESS

실패와 오류는 없었지만 377개 모두가 실행된 것은 아니었다. 목록 377개 중 4개가 skipped였다는 원래 집계를 유지했다. 통과 숫자를 크게 보이게 바꾸기보다 어떤 결과가 남았는지 그대로 적는 편이 다음 실행과 비교하기에도 정확했다.

이어진 패키징에서는 Node와 npm을 프로젝트 내부에 설치했다. 전역 Node 설치를 전제로 한 구성이 아니었다. 로그에는 Node v22.22.0과 npm 11.3.0 설치, npm ci, tsc --noEmit && vite build가 차례로 나타났다. 프론트 빌드 뒤 다섯 개 리소스를 target/classes/static으로 복사하고 Spring Boot repackage를 끝냈다.

Java Test stage는 약 4분 12초, 통합 패키징은 약 1분 1초가 걸렸고 마지막에는 RCA Platform CI SUCCESS와 Finished: SUCCESS가 남았다. 이때 확인한 것은 Java 테스트와 React 빌드를 포함한 JAR 생성이었다. Frontend 단위 테스트와 Python 테스트까지 이 최초 성공에 포함시키지는 않았다.

테스트 수보다 실행 범위를 먼저 비교했다

후속 작업에서는 Java 외의 코드도 같은 CI 흐름에서 검증하도록 넓혔다. 최종 main 빌드는 Backend, Frontend, Python, Integrated JAR 순서로 진행한 뒤 이미지 빌드와 런타임·보안 검사를 이어 갔다. 최종 집계는 다음과 같았다.

구분 최종 main 결과
Java Surefire 393개 + Failsafe 2개 = 395개
Frontend 24개
Python 219개
합계 638개, 실패·오류·skips 모두 0

격리한 PostgreSQL과 MariaDB 검사 네 개, 패키징된 CLI 검사 두 개도 실제 실행 범위에 들어갔다. 이 항목을 표의 합계 밖에 임의로 더하지 않았다. 별도 CI helper의 회귀 검사 54개는 애플리케이션 638개와 분리해서 기록했다.

Jenkins main build 1의 638 pass·0 fail·0 skipped
Jenkins main build 1의 638 pass·0 fail·0 skipped.

초기와 최종 사이에는 622개 테스트가 통과하고도 이미지 빌드 전에 멈춘 실행이 있었고, 638개 테스트와 Push가 끝난 뒤 검증 로직에서 실패한 실행도 있었다. 테스트 성공만으로 파이프라인 전체를 성공 처리할 수 없었다. 어느 단계까지 통과했는지와 최종 빌드 상태를 함께 봤다.

패키징 성공과 실행 검증을 연결했다

JAR가 만들어졌다는 사실은 컨테이너 안에서 원하는 사용자로 기동한다는 뜻까지 포함하지 않았다. 최종 흐름에서는 Platform과 Agent를 각각 rootless로 빌드하고 UID 65532 런타임 검증을 거쳤다. Java·Frontend·Python 테스트 다음에 런타임 확인을 둔 이유였다.

Agent의 safe 모드 fixture도 별도로 실행했다. 이 검사는 제한된 네트워크와 파일시스템 조건에서 허용한 호출만 수행하는지를 확인하는 범위였다. 운영 클러스터에 접근하거나 실제 운영 Agent를 교체하는 시험으로 설명하지 않았다.

의존성과 실행 기반도 초기와 후속 작업 사이에 바뀌었다. 최초 패키징 로그의 Spring Boot 3.5.16과 최종 작업의 Boot 4.1.1을 같은 시점의 값처럼 섞지 않았다. 테스트 수 증가와 함께 실제로 어떤 소스와 환경을 검사했는지가 중요했다.

최종 main 빌드의 테스트 638개 통과 결과
main build #1의 테스트 638개 통과, 실패·건너뜀 0개.
완료된 Jenkins Pipeline 단계
main build #1의 Pipeline 단계 완료.

638개가 모든 검증을 뜻하지는 않았다

최종 빌드에서는 브라우저 테스트를 선택하지 않았다. 실제 외부 LLM 서비스 호출도 수행하지 않았고, 로컬 HTTP fixture와 호환성 검사 결과를 그 대체 증거로 확대하지 않았다. 638이라는 숫자에 브라우저 E2E나 실제 클라우드 호출까지 포함됐다고 설명하지 않은 이유다.

기존 서비스를 CI에 연결하면서 단순한 성공 표시보다 단계와 산출물의 관계를 읽는 일이 더 중요해졌다. Java 테스트가 끝났는지, 프론트가 JAR에 들어갔는지, 만들어진 이미지가 기동하는지, 이후 게시 검증까지 끝났는지를 각각 남겼다. 다음 단계에서는 이 테스트 결과를 실제 Registry 이미지의 출처와 연결했다.

SEARCH JOURNAL

기록 검색

글 제목, 요약, 태그에서 찾습니다.

검색을 준비하고 있어요.

검색어를 입력해 주세요.

    Ctrl/⌘ K 검색 Esc 닫기 ↑ ↓ 결과 이동