오픈소스 인사이트
home
오픈소스 기술 동향
home

오픈소스 배포에서 불필요한 산출물을 줄이는 방법

참고: 아래 글은 소나타입(Sonatype)의 공식 블로그 글을 번역하여 작성되었습니다. 원문은 Sonatype 공식 블로그에서 확인하실 수 있습니다.

에스코어 인사이트

원문에 앞서 국내 개발·오픈소스 운영 조직이 함께 점검할 만한 사항을 간단히 정리했습니다.
•
배포 전에 번들 구성을 확인: 배포가 끝난 뒤 전체 용량만 보는 대신, 배포 예정 파일과 모듈별 크기, classifier별 비중을 미리 확인할 수 있는 점검 절차를 둡니다.
•
외부 사용 목적이 없는 산출물 분리: 벤치마크 JAR, 내부 테스트 산출물, 개발용 서버처럼 사내 개발 과정에서만 필요한 파일은 공개 저장소에 배포할 이유가 있는지 별도로 확인합니다.
•
도구 기본값까지 개선: 중복 메타데이터 생성, 기계 처리용 파일에 불필요한 들여쓰기와 공백을 추가하는 설정, 자동 아티팩트 첨부처럼 반복적으로 용량을 늘리는 기본값은 개별 프로젝트에만 손대지 말고 플러그인과 공통 빌드 설정에서도 함께 개선합니다.

Sonatype 원문 번역

Maven Central 퍼블리셔들과 지속 가능한 운영에 대해 논의하면서 반복해서 확인한 점이 하나 있습니다. Central에 올라오는 파일 가운데 상당수는 애초에 외부 사용자를 위한 것이 아니었습니다.
악의적이거나 무책임해서 생긴 문제도 아니고, 특별히 드문 일도 아닙니다. 대부분은 빌드 기본값, 릴리스 관행, 레거시 설정, 굳이 다시 손볼 이유가 없었던 자동화가 오랫동안 쌓인 결과입니다.
빌드가 늘 그렇게 해왔다는 이유로 모든 릴리스에 벤치마크 JAR이 붙습니다. 조직 밖에서는 아무도 사용하지 않는 테스트 픽스처가 공개됩니다. 개발 서버를 shaded JAR로 조립한 뒤 별다른 의도 없이 공개 릴리스 번들에 포함하기도 합니다. 같은 기계 판독용 메타데이터를 여러 형식으로 중복 배포하고, 사람이 읽을 일이 없는 파일을 보기 좋게 포맷팅하기도 합니다.
각각의 선택만 보면 사소해 보일 수 있습니다. 하지만 이런 선택이 수많은 모듈과 릴리스, 퍼블리셔에서 수년간 반복되면 결국 인프라 부담으로 이어집니다.
릴리스가 완전히 정상적이어도 아무도 필요로 하지 않는 파일이 들어 있을 수 있습니다.
Maven Central의 지속 가능성을 개선하는 과정에서도 단순히 사용량 한도를 정하는 것만으로는 부족하다는 점이 분명해지고 있습니다. 배포량을 줄인다고 해서 릴리스 횟수를 줄이거나, 지원하는 사용자 수를 줄이거나, 프로젝트의 가치를 낮춰야 하는 것은 아닙니다.
때로는 릴리스에 실제로 무엇이 들어 있는지 자세히 살펴보는 것만으로도 충분합니다.

낭비와 남용은 다르다

