[ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.8.2:deploy
Could not transfer artifact ... from/to maven-snapshots (...)
transfer failed, status: 500 Server Error
자사에서 서비스 배포 중 GitLab CI/CD 파이프라인에서 Maven deploy 단계가 위와 같은 에러로 실패하기 시작했습니다. 전체 프로젝트의 SNAPSHOT 배포가 막혀버린 상황이라 원인을 빨리 찾아야 했습니다.
500 에러라서 처음에는 네트워크나 권한 문제인가 싶었는데, Nexus 서버에 직접 들어가 보니 훨씬 근본적인 문제가 있었습니다.
원인 분석
1. EC2 디스크 용량 부족
가장 먼저 확인한 건 디스크 사용량이었습니다.
df -h
# /dev/nvme0n1p1 50G 46G 4.2G 92% /
전체 50GB 중 46GB, 무려 92%를 사용 중이었습니다. 뭐가 이렇게 공간을 잡아먹고 있나 봤더니 역시나 Nexus였습니다.
du -sh /app/sonatype-work/nexus3/*
# 39G /app/sonatype-work/nexus3/blobs
blob 저장소 하나가 39GB를 차지하고 있었습니다.
2. OrientDB read-only 전환
문제는 여기서 끝이 아니었습니다. 디스크 여유 공간이 Nexus 내부 DB인 OrientDB의 최소 요구치(4,096MB)에 가까워지면서, DB 자체가 read-only 모드로 전환되어 있었습니다.
OLowDiskSpaceException: Error occurred while executing a write operation to database 'config'
due to limited free space on the disk (4077 MB).
The database is now working in read-only mode.
The minimal required space is 4096 MB.
3. 정리하고 싶어도 정리가 안 되는 악순환
여기서부터가 진짜 답답한 부분이었는데, DB가 read-only 상태가 되니까 정작 디스크를 비워줄 Cleanup Task 자체를 실행할 수 없는 상황이 되어버렸습니다. 디스크가 가득 차서 정리 기능이 멈추고, 정리 기능이 멈춰서 디스크를 못 비우는 전형적인 악순환이었습니다.
게다가 UI에서는 Compact blob store Task가 "Running" 상태로 표시되고 있었지만, 실제 로그를 까보니 이미 취소(Task canceled 'compact blob')된 좀비 상태였습니다. 화면만 보고 있었으면 계속 헛짓을 하고 있었을 뻔했습니다.
해결 과정
1. 진짜 범인 찾기
디스크 전체를 다시 훑어봤습니다.
du -sh /* 2>/dev/null | sort -rh | head -20
# 40G /app
# 4.7G /var
du -sh /var/log/*
# 3.5G /var/log/journal ← 여기
/var/log/journal이 3.5GB나 차지하고 있었습니다. systemd journal 로그가 이렇게 쌓일 수 있다는 걸 이번에 제대로 체감했습니다.
2. journal 로그 정리로 숨통 틔우기
journalctl --vacuum-time=2d
이 한 줄로 약 1GB를 확보했고, OrientDB 최소 요구치(4,096MB)를 겨우 넘겨서 read-only 상태를 풀 수 있는 조건을 만들었습니다.
3. Nexus 재시작
systemctl restart nexus
재시작 후 OrientDB의 read-only 상태가 정상적으로 해제된 것을 확인했습니다.
4. Nexus Task를 순서대로 실행
- Maven - Delete SNAPSHOT 실행 → 오래된 SNAPSHOT 컴포넌트 99개 삭제 마킹 완료
- Admin - Compact blob store 실행 → 마킹된 파일들을 실제로 물리 삭제
결과적으로 46GB → 18GB로, 디스크 사용률이 92%에서 35%까지 내려왔습니다.
각 Task가 하는 일 (정리하면서 알게 된 것)
이번 일을 겪으면서 Nexus의 정리 관련 Task들이 각각 어떤 역할을 하는지 헷갈렸던 부분을 정리해봤습니다.
Task 역할
| Delete SNAPSHOT cleanup | maven-snapshots 레포 전용. 보존 기준에 따라 오래된 SNAPSHOT을 삭제 마킹만 함 |
| Cleanup service | 전체 레포 대상. 연결된 Cleanup Policy 규칙대로 삭제 마킹만 함 |
| Compact blob store | 위 두 Task가 마킹해둔 파일을 실제로 디스크에서 물리 삭제 |
여기서 중요한 포인트는, 앞의 두 Task는 "삭제 마킹"만 할 뿐 실제 디스크 용량을 돌려주지 않는다는 겁니다. Compact blob store가 돌아야 비로소 디스크 공간이 줄어듭니다. 이 구조를 모르고 있으면 "Cleanup Task를 돌렸는데 왜 용량이 그대로지?" 하고 헤맬 수 있을 것 같습니다.
Nexus의 blob store는 기본적으로 soft delete 방식으로 동작한다는 것도 이번에 알게 됐습니다.
재발 방지를 위해 정리한 것들
Cleanup Policy 분리
원래는 default Policy(Component Usage 1000일 기준)가 release 레포와 snapshot 레포 양쪽에 그대로 적용되어 있었습니다. SNAPSHOT은 굳이 그렇게 오래 들고 있을 이유가 없어서, 전용 Policy를 새로 만들었습니다.
항목 값
| Name | snapshot-cleanup |
| Format | maven2 |
| Component Age | 90일 |
| Component Usage | 90일 |
| Release Type | Pre-Release / Snapshot Versions |
레포 적용 Policy
| maven-releases | default (Component Usage 1000일) |
| maven-snapshots | snapshot-cleanup (90일 전용) |
Cleanup Task 스케줄링
Task 스케줄 역할
| Delete SNAPSHOT cleanup | 매일 01:00 | SNAPSHOT 삭제 마킹 |
| Compact blob store | 매일 03:00 | 실제 파일 물리 삭제 |
| Cleanup service | 매일 08:00 | Policy 기준 삭제 마킹 |
실행 순서는 Delete SNAPSHOT(01:00) → Compact blob(03:00) → Cleanup service(08:00) → 다음날 Compact blob(03:00) 흐름으로 짜서, 마킹과 물리 삭제가 계속 순환되도록 했습니다.
단기/중기 조치
- systemd journal 로그를 주기적으로 정리 (journalctl --vacuum-time=7d)
- EC2 EBS 볼륨 확장 검토 (50GB → 100GB 정도로)
- 디스크 사용률 80% 초과 시 알람이 오도록 모니터링 설정 필요
마무리
이번 장애를 겪으면서 느낀 건, Nexus 자체보다도 그 아래에서 돌아가는 EC2 인스턴스의 기본적인 리소스 상태를 평소에 잘 안 들여다봤다는 점이었습니다. Nexus만 잘 돌아가면 된다고 생각했는데, 정작 발목을 잡은 건 journal 로그처럼 별생각 없이 지나쳤던 부분이었습니다.
또 하나 배운 건, "Task가 Running으로 표시된다"는 화면상의 상태를 그대로 믿으면 안 될 때도 있다는 점입니다. 실제 로그를 까봐야 진짜 상태를 알 수 있는 경우가 생각보다 많은 것 같습니다.
당장은 로그 정리로 급한 불을 껐지만, Cleanup Policy를 레포별로 분리하고 Task 스케줄을 잡아둔 덕분에 앞으로는 같은 문제가 자동으로 반복되지는 않을 것 같습니다. 다만 EBS 볼륨 자체를 늘리는 것도 함께 검토해야 근본적으로 안심할 수 있을 듯합니다.
'n년차 개발자' 카테고리의 다른 글
| AI 시대 개발자 공부법, IDE 없이 개발하는 사람들을 보며 든 생각 (0) | 2026.07.17 |
|---|---|
| GitLab Runner 오프라인, This job is stuck because you don't have any active runners online (0) | 2026.07.16 |
| 크롤링 트래픽을 어디까지 허용하고 어떻게 통제해야 할까? (0) | 2025.12.15 |
| 개인화 추천 API 성능 개선 (0) | 2025.11.27 |
| 서버 자원 수집 및 시각화 (0) | 2025.04.28 |
