- Published on
Jenkins 빌드가 갑자기 느려질 때 원인 7가지
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서로 다른 팀(개발/인프라/보안)이 동시에 만지는 Jenkins는 “갑자기 느려짐”이 자주 발생합니다. 문제는 느려진 지점이 Jenkins 자체(컨트롤러/큐) 일 수도 있고, 에이전트 노드, Docker/쿠버네티스 런타임, 외부 네트워크(Git/Artifact/Registry), 스토리지(I/O), 플러그인/스크립트일 수도 있다는 점입니다.
이 글은 “원인 7가지”를 증상 → 확인 방법 → 즉시 조치 순으로 정리합니다. 가능하면 빌드 로그만 보고 추측하지 말고, 아래 커맨드로 병목을 수치로 잡는 것을 목표로 합니다.
> 전제: Pipeline/Declarative 기준 예시를 포함하며, 컨트롤러는 Jenkins, 실행 노드는 agent로 표기합니다.
1) 에이전트 노드 CPU/메모리 스로틀링(특히 컨테이너)
증상
- 같은 커밋인데 단계별 시간이 전반적으로 늘어남(컴파일/테스트/압축 등 CPU 작업이 모두 느림)
docker build/npm ci/mvn test가 전체적으로 “느리고 고르게” 늘어남- Kubernetes 에이전트라면 Pod가 제한된 CPU quota로 스로틀링
확인 방법
- 리눅스 에이전트에서 즉시 확인:
# CPU/메모리/Load
uptime
free -h
vmstat 1 5
# 컨테이너 환경이면 cgroup 제한 확인(일부 배포판 경로 상이)
cat /sys/fs/cgroup/cpu.max 2>/dev/null || true
cat /sys/fs/cgroup/memory.max 2>/dev/null || true
- Kubernetes라면:
kubectl top pod -n jenkins
kubectl describe pod <agent-pod> -n jenkins | sed -n '/Limits:/,/Requests:/p'
즉시 조치
- 에이전트 리소스 requests/limits 상향 또는 동시 실행 수 감소
- JVM 기반 빌드(Gradle/Maven)라면
-Xmx가 너무 커서 OOM/스왑 유발하지 않는지 점검
2) 디스크 I/O 병목(워크스페이스/도커 레이어/캐시 디렉터리)
증상
checkout이후부터 갑자기 느려짐(특히 테스트 리포트/아티팩트 생성 단계)tar,zip,npm ci,pip install,gradle캐시가 느려짐- 로그에 특별한 에러 없이 “그냥 오래 걸림”
확인 방법
- 에이전트에서 디스크 사용량/IO wait 확인:
# 디스크 용량
df -h
# IO wait/디스크 병목
iostat -xz 1 5 2>/dev/null || true
# 상위 디렉터리 사용량(워크스페이스/캐시)
du -h -d 1 $WORKSPACE | sort -h | tail -n 20
- Docker 사용 시 레이어/빌드캐시가 비대해졌는지:
docker system df
즉시 조치
- 워크스페이스 정리(단, 무조건 삭제는 금물: 캐시까지 날리면 더 느려질 수 있음)
- 캐시 디렉터리(
~/.m2,~/.gradle,~/.npm)를 별도 빠른 볼륨으로 분리 - 도커 빌드가 많다면 BuildKit 캐시/registry cache 도입 검토
3) Git Checkout/Fetch가 느려짐(네트워크·서버·레포 크기)
증상
checkout scm단계만 유독 느려짐- shallow clone을 쓰다가 어느 순간 full fetch로 바뀜(브랜치 전략/플러그인 설정 변경)
- Git 서버(사내 GitLab/GHE) 부하 또는 네트워크 경로 문제
확인 방법
- Jenkins Git 플러그인 로그에서 fetch 옵션 확인(깊이, refspec)
- 에이전트에서 Git 네트워크/인증 왕복 확인:
# DNS/네트워크 기본 지표
getent hosts github.com || true
curl -I -L https://github.com 2>/dev/null | head
# Git 전송시간이 긴지 확인(진단용)
GIT_CURL_VERBOSE=1 GIT_TRACE=1 git ls-remote <repo-url> 2>&1 | tail -n 50
즉시 조치
CloneOption으로 shallow depth, no-tags, reference repo(미러) 적용- 레포가 너무 커졌다면 LFS/아티팩트 분리 검토
- Kubernetes/EKS 환경에서 DNS가 느리면 Git/Artifact 모두 느려지는 연쇄가 생깁니다. Pod DNS만 느린 케이스는 아래 글의
ndots/search튜닝이 힌트가 됩니다: EKS에서 Pod DNS만 느릴 때 ndots·search 튜닝
4) Docker/컨테이너 권한·스토리지 드라이버 이슈로 “재시도/대기” 증가
증상
docker build,docker login,docker run에서 간헐적으로 멈춘 듯 느려짐- 퍼미션 문제로 내부적으로 재시도/폴백이 발생하거나, 볼륨 마운트가 느림
- overlay2 스토리지 드라이버/디스크 부족으로 성능 급락
확인 방법
# Docker 데몬 상태와 오류
systemctl status docker --no-pager || true
journalctl -u docker -n 200 --no-pager || true
# 스토리지 드라이버/루트 디렉터리 확인
docker info | sed -n '/Storage Driver/,+10p'
즉시 조치
- 에이전트가 Docker socket을 쓰는 구조라면 권한/그룹 문제부터 정리(빌드가 느려질 뿐 아니라 실패로도 이어짐)
- 관련해서 Docker 에이전트 권한 이슈 체크리스트는 아래 글이 빠릅니다: Jenkins Docker 에이전트 Permission denied 7가지 해결
- 디스크가 임계치에 가까우면 overlay2 성능이 급락할 수 있으니
docker system prune는 신중히(공유 캐시 환경에서는 역효과)
5) 외부 의존성(레지스트리/패키지 저장소/아티팩트) 지연
증상
npm ci,pip install,go mod download,mvn dependency:resolve가 갑자기 느림- 도커 이미지 pull이 느리거나
ImagePullBackOff가 간헐적으로 발생 - 사내 Nexus/Artifactory/Harbor가 느려짐 또는 egress 경로(NAT) 병목
확인 방법
- 다운로드 구간을 타임스탬프로 쪼개서 확인(파이프라인에서 측정):
pipeline {
agent any
stages {
stage('Deps') {
steps {
sh '''
set -e
date
time npm ci
date
'''
}
}
}
}
- Kubernetes라면 이미지 pull rate limit/429 여부 확인. 특히 퍼블릭 레지스트리 의존이 크면 빈번합니다: EKS ImagePullBackOff 429 Too Many Requests 해결
즉시 조치
- 사내 프록시/캐시 레지스트리(예: Harbor proxy cache, Nexus Docker proxy) 도입
- 패키지 매니저 캐시를 워크스페이스와 분리하고, 에이전트 재사용 전략(고정 노드/캐시 볼륨) 적용
- NAT Gateway를 통한 egress가 병목이면 비용뿐 아니라 성능도 흔들립니다. 트래픽 급증 진단이 필요할 때: VPC NAT Gateway 비용 폭증 10분 진단·절감
6) Jenkins 컨트롤러/큐 병목(Executor, Throttle, Lock, SCM Polling)
증상
- 빌드 자체는 짧은데 “대기 시간”이 길어짐(Queue에서 오래 머뭄)
- 특정 라벨의 에이전트만 항상 밀림
lock()/throttle/milestone/input같은 제어 스텝으로 직렬화
확인 방법
- Jenkins UI에서
Build Queue,Manage Jenkins → System Information확인 - Pipeline에서 큐 대기/실행 시간을 로그로 남기기(간단한 방법):
pipeline {
agent { label 'linux' }
options {
timestamps()
}
stages {
stage('Info') {
steps {
echo "NODE_NAME=${env.NODE_NAME} EXECUTOR_NUMBER=${env.EXECUTOR_NUMBER}"
}
}
}
}
- 특정 자원 잠금으로 느려지는지 Jenkinsfile 검색:
grep -R "lock(\|throttle\|milestone\|disableConcurrentBuilds" -n Jenkinsfile
즉시 조치
- 라벨별 에이전트 풀을 확장하거나 executor 수 조정(컨트롤러 executor는 보통 0 권장)
disableConcurrentBuilds()가 불필요하게 전체 파이프라인을 직렬화하고 있지 않은지 재검토lock(resource: 'docker-daemon')처럼 “큰 락”을 잡고 있으면 세분화
7) 플러그인/스크립트 변경으로 인한 성능 저하(특히 단계별 post/notify)
증상
- 빌드 본 작업은 끝났는데
post { always { ... } }에서 오래 걸림 - Slack/Jira/GitHub status update 같은 외부 호출이 느려짐
- 최근 Jenkins/플러그인 업데이트 이후부터 체감
확인 방법
- 빌드 로그에서 느린 구간이 항상 같은 스텝인지 확인
- Scripted step에서 네트워크 호출 타임아웃/재시도 여부 점검
- Jenkins 컨트롤러 로그에서 플러그인 예외/GC 증가 확인
# (컨트롤러 노드에서) 최근 로그 확인 경로는 설치 방식에 따라 다름
# systemd 기반이면:
journalctl -u jenkins -n 300 --no-pager || true
즉시 조치
- 외부 API 호출은 타임아웃을 명시하고, 실패 시 빌드 전체를 막지 않도록 격리
- 플러그인 업데이트는 한 번에 몰아서 하지 말고, 느려짐이 시작된 시점의 변경 이력을 역추적
- 알림/리포팅은 가능하면 비동기(별도 job)로 분리
빠르게 결론 내는 10분 진단 루틴
아래 순서로 보면 “감”이 아니라 “근거”로 원인을 좁힐 수 있습니다.
- Queue 대기인가, 실행이 느린가부터 분리(Jenkins UI/타임스탬프)
- 실행이 느리면 에이전트에서 CPU/메모리/IO wait 확인(
vmstat,iostat) - 느린 단계가
checkout/deps download면 DNS/네트워크/레지스트리 확인 - Docker 사용 시
docker info,docker system df, 데몬 로그 확인 - 최근 변경(플러그인/에이전트 이미지/네트워크 정책/보안 정책)을 타임라인으로 정리
부록: 단계별 시간을 자동으로 남기는 Jenkinsfile 예시
“갑자기 느려짐”을 반복해서 겪는다면, 최소한 단계별 소요시간을 표준화해 두는 게 좋습니다.
pipeline {
agent any
options {
timestamps()
timeout(time: 60, unit: 'MINUTES')
}
stages {
stage('Checkout') {
steps {
sh 'date; echo "== checkout start =="'
checkout scm
sh 'date; echo "== checkout end =="'
}
}
stage('Build') {
steps {
sh '''
set -e
date; echo "== build start =="
time make build
date; echo "== build end =="
'''
}
}
stage('Test') {
steps {
sh '''
set -e
date; echo "== test start =="
time make test
date; echo "== test end =="
'''
}
}
}
post {
always {
sh 'date; echo "== post always =="'
}
}
}
이 정도만 해도 “Checkout이 3배 느려짐”, “Deps download가 10배 느려짐”, “post 구간에서 5분 대기”처럼 병목이 선명해집니다. 그 다음부터는 위 7가지 원인 중 어디에 속하는지 매칭해서, 리소스/네트워크/캐시/플러그인/동시성 중 정확한 축으로 해결하면 됩니다.