"낭비"라는 표현은 신중하게 사용할 필요가 있습니다. 부주의나 의도적인 과잉 사용을 뜻하는 것처럼 들릴 수 있기 때문입니다. 하지만 퍼블리셔들과 이야기하면서 확인한 대부분의 사례는 그렇지 않았습니다. 각 조직 안에서는 합리적이었던 결정들이 쌓이면서 전체적으로는 비효율적인 결과를 만든 경우가 더 많았습니다.
현대적인 빌드 시스템은 자동화를 전제로 설계됩니다. 플러그인은 아티팩트를 자동으로 추가하고, 상위 프로젝트의 설정은 그대로 상속됩니다. 릴리스 파이프라인은 지정된 대상을 그대로 패키징합니다. 한 번 안정적으로 동작하기 시작한 프로세스는 굳이 손대지 않으려는 경향도 자연스럽습니다.
그 결과 공개 릴리스에는 다음과 같은 파일이 포함될 수 있습니다.
•
내부 벤치마킹에만 사용하는 아티팩트
•
로컬 개발용으로 만든 shaded 실행 파일
•
외부 사용자가 없는 테스트 JAR과 테스트 소스
•
여러 직렬화 형식으로 중복 생성된 메타데이터
•
보기 좋게 포맷팅했지만 기계가 읽는 데에는 도움이 되지 않고 크기만 늘어난 생성 파일
•
과거에는 외부 사용처가 있었지만 지금도 관성적으로 배포되는 모듈
•
전체 릴리스 번들에 포함됐지만 한 번도 함께 검토되지 않은 산출물
이런 사례를 곧바로 Central의 오용이라고 보기는 어렵습니다. 처음에는 타당한 이유가 있었지만 시간이 지나며 그 이유가 사라졌는데도 그대로 유지된 배포 결정에 가깝습니다.
그래서 퍼블리셔는 릴리스의 전체 크기와 구성을 한눈에 볼 수 있어야 합니다. 그렇지 않으면 반드시 필요한 파일과 단순히 포함되어 있는 파일을 구분하기 어렵습니다.

Central은 릴리스 전체를 본다

개발자는 보통 모듈별 아티팩트를 따로 살펴보지만, Central에는 모든 모듈의 산출물이 한꺼번에 들어옵니다.
한 모듈에 불필요한 파일 몇 개가 있는 정도는 큰 문제가 아닐 수 있습니다. 하지만 같은 파일이 수십 개 모듈과 여러 저장소에서 반복 생성되고 릴리스도 자주 이루어진다면 전체 부담은 크게 커집니다.
개별 조직에서는 합리적인 선택도 수많은 프로젝트에서 반복되면 공유 인프라에 부담을 줄 수 있습니다. 이번 시리즈에서 계속 다루고 있는 것도 바로 이 점입니다.
테스트 JAR은 작을 수 있습니다. 소스 아카이브는 함께 배포되는 경우가 많습니다. SBOM도 중요한 산출물입니다. shaded 아티팩트가 반드시 필요한 프로젝트도 있습니다.
따라서 특정 classifier나 파일 유형 자체가 낭비인지 따지는 것이 핵심은 아닙니다. 해당 릴리스에서 그 파일을 실제로 필요로 하는 외부 사용자가 있는지를 확인해야 합니다.
사용 목적을 확인하지 않은 채 일괄적인 규칙을 적용하면 문제가 생길 수 있습니다. 다른 개발자가 실제로 의존하는 재사용 가능한 테스트 하네스를 배포하는 프로젝트도 있습니다. 반대로 아무도 쓰지 않는데 빌드 설정 때문에 테스트 아티팩트가 자동으로 붙는 프로젝트도 있습니다. 실행 가능한 배포판이 필요한 프로젝트가 있는가 하면, 라이브러리와 함께 개발 전용 서버를 실수로 배포하는 프로젝트도 있습니다.
파일 이름만 보고 어느 경우인지 판단할 수는 없습니다.

한 퍼블리셔가 릴리스 번들을 직접 점검한 사례

