Jenkins가 2주에 걸쳐 EFS 버스트 크레딧을 서서히 소진한 방법

발행: (2026년 1월 31일 오후 12:58 GMT+9)
9 min read
원문: Dev.to

Source: Dev.to

TL;DR

우리의 Jenkins가 1/26에 실패하기 시작했지만, 근본 원인은 1/13에 시작되었습니다. 우리는 세 가지 복합적인 문제를 발견했습니다:

  • Shared Library cache가 비활성화됨 (기존 문제)
  • disposable agents로 전환 (1/13 변경)
  • Increased build frequency (새해 효과)

Result: ≈ 50× 증가한 메타데이터 IOPS → EFS 버스트 크레딧이 2주 동안 소진됨.

Why You Should Care

Jenkins를 EFS에서 실행하고 있다면 이런 일이 발생할 수 있습니다. 증상은 갑자기 나타나지만, 근본 원인은 종종 몇 주 전부터 시작됩니다. 메트릭의 시계열 분석이 중요합니다.

미스터리: 증상 vs. 근본 원인

Previously, I wrote about how Jenkins became slow and Git clones started failing. We found ~15 GB of Git temporary files (tmp_pack_*) accumulated on EFS, causing metadata IOPS exhaustion.

We fixed it with Elastic Throughput and cleanup jobs. Case closed, right?

Not quite.

When I checked the EFS Burst Credit Balance graph, I noticed something important:

The credit started declining around 1/13, but symptoms appeared on 1/26.

Timeline

날짜이벤트
1/13크레딧 감소 시작
1/19급격한 감소
1/26크레딧 바닥 도달
1/26‑27증상 발생

The tmp_pack_* accumulation was a symptom, not the root cause. Something changed on 1/13.

1월 13일에 무엇이 바뀌었나요?

솔직히, 이게 저를 난감하게 만들었어요. 몇 가지 생각은 있었지만 확실한 것은 없었습니다:

1. 에이전트 아키텍처 변경

1월 13일경에 우리는 Jenkins 에이전트 전략을 변경했습니다:

이전 (공유 에이전트)이후 (일회용 에이전트)
EC2 유형: c5.large 등.EC2 유형: t3.small 등.
여러 작업이 에이전트를 공유작업당 하나의 에이전트, 사용 후 파기
작업 공간 재사용매번 전체 git clone 수행
증분 업데이트를 위한 git pull매번 전체 복제를 위한 git clone

목표는 비용 절감이었습니다. 메타데이터 IOPS 영향은 고려하지 않았습니다.

2. 연말연시 이후 개발 급증

팀들이 새해 연휴 이후 개발을 가속화하면서 전체 Jenkins 부하가 증가했습니다.

The Math: 50× Metadata IOPS Increase

Builds per day: 50 (estimated)
Files created per clone: 5,000

Shared‑agent approach:
  Clone once = 5,000 metadata operations

Disposable‑agent approach:
  50 builds × 5,000 files = 250,000 metadata operations/day

≈ 50× increase in metadata IOPS.
Add the New‑Year rush, and the numbers get even worse.

Source:

Jenkins에서 Git 캐시 이해

조사를 진행하던 중 다음 디렉터리를 발견했습니다:

/mnt/efs/jenkins/caches/git-3e9b32912840757a720f39230c221f0e

이는 Jenkins Git 플러그인의 베어‑레포지토리 캐시입니다.

Git 캐시 작동 방식

플러그인은 클론을 최적화하기 위해 다음을 수행합니다:

  1. 원격 레포지토리를 /mnt/efs/jenkins/caches/git-{hash}/에 베어 레포지토리 형태로 캐시합니다.
  2. 작업 공간으로 클론할 때 이 캐시를 git clone --reference 옵션으로 사용합니다.
  3. 해시는 레포지토리 URL + 브랜치를 기반으로 생성됩니다.

문제점: 일회성 에이전트는 매 빌드마다 새로 생성되므로 이 캐시의 혜택을 받지 못할 수 있습니다.

스모킹 건: tmp_pack_* 위치

I revisited where the tmp_pack_* files lived:

jobs/sample-job/jobs/sample-pipeline/builds/104/libs/
  └── 335abf.../root/.git/objects/pack/
      └── tmp_pack_WqmOyE  ← 100‑300 MB

These are in per‑build directories:

jobs/sample-job/jobs/sample-pipeline/
└── builds/
    ├── 104/
    │   └── libs/.../tmp_pack_WqmOyE
    ├── 105/
    │   └── libs/.../tmp_pack_XYZ123
    └── 106/
        └── libs/.../tmp_pack_ABC456

Every build was re‑checking out the Pipeline Shared Library, generating tmp_pack_* each time.

Question: Why is the Shared Library being fetched on every build?

근본 원인: 캐시 설정이 꺼짐

In Jenkins configuration I found the smoking gun:

공유 라이브러리 설정인 “컨트롤러에서 가져온 버전을 캐시하여 빠르게 검색” 옵션이 선택 해제되어 있었습니다.

Consequences:

  • 공유 라이브러리 캐시가 완전히 비활성화되었습니다.
  • 각 빌드마다 원격 저장소에서 전체를 가져옵니다.
  • .git/objects/pack/에 임시 파일이 생성됩니다.
  • 대규모 메타데이터 IOPS 사용량이 발생합니다.

The Fix: Enable Caching

  1. Enable “Cache fetched versions on controller for quick retrieval”.
  2. Set Refresh time in minutes to 180 minutes.

Choosing the Refresh Time

Refresh intervalEffect
60‑120 minFast updates, moderate IOPS reduction
180 min (3 h)Balanced – ~8 updates/day
360 min (6 h)Stable – ~4 updates/day
1440 min (24 h)Maximum IOPS reduction

Why 180 min?

  • Updates check ~8 times/day (9 am, 12 pm, 3 pm, 6 pm…).
  • Shared Library changes reflected within half a day is acceptable.
  • Significant IOPS reduction (once per 3 h instead of every build).
  • Urgent changes can be forced via the “force refresh” feature.

I documented this in our runbook so we don’t forget.

영향 측정

기간예상 관찰
단기 (24‑48 시간)tmp_pack_* 파일이 생성되지 않음; 메타데이터 IOPS 감소
중기 (1 주)버스트 크레딧 잔액 회복 추세; 빌드 성능 안정
장기 (1 개월)크레딧이 안정적으로 유지; 재발 없음

교훈

1. 증상 ≠ 근본 원인 타임라인

  • 증상 발생: 1/26‑1/27
  • 근본 원인: 약 1/13
  • 크레딧 고갈: 2주에 걸쳐 점진적

시계열 분석이 중요합니다. 눈에 보이는 증상만 고쳐도 피상적인 해결책에 그칩니다.

2. 아키텍처 변경에는 숨겨진 비용이 있다

일회용 에이전트 변경으로 EC2 비용은 줄었지만 다른 곳에 문제를 만들었습니다.

아키텍처를 변경할 때:

  • 사전에 성능 영향을 평가한다.
  • 적절한 모니터링을 설정한다.

3. EFS 메타데이터 IOPS 특성

  • 작은 파일을 대량으로 생성/삭제하는 것은 치명적이다.
  • 파일 개수가 저장 용량보다 더 중요하다.
  • 버스트 모드는 크레딧 관리를 필요로 한다.
  • 크레딧 고갈은 점진적으로 일어난다.

특히 .git/objects/에 수천 개의 작은 파일이 포함된 경우, 동작이 일반 파일 I/O와 크게 다릅니다.

4. 복합 근본 원인

이 문제는 단일 원인이 아니라 세 가지 요인이 결합된 것이었다:

  1. 공유 라이브러리 캐시 비활성화 (기존부터)
  2. 일회용 에이전트 전환 (1/13)
  3. 빌드 증가 (새해)

각각만으로는 큰 문제를 일으키지 않을 수 있지만, 함께 작용하면 임계값을 초과했다.

미해결 질문

공유 라이브러리 캐싱을 활성화했지만, 여전히 일회성 에이전트를 사용하고 있습니다.

일회성 에이전트에서도 에이전트 측 Git 캐시를 효과적으로 활용할 수 있을까요?

가능한 접근 방식:

  • 모든 에이전트에서 EFS Git 캐시 공유
  • 작업 간 재사용을 위해 에이전트 수명을 약간 연장
  • S3에 캐시를 저장하고 시작 시 동기화

비용과 성능 사이의 적절한 균형을 찾는 것이 여전히 과제입니다.


기술적 의사결정 및 엔지니어링 실천에 대해 제 블로그에서 더 많이 다루고 있습니다. 확인해 보세요.

Back to Blog

관련 글

더 보기 »

AI가 개발자를 대체할까요?

표지 이미지: AI가 개발자를 대체할까요? https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-up...