퍼블리셔들과의 논의에서 가장 분명했던 사례 중 하나는 초기 사용 가이드의 기준을 넘는 규모로 릴리스하던 한 상용 퍼블리셔였습니다.
해당 조직의 이름은 공개하지 않지만, 정당한 릴리스를 줄이거나 사용자에게 제공하는 내용을 바꾸지 않고도 큰 개선을 이뤘다는 점에서 살펴볼 가치가 있습니다.
이 팀은 먼저 빌드 과정에서 실제로 어떤 파일이 배포 대상에 포함되는지 확인했습니다.
작은 점검 스크립트를 만들어 실제 배포 없이 릴리스를 미리 실행하고, 생성된 번들을 검사해 다음 항목을 보고하도록 했습니다.
•
예상되는 전체 릴리스 크기
•
각 모듈의 크기
•
아티팩트 classifier별 용량 비중
•
릴리스에서 가장 큰 용량을 차지하는 파일
스크립트를 정교하게 만드는 것이 목적은 아니었습니다. 중요한 것은 그동안 잘 보이지 않던 릴리스 구성을 실제로 판단하고 조정할 수 있는 정보로 드러냈다는 점이었습니다.
점검 결과 줄일 수 있는 산출물이 여러 종류 발견됐습니다. 벤치마킹 모듈은 지속적인 성능 테스트에 필요한 대형 shaded JAR을 만들고 있었지만 외부에서는 사용되지 않았습니다. 일부 저장소에서는 엔지니어가 로컬에서 라이브러리를 시험할 수 있도록 개발 서버를 fat JAR로 조립했습니다. 개발 과정에서는 유용했지만 Central을 통해 배포할 이유는 없었습니다.
팀은 테스트 JAR과 테스트 소스 JAR도 모듈별로 점검했습니다. 다른 프로젝트가 실제로 사용하는 재사용 가능한 테스트 하네스나 계약 테스트 스위트는 그대로 배포했습니다. 내부에서만 사용하거나 아무도 사용하지 않는 아티팩트는 공개 릴리스에서 제외했습니다.
감축 효과는 상당했습니다.
세 차례의 보고 기간 동안 이 조직의 전체 릴리스 크기는 약 3GB에서 1.5GB로, 다시 약 300MB까지 줄었습니다. 릴리스 건수와 주기는 큰 차이가 없었습니다. 소프트웨어 제공 자체를 줄인 것이 아니라 무엇을 배포할지 더 명확하게 판단한 결과였습니다.
여기서 중요한 점은 제품 품질을 희생해 숫자만 줄인 것이 아니라는 것입니다. 애초에 Central 사용자가 필요로 하지 않았던 파일을 찾아낸 것입니다.

가장 큰 파일이 바이너리라는 보장은 없다

같은 점검 과정에서 예상 밖의 결과도 나왔습니다.
의도치 않게 포함된 대형 아티팩트를 제거하고 나자 일부 릴리스 번들에서는 SBOM이 차지하는 비중이 눈에 띄게 커졌습니다.
SBOM이 낭비라는 뜻은 아닙니다. SBOM은 소프트웨어 투명성을 높이기 위해 다양한 정보를 담는 중요한 산출물이므로, 정보가 풍부한 것 자체가 문제는 아닙니다. 다만 의존성 트리가 깊은 프로젝트에서는 기계가 읽는 문서인 SBOM 자체도 상당히 커질 수 있습니다.
이 사례에서는 같은 의미의 정보를 두 가지 이상의 직렬화 형식으로 만들고 있었습니다. 퍼블리셔는 실제 외부 사용처에서 쓰는 형식 하나만 배포하도록 변경했습니다.
SBOM 파일에 기본적으로 들여쓰기와 공백을 넣어 보기 좋게 포맷팅한다는 점도 확인했습니다. 사람이 읽는 문서라면 들여쓰기와 공백이 유용하지만, 주로 기계가 처리하는 산출물에는 그만큼 필요하지 않습니다.
퍼블리셔는 더 간결한 출력을 쉽게 만들 수 있도록 업스트림 프로젝트에 변경 사항을 기여했고, 이후 빌드 도구에서 그 기능을 사용하기 위한 적용 작업을 시작했습니다. 규모가 큰 일부 모듈에서는 불필요한 포맷팅을 제거해 SBOM 하나당 약 100~150KB를 줄였습니다. 파일 하나만 보면 큰 차이는 아니지만 모듈과 릴리스마다 반복되면 무시하기 어려운 용량이 됩니다. 자세히 들여다보기 전까지 보이지 않던 불필요한 용량이 드러난 사례입니다.
이 사례를 보면 지속 가능한 운영을 위한 개선이 개별 퍼블리셔 설정에만 머물러서는 안 된다는 점도 알 수 있습니다.
불필요한 산출물이 도구의 기본값 때문에 만들어지는 경우도 있습니다. 원인을 도구 자체에서 바로잡으면 이후 그 도구를 사용하는 모든 프로젝트가 같은 개선 효과를 얻을 수 있습니다.

배포 과정에서 생기는 낭비의 유형

앞선 사례처럼 불필요한 배포는 몇 가지 유형으로 나눌 수 있습니다.

외부 사용자가 없는 아티팩트

개발, 테스트, 벤치마킹, 내부 운영에는 필요하지만 프로젝트의 공개 인터페이스에는 포함되지 않는 파일입니다.
이런 파일이 유용할 수 있고, 퍼블리셔 내부의 엔지니어링 과정에서는 반드시 필요할 수도 있습니다. 그렇다고 Central이 적절한 배포 장소라는 뜻은 아닙니다.
가장 명확하게 줄일 수 있는 유형입니다. 아티팩트 자체에는 문제가 없지만 실제로 받아 쓸 외부 사용자가 없습니다.

같은 정보를 여러 형태로 중복 배포

메타데이터를 XML과 JSON으로 동시에 만들거나, 압축본과 비압축본을 함께 만들거나, 여러 플러그인이 비슷한 산출물을 각각 생성할 수 있습니다.
실제로 여러 형식을 필요로 하는 사용자도 있습니다. 반면 각 도구가 선호하는 형식을 제각각 추가하면서 중복 배포되는 경우도 있습니다.
두 파일이 같은 정보를 담고 있는데 실제로는 하나만 사용한다면 둘 다 배포하는 것은 그만큼 비용만 늘릴 뿐 추가 가치를 만들지 못합니다.

빌드 산출물을 릴리스 산출물로 오인하는 경우

소프트웨어 빌드 과정에서는 최종 릴리스에 도달하기까지 많은 파일이 만들어집니다. 중간 패키지, 개발 서버, 진단 번들, 자동 생성된 테스트 픽스처, 벤치마크 실행 파일, 임시 조립 산출물이 모두 정상적인 빌드 산출물일 수 있습니다.
하지만 빌드 중에 생성됐다는 이유만으로 공개 릴리스 아티팩트가 되는 것은 아닙니다.
Central은 릴리스 준비가 끝난 컴포넌트를 공개 배포하는 곳이지, 파이프라인이 만들어낼 수 있는 모든 파일을 영구 보관하는 장소가 아닙니다. 이 구분은 처음부터 지속 가능성 논의의 중요한 기준이었습니다.

과거 설정이 그대로 남아 있는 배포

어떤 모듈은 과거에 외부 사용자가 있었을 수 있습니다. 오래된 툴체인이 특정 classifier를 요구했거나, 몇 년 전 상위 프로젝트에서 릴리스 프로필을 복사해 왔을 수도 있습니다.
공개 아티팩트는 추가하기는 쉽지만, 제거하면 호환성 문제가 생길 수 있어 없애도 되는지 판단하기는 어렵습니다. 그렇다고 해당 아티팩트가 지금도 실제로 사용되는지 확인하지 않을 이유는 없습니다.
중요한 것은 무작정 삭제하는 것이 아니라, 해당 아티팩트가 지금도 실제로 사용되는지 확인할 근거를 확보하는 것입니다.

필요 이상으로 큰 산출물

반드시 필요한 아티팩트라도 실제 필요보다 크게 만들어지는 경우가 있습니다.
기계가 읽는 문서에 불필요한 들여쓰기와 공백을 넣는 것이 대표적인 예입니다. 같은 의존성을 반복해서 포함하거나, 의도치 않게 shading이 적용되거나, 리소스를 압축하지 않거나, 중복 정보가 많은 메타데이터를 생성하는 경우도 있습니다.
모든 바이트를 줄이는 것이 목표가 되어서는 안 됩니다. 엔지니어링 시간에도 비용이 들고, 지나친 최적화는 인프라 절감 효과보다 더 큰 복잡성을 만들 수 있습니다.
비교적 간단한 변경으로 실질적인 중복을 줄이면서 유용성은 그대로 유지할 수 있는지를 확인하는 편이 더 현실적입니다.

최적화는 측정에서 시작된다

익명의 퍼블리셔 사례를 보면 처음부터 정책 엔진이나 복잡한 플랫폼이 필요했던 것은 아닙니다.
처음 필요했던 것은 보고서였습니다.
점검 스크립트를 만들기 전에도 릴리스 프로세스 자체는 정상적으로 동작했습니다. 다만 팀은 전체 배포 번들에 무엇이 들어가는지 명확히 볼 수 없었습니다. 산출물을 모듈, 아티팩트 유형, 크기별로 묶어 보자 줄일 수 있는 후보가 분명하게 드러났습니다.
퍼블리셔와 인프라 운영자 모두 이런 방식으로 릴리스 구성을 점검할 수 있습니다.
퍼블리셔는 배포가 끝난 뒤 전체 용량을 확인하는 데 그치지 않고, 배포 전에 무엇이 나갈지 볼 수 있어야 합니다. 다음과 같은 질문에 답할 수 있는 릴리스 점검 절차가 유용합니다.
•
무엇이 배포될 예정인가?
•
새로 추가된 파일은 무엇인가?
•
전체 크기에서 가장 큰 비중을 차지하는 모듈은 무엇인가?
•
어떤 classifier가 붙어 있는가?
•
이전 릴리스와 비교하면 무엇이 달라졌는가?
•
각 아티팩트가 외부에서 어떻게 쓰이는지 확인됐는가?
이런 질문에 답하기 위해 릴리스마다 포렌식 조사에 가까운 수작업을 반복해서는 안 됩니다. 이상적인 빌드·릴리스 도구라면 배포 번들의 구성을 쉽게 확인할 수 있어야 합니다.
한 퍼블리셔가 직접 점검 스크립트를 만든 것은 긍정적이지만, 동시에 생태계 전반에 이런 용도의 도구가 부족하다는 뜻이기도 합니다.

모든 감축이 가치 있는 것은 아니다

낭비를 줄이자는 논의가 최소화 자체에 집착하는 방향으로 흐를 위험도 있습니다.
하지만 모든 산출물을 무조건 줄이는 것은 잘못된 결론입니다.
소스 JAR, 문서, 서명, 프로비넌스, SBOM, 체크섬, 메타데이터는 모두 정당한 역할이 있습니다. 파일이 커지더라도 사용성이 좋아질 수 있습니다. 재사용 가능한 테스트 픽스처 하나가 여러 외부 팀이 같은 것을 다시 만드는 수고를 줄여줄 수도 있습니다. 생태계가 하나의 형식으로 통일되지 않았다면 여러 형식이 반드시 필요할 수 있습니다.
지속 가능성을 이유로 유용한 자료를 없애거나 릴리스를 사용하기 어렵게 만들어서는 안 됩니다.
기준은 "가능한 한 적은 바이트를 배포하라"가 아닙니다.
"외부 사용자에게 가치를 주는 것을 배포하고, 왜 필요한지 알고 있어야 한다"가 기준입니다.
어디까지 필요한 산출물인지는 상황에 따라 판단해야 합니다. 수치만으로 결론을 내리지 않고 실제 용도를 함께 살피는 원칙은 커뮤니티 오픈소스 예외를 판단하는 방식에도 적용됩니다. 수치 데이터는 어디를 살펴봐야 하는지 알려줄 수 있지만, 실제 사용 목적과 상황까지 대신 판단해주지는 못합니다.

효율화는 퍼블리셔에게도 도움이 된다

불필요한 배포를 줄이는 목적은 Central의 부하를 낮추는 것에만 있지 않습니다.
릴리스가 작아지고 구성이 명확해지면 퍼블리셔도 다음과 같은 효과를 얻을 수 있습니다.
•
빌드와 릴리스 파이프라인 단축
•
퍼블리셔 내부 시스템의 저장 공간과 전송량 감소
•
릴리스 크기가 갑자기 변했을 때 원인을 더 쉽게 파악
•
의도하지 않은 공개 정보 노출 감소
•
외부 사용자의 의존성 선택 간소화
•
프로젝트가 실제로 지원하려는 범위만 공개됐다는 확신
익명의 퍼블리셔는 Central 사용량을 더 잘 파악하기 위해 점검을 시작했지만, 그 과정에서 자체 릴리스 프로세스도 훨씬 명확하게 이해하게 됐습니다.
인프라를 제대로 최적화하다 보면 공유 시스템의 낭비를 줄이는 과정에서 그 낭비를 만들어낸 내부 시스템의 비효율도 함께 드러나는 경우가 많습니다.

더 나은 기본값이 중요하다

개별 퍼블리셔가 릴리스 번들을 검토할 수는 있지만, 모든 팀이 같은 문제를 각각 발견하도록 내버려둘 수는 없습니다.
빌드 도구와 플러그인의 기본값은 실제 배포 방식을 크게 좌우합니다. 아티팩트를 자동으로 추가하고, 중복 산출물을 만들고, 기계 처리용 파일에 불필요한 들여쓰기와 공백을 넣고, 릴리스 번들 구성을 확인하기 어렵게 만드는 기본값은 수천 개 프로젝트에서 반복되면서 상당한 비용을 초래할 수 있습니다.
대부분의 사용자는 기본 설정을 따릅니다. 따라서 누군가 이를 정책으로 정하지 않았더라도 기본값 자체가 사실상 인프라 운영 정책처럼 작동합니다.
한 퍼블리셔가 낭비를 찾아냈다면 그 조직의 설정 하나만 바꾸는 데 그쳐서는 안 됩니다. 확인한 개선 사항을 업스트림에도 반영해야 합니다.
•
플러그인
•
상위 POM
•
릴리스 도구
•
문서
•
배포 전에 릴리스 번들 구성을 확인할 수 있는 기능
앞서 소개한 퍼블리셔도 최적화를 로컬 설정에만 남겨두지 않고 업스트림 SBOM 라이브러리에 변경 사항을 기여했습니다.
이렇게 개별 조직의 개선이 생태계 전체의 개선으로 이어질 수 있습니다.

목적을 분명히 하고 배포하기

Maven Central은 Java 생태계에 유용한 소프트웨어를 쉽게 배포할 수 있는 공간이어야 합니다.
그렇다고 모든 빌드 산출물을 영구적인 공개 아티팩트로 만들어야 하는 것은 아닙니다. 릴리스를 불편하거나 불완전해질 정도까지 최소화할 필요도 없습니다.
중요한 것은 무엇을 왜 배포하는지 명확히 판단하는 것입니다.
릴리스에는 사용자가 실제로 필요로 하는 바이너리, 메타데이터, 문서, 보안 정보, 지원에 필요한 아티팩트가 들어 있어야 합니다. 퍼블리셔 내부 엔지니어링 과정에서만 필요한 파일은 대부분 다른 곳에 보관하는 편이 적절합니다. 같은 정보를 두 번 배포하고 있다면 두 파일이 모두 필요한지 따져볼 수 있습니다. 도구의 기본값 때문에 파일이 커지고 있다면 그 기본값을 개선할 수 있는지도 살펴볼 가치가 있습니다.
각 결정은 하나씩 보면 사소해 보입니다. 하지만 Central에서는 같은 선택이 생태계 전체에서 반복됩니다.
지속 가능성 개선 작업은 규모, 한도, 상용 사용, 커뮤니티 예외처럼 눈에 잘 보이는 문제에서 시작했습니다. 이런 문제는 여전히 중요합니다. 퍼블리셔들과 논의하면서 무엇을 배포하고 있는지 정확히 파악하고, 더 이상 목적이 없는 산출물을 제거하도록 돕는 일도 중요하다는 점이 분명해졌습니다.
가장 좋은 방법은 불필요한 산출물을 더 싸게 처리하거나 저장하거나 사후에 최적화하는 것이 아닙니다.
애초에 불필요한 파일이 시스템에 들어오지 않게 하는 것입니다.
에스코어는 Sonatype 공식 파트너로서 소프트웨어 공급망 보안 및 오픈소스 거버넌스 구축을 지원합니다. 도입이나 구축이 필요하시면 언제든 문의해 주세요. 지원 솔루션: Nexus Repository · Repository Firewall · Lifecycle · Sonatype Guide