13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] Jenkinsfile

  • [Cloud] Jenkins 장애 해결: CI/CD 파이프라인 디버깅 방법론

    [Cloud] Jenkins 장애 해결: CI/CD 파이프라인 디버깅 방법론

    Jenkins 장애 해결: CI/CD 파이프라인 장애 발생 시 디버깅 방법론

    Jenkins 장애 해결이 급한 순간은 늘 비슷하더라고요. 배포 직전인데 파이프라인이 멈추고, 로그는 길고, 팀 채팅방은 조용히 뜨거워집니다. 지속적 통합 환경에서는 작은 설정 하나가 전체 흐름을 막는 경우가 많거든요. 그래서 이번 글에서는 Jenkins CI/CD 파이프라인 장애가 났을 때 어디부터 보고, 무엇으로 판단할지 실무 순서대로 정리해보겠습니다.

    처음엔 저도 젠킨스 에러가 뜨면 Jenkins 자체 문제부터 의심했는데요. 실제로는 소스 저장소 인증, 에이전트 연결, 워크스페이스, 셸 환경 변수처럼 경계 지점에서 막히는 일이 훨씬 많았습니다. 중요한 포인트는 하나입니다. 증상만 보지 말고 실행 경로를 층별로 나눠서 확인해야 합니다.

    Jenkins 장애 해결을 위한 CI/CD 전체 아키텍처 다이어그램

    Jenkins 컨트롤러, 에이전트, Git 저장소, 빌드 도구, 배포 대상 시스템 사이의 장애 지점을 한눈에 보여주는 개요 이미지입니다.

    Jenkins 장애 해결은 왜 순서가 중요할까

    쉽게 말해 Jenkins는 혼자 일하지 않습니다. 컨트롤러가 잡(Job)을 받고, 에이전트가 실제 명령을 수행하고, Git 같은 외부 시스템에서 코드를 가져오고, Docker나 Maven, Gradle 같은 도구를 호출합니다. 여기서 하나라도 어긋나면 파이프라인 문제 해결이 꼬이기 시작하죠.

    실무에서 자주 보는 장애 구간은 대략 이렇습니다.

    • 시작도 못 하는 장애: 큐에만 쌓이고 실행되지 않음
    • 초반 실패: SCM checkout 실패, credential 문제, webhook 미동작
    • 중간 실패: 테스트, 빌드, 이미지 생성, 스크립트 문법 에러
    • 후반 실패: 아티팩트 업로드, 배포 권한, 대상 서버 연결 불가
    • 간헐 장애: 같은 커밋인데 어떤 때는 되고 어떤 때는 안 됨

    결국 Jenkins 장애 해결은 Jenkins 자체보다 연결된 구성 요소의 경계면을 보는 작업에 가깝습니다. 저도 예전엔 콘솔 출력만 붙잡고 오래 헤맨 적이 있었는데, 구조를 나눠서 보니까 훨씬 빨리 풀리더라고요.

    CI/CD 디버깅 기본 원칙: 한 번에 하나씩 잘라 보기

    팀에서 자주 맞추는 기준이 있습니다. 재현 가능한 최소 실패 지점(minimal failing step)을 먼저 만들자는 거예요. 로그가 2천 줄이어도 결국 실패는 한 단계에서 시작되거든요.

    1. 최근 변경이 어디인지 확인합니다. Jenkinsfile, credential, agent image, plugin, target server 중 무엇이 바뀌었는지 먼저 봅니다.
    2. 실패 지점을 단계 단위로 자릅니다. checkout, build, test, publish, deploy 순서로 어디서 처음 깨지는지 확인합니다.
    3. 컨트롤러와 에이전트를 분리해서 봅니다. UI에서 보이는 에러와 실제 실행 노드의 시스템 로그는 다를 수 있습니다.
    4. 같은 명령을 에이전트 셸에서 직접 실행합니다. Jenkins만 실패하는지, OS 레벨에서도 실패하는지 비교합니다.
    5. 마지막 성공 이력과 비교합니다. 같은 브랜치의 이전 성공 빌드가 가장 좋은 기준선입니다.

    여기서 중요한 포인트는 왜 안 되지?보다 어디까지는 됐지?라고 묻는 습관입니다. 이거 진짜 편하더라고요.

    Jenkins 장애 해결 1차 점검: 서비스 상태와 기본 로그

    Jenkins 장애 해결에서 제일 먼저 할 일은 화려한 분석이 아닙니다. 서비스가 살아 있는지, 최근 로그에 뻔한 실패가 있는지부터 확인해야 합니다. 의외로 Java 프로세스 메모리 문제, 디스크 공간 부족, 권한 문제 같은 기본기가 원인인 경우가 많거든요.

    1. systemd 서비스 상태 확인

    sudo systemctl status jenkins
    sudo journalctl -u jenkins -n 200 --no-pager
    sudo journalctl -u jenkins -f

    Linux 패키지 설치 환경에서는 Jenkins 공식 문서 기준으로 journalctl -u jenkins가 기본 로그 확인 방법입니다. 여기서 볼 건 단순합니다. 프로세스가 반복 재시작하는지, 플러그인 로딩 실패가 있는지, 포트 바인딩 실패, Permission denied 같은 메시지가 있는지 먼저 보세요. 마지막 한 줄만 보지 말고, 실패 직전 수십 줄을 같이 보는 게 훨씬 정확합니다.

    2. Jenkins 홈 디렉터리와 디스크 확인

    sudo du -sh /var/lib/jenkins
    sudo df -h
    sudo ls -ld /var/lib/jenkins

    일반적인 Linux 패키지 설치에서는 /var/lib/jenkins가 자주 쓰이는 Jenkins 홈 디렉터리입니다. 다만 로그 파일 경로는 설치 방식에 따라 다를 수 있어서, Linux에서는 먼저 journalctl을 우선으로 보는 편이 안전합니다. 디스크가 꽉 차면 빌드 중단, 워크스페이스 정리 실패, 플러그인 캐시 이상처럼 애매한 증상으로 보일 때가 많습니다.

    3. 웹 응답과 큐 상태 확인

    curl -I http://127.0.0.1:8080/login
    curl -s http://127.0.0.1:8080/queue/api/json
    curl -s http://127.0.0.1:8080/computer/api/json

    /queue/api/json은 작업이 왜 대기 중인지 볼 때 유용합니다. 대기 사유를 설명하는 값이 내려오는 경우가 있어서, 적절한 라벨의 에이전트가 없거나 모든 실행기(executor)가 점유된 상황을 빨리 찾을 수 있죠. /computer/api/json도 에이전트 상태를 한 번에 점검할 때 꽤 편합니다.

    Jenkins 장애 해결을 위한 서비스 상태 및 로그 점검 이미지

    systemctl, journalctl, Jenkins 로그를 보며 서비스 상태와 에러 메시지를 추적하는 터미널 중심의 점검 장면입니다.

    파이프라인 문제 해결의 핵심: 콘솔 로그를 단계별로 읽는 법

    콘솔 로그는 다들 보지만, 읽는 순서가 제각각인 경우가 많습니다. 저는 아래 순서대로 봅니다.

    1. 첫 실패 지점을 찾습니다. 마지막 실패가 아니라 첫 실패입니다.
    2. 실행한 실제 명령을 찾습니다. Jenkins가 감싼 메시지 말고 sh, bat, git, docker 같은 실제 명령을 봅니다.
    3. 반환 코드(exit code)를 확인합니다. 같은 문구라도 종료 코드가 다르면 해석이 달라집니다.
    4. 환경 변수와 작업 디렉터리를 의심합니다. Jenkins 안에서만 실패하면 경로, 사용자, 셸 차이일 가능성이 큽니다.

    예를 들어 이런 Declarative Pipeline 조각이 있다고 해보겠습니다.

    pipeline {
      agent any
      stages {
        stage('Checkout') {
          steps {
            checkout scm
          }
        }
        stage('Build') {
          steps {
            sh 'pwd'
            sh 'printenv | sort'
            sh './gradlew clean build'
          }
        }
      }
      post {
        always {
          archiveArtifacts artifacts: 'build/reports/**', allowEmptyArchive: true
        }
      }
    }

    여기서 pwd와 printenv | sort를 자주 넣는 이유가 있습니다. 처음엔 투박해 보여도, 로컬에서는 되는데 Jenkins에서만 실패하는 문제를 잡아낼 때 꽤 강력하거든요. 특히 PATH, HOME, WORKSPACE 차이를 확인할 때 도움이 큽니다.

    또 하나 중요한 점은 SCM checkout 실패와 빌드 도구 실패를 섞어서 보지 않는 겁니다. checkout scm 이전에 실패하면 Git 접근, credential, 네트워크 문제일 가능성이 높고, 그 이후에 실패하면 빌드 스크립트나 런타임 문제로 좁혀집니다.

    CI/CD 디버깅 실전: 에이전트와 셸 환경 검증

    실전에서 정말 자주 만나는 케이스가 하나 있습니다. 파이프라인에서는 docker: command not found가 뜨는데, 운영자는 분명 에이전트에 Docker를 설치했다고 말하는 상황이죠. 저도 이런 경우를 여러 번 봤는데, 알고 보면 Jenkins가 실행되는 사용자와 사람이 SSH로 접속했을 때의 사용자 환경이 다른 경우가 많았습니다.

    이럴 때는 Jenkinsfile 안에서 추측만 하지 말고, 에이전트 셸에서 같은 사용자 맥락을 확인하는 게 빠릅니다.

    whoami
    id
    pwd
    echo "$PATH"
    command -v git
    command -v docker
    command -v java
    ls -la

    판단 기준은 이렇습니다.

    • command -v docker가 비어 있으면 PATH 또는 설치 경로 문제를 먼저 봅니다.
    • whoami 결과가 예상과 다르면 서비스 계정이 다를 수 있습니다.
    • 현재 디렉터리가 워크스페이스인지 확인합니다. 상대 경로 스크립트는 여기서 자주 깨집니다.
    • SSH 로그인 셸에서는 되는데 Jenkins에서 안 되면 .bashrc, .profile 같은 로그인 셸 초기화에 의존했을 가능성이 큽니다.

    에이전트가 컨테이너 기반이라면 한 번 더 들어가야 합니다. 이미지 자체에 도구가 빠졌거나, 엔트리포인트가 달라 환경 초기화가 예상과 다를 수 있거든요. 이런 경우는 Jenkins 문제라기보다 실행 런타임 문제에 더 가깝습니다.

    Jenkins 장애 해결 중 에이전트 환경 변수와 PATH 분석 다이어그램

    컨트롤러와 에이전트 사이에서 사용자 계정, PATH, 워크스페이스, 컨테이너 런타임 차이를 추적하는 장면을 설명하는 이미지입니다.

    자주 만나는 젠킨스 에러와 첫 대응 기준

    Jenkins 장애 해결에서 시간을 아끼려면, 증상별 첫 대응을 미리 정해두는 게 좋습니다. 아래 표는 현장에서 자주 쓰는 분류입니다.

    증상 의심 구간 먼저 볼 것 초기 대응
    빌드가 큐에서 안 나감 에이전트/라벨/실행기 /queue/api/json, /computer/api/json label 매칭, offline agent, executor 점유 상태 확인
    SCM checkout 실패 Git 접근/credential/네트워크 콘솔 로그의 git 명령, credential ID, known_hosts 토큰 권한, SSH 키, 저장소 URL, DNS 확인
    script returned exit code 1 빌드 스크립트 자체 실패한 실제 셸 명령 에이전트 셸에서 동일 명령 재실행
    Permission denied 파일 퍼미션/실행 권한 whoami, ls -l, mount 옵션 실행 비트, 소유권, workspace 권한 확인
    No space left on device 디스크/캐시/로그 df -h, du -sh, build history 불필요한 워크스페이스와 오래된 아티팩트 정리
    Agent disconnected 노드 연결/SSH 또는 inbound agent agent 로그, controller 로그 네트워크 단절, Java 실행 환경, 인증 정보 재확인
    HTTP 403/401 토큰/권한/CSRF API 호출 방식, crumb 필요 여부 인증 토큰, 권한 매트릭스, 요청 헤더 검토

    핵심은 숫자를 외우는 게 아니라 증상과 레이어를 연결하는 감각입니다. 예를 들어 Permission denied가 보여도 Jenkins 권한 모델 문제일 수 있고, 리눅스 파일 퍼미션 문제일 수도 있습니다. 문맥을 같이 봐야 헛수고를 줄일 수 있습니다.

    실제 삽질 포인트: 플러그인, 워크스페이스, 그리고 숨은 상태값

    이 섹션은 현장에서 자주 걸리는 포인트를 모은 겁니다. Jenkins는 눈에 보이는 설정 외에도 상태값 때문에 사람을 헷갈리게 할 때가 있더라고요.

    1. 플러그인 업데이트 직후 파이프라인 이상 동작

    플러그인 업데이트 후 특정 단계만 갑자기 깨질 수 있습니다. 특히 Pipeline, Git, Credentials 관련 플러그인이 바뀌면 증상이 미묘합니다. 로그를 보면 클래스 로딩 문제나 메서드 시그니처 불일치처럼 드러나는 경우가 있어서, 업데이트 직전 시점을 기준선으로 잡는 게 중요합니다.

    2. 워크스페이스 오염

    같은 잡이 브랜치나 조건에 따라 다른 파일을 남겨두면 간헐 장애가 납니다. 특히 생성 파일이 다음 빌드에 영향을 주는 프로젝트에서 자주 보이죠. 이런 때는 Jenkins의 cleanWs()나 Workspace Cleanup 플러그인처럼 범위가 명확한 정리 방식을 우선 권장합니다.

    post {
      always {
        cleanWs()
      }
    }

    셸에서 직접 삭제가 꼭 필요하다면 현재 디렉터리와 변수 값을 먼저 출력한 뒤, 삭제 범위를 다시 확인하세요. 이 단계에서 서두르면 더 큰 사고로 이어지기 쉽습니다.

    3. 숨은 환경 변수 차이

    로컬 셸에서는 프록시, 인증서, locale, JAVA_HOME이 잡혀 있는데 Jenkins에서는 빠져 있는 경우가 있습니다. 이건 CI/CD 디버깅에서 정말 흔합니다. 랜덤 장애처럼 보여도 사실은 환경 차이인 경우가 많습니다.

    4. 타임아웃과 외부 의존성

    테스트가 멈춘 것처럼 보여도 실제로는 외부 API 응답 대기일 수 있습니다. 이럴 땐 Jenkins 화면만 보지 말고 애플리케이션 로그, 대상 시스템 로그, 네트워크 경로, DNS, 프록시 유무까지 같이 봐야 합니다. Jenkins는 멈춘 원인이라기보다 멈춘 결과가 보이는 관측 지점일 때가 많거든요.

    검증 단계: 장애가 풀렸는지 어떻게 확인할까

    장애 복구 후에 초록불만 보고 끝내면 다음 주에 같은 문제를 다시 만날 수 있습니다. 그래서 검증은 세 가지로 나눠 보는 편이 좋습니다.

    1. 같은 커밋 재실행: 같은 입력에서 재현이 사라졌는지 봅니다.
    2. 바로 이전 성공 경로 비교: stage 흐름과 로그 패턴이 정상 범위인지 확인합니다.
    3. 외부 연동까지 확인: artifact, image, deploy, webhook, notification이 끝까지 이어지는지 봅니다.

    예를 들어 빌드는 성공했는데 아티팩트 보관이 비어 있으면, 저는 완전한 성공으로 보지 않습니다. 배포 단계가 생략됐는데 파이프라인만 녹색이어도 마찬가지예요. 무엇이 성공인지를 stage 단위로 정의해두면 재발 방지에도 도움이 됩니다.

    Jenkins UI로 확인해도 되지만, API로 확인하는 습관도 좋습니다.

    curl -s http://127.0.0.1:8080/job/my-pipeline/lastBuild/api/json
    curl -s http://127.0.0.1:8080/job/my-pipeline/lastSuccessfulBuild/api/json

    여기서는 result, number, building 같은 기본 상태와 함께, 단계 흐름과 산출물이 기대한 대로 나왔는지 같이 보세요. 숫자보다 성공 상태의 구조적 일관성을 확인하는 게 더 중요합니다.

    Jenkins 장애 해결 결과를 검증하는 빌드 대시보드 이미지

    성공과 실패가 섞인 스테이지 뷰, 빌드 이력, 아티팩트 보관 여부를 비교해 검증하는 결과 화면 이미지입니다.

    운영하면서 효과 있었던 예방책

    장애를 줄이려면 사후 대응만큼 예방도 중요합니다. 실제로 운영하면서 체감이 컸던 건 아래 네 가지였습니다.

    • Jenkinsfile에 진단용 출력 최소 세트를 넣어둡니다. pwd, whoami, printenv | sort 같은 기본 정보가 생각보다 자주 문제를 풀어줍니다.
    • 에이전트 이미지를 표준화합니다. 팀마다 다른 도구 버전과 PATH 구성은 결국 장애 원인이 됩니다.
    • 워크스페이스 정리 정책을 둡니다. 오래된 빌드와 캐시가 간헐 장애를 만듭니다.
    • 변경 이력 분리가 중요합니다. Jenkinsfile 변경, credential 변경, plugin 변경을 한 번에 몰아서 하지 않는 편이 좋습니다.

    이전 글에서 다룬 로그 읽기나 리눅스 디스크 점검 방법과 함께 보면 더 도움이 됩니다. 관련 운영 글도 내부 링크로 묶어두면 검색 유입과 체류 시간 둘 다 챙기기 좋습니다.

    FAQ: Jenkins 장애 해결에서 자주 받는 질문

    Q1. Jenkins UI에 에러가 너무 짧게 보일 때는요?

    컨트롤러 로그와 에이전트 로그를 분리해서 보시면 됩니다. UI는 요약일 뿐이라 실제 원인은 시스템 로그에 남는 경우가 많습니다.

    Q2. 파이프라인이 가끔만 실패하면 어디부터 봐야 하나요?

    간헐 실패는 외부 의존성, 워크스페이스 오염, 동시성, 네트워크 지연을 먼저 의심합니다. 같은 커밋 재실행과 깨끗한 워크스페이스 실행을 비교해보면 방향이 꽤 빨리 잡힙니다.

    Q3. Jenkins 장애 해결에서 가장 먼저 버려야 할 습관은 뭔가요?

    마지막 에러 한 줄만 보고 원인을 단정하는 습관입니다. 항상 첫 실패 지점을 찾는 쪽이 훨씬 정확합니다.

    Jenkins 장애 해결 유형별 대응 요약 인포그래픽

    증상별 원인 구간, 확인 명령어, 권장 대응 순서를 한 장으로 정리한 요약 이미지입니다.

    현장에서 바로 쓰는 Jenkins 장애 해결 방식

    배포가 급한 상황이라면 먼저 서비스 상태 확인 → 콘솔 로그 첫 실패 지점 확인 → 에이전트 셸에서 동일 명령 재실행, 이 세 단계부터 밟아보세요. 대부분 여기서 방향이 나옵니다. 복잡한 추측보다 이 순서가 훨씬 빠릅니다.

    반대로 같은 장애가 반복된다면 접근을 바꿔야 합니다. 에이전트 표준화, 워크스페이스 정리, Jenkinsfile 진단 출력 추가, 변경 이력 분리 쪽으로 가야 재발 방지 효과가 큽니다.

    결국 Jenkins 장애 해결은 화려한 비법보다 관찰 순서가 더 중요합니다. 젠킨스 에러를 보면 당황하기 쉽지만, 컨트롤러, 에이전트, 외부 연동, 실행 명령을 층으로 나눠 보면 생각보다 빨리 풀리더라고요. 파이프라인 문제 해결이 막막할 때는 오늘 적은 체크 순서대로 한 번 따라가 보세요.

  • [Cloud] Jenkins on Kubernetes 마이그레이션: 클라우드 네이티브 CI/CD 전환 사례

    [Cloud] Jenkins on Kubernetes 마이그레이션: 클라우드 네이티브 CI/CD 전환 사례

    안녕하세요, 13년차의 서버실 운영자입니다. 오늘은 많은 분들이 고민하고 계실 법한 주제, 바로 Jenkins on Kubernetes 마이그레이션 경험담을 풀어보려고 합니다. 사실 저도 기존 Jenkins 환경을 운영하면서 여러 가지 페인 포인트(Pain Point)를 겪었거든요. 빌드가 몰리면 서버 리소스가 부족하고, 특정 에이전트(Agent)에 문제가 생기면 전체 파이프라인이 멈추고… 이런 경험, 혹시 여러분도 있으신가요?

    클라우드 네이티브(Cloud-Native) 환경으로의 전환은 이제 선택이 아닌 필수가 되어가고 있습니다. CI/CD(Continuous Integration/Continuous Deployment, 지속적 통합/지속적 배포) 파이프라인의 핵심인 Jenkins 역시 예외는 아니죠. 기존 VM 기반의 Jenkins를 Kubernetes(쿠버네티스) 위로 옮기면서 얻게 된 이점과, 그 과정에서 겪었던 삽질 경험을 솔직하게 공유해 드릴게요. 이 글이 여러분의 Jenkins Kubernetes 마이그레이션 여정에 멘토 같은 역할을 해주었으면 좋겠습니다.

    Jenkins on Kubernetes 클라우드 네이티브 CI/CD 아키텍처 다이어그램

    Jenkins on Kubernetes 아키텍처는 효율적인 CI/CD 파이프라인을 위한 핵심입니다. 동적 에이전트가 필요할 때마다 생성되어 리소스를 최적화합니다.

    Jenkins on Kubernetes, 왜 필요할까요?

    기존 Jenkins는 보통 고정된 마스터(Master)와 여러 개의 에이전트(Agent) 서버로 구성됩니다. 작업이 많아지면 에이전트 서버를 증설해야 하고, 사용하지 않을 때도 리소스를 계속 점유하죠. 특정 에이전트에 문제가 생기면 해당 에이전트에서 동작하는 모든 작업이 실패할 수 있으니 정말 골치 아픈 거거든요.

    하지만 Jenkins on Kubernetes 환경은 다릅니다. 쉽게 말해, 필요한 순간에만 에이전트(Agent)를 띄워서 작업을 처리하고, 끝나면 바로 없애는 방식입니다. Jenkins 마스터는 Kubernetes 클러스터 내의 컨트롤러(Controller)로 동작하고, CI/CD 파이프라인 작업이 필요할 때마다 Kubernetes Pod(파드) 형태로 에이전트를 동적으로 생성합니다. 작업이 완료되면 해당 Pod는 자동으로 소멸됩니다. 이게 바로 클라우드 네이티브 CI/CD의 핵심 장점 중 하나예요.

    ✅ 주요 장점

    • 탄력적인 확장성 (Elastic Scalability): 빌드 요청이 폭증해도 Kubernetes가 알아서 에이전트 Pod를 늘려줍니다.
    • 리소스 효율성 (Resource Efficiency): 작업이 없을 때는 에이전트 Pod가 존재하지 않으므로 불필요한 리소스 낭비가 없습니다.
    • 고가용성 (High Availability): Kubernetes의 자체 복구(Self-healing) 기능 덕분에 에이전트 Pod에 문제가 생겨도 다른 Pod로 대체되어 안정성이 높아집니다.
    • 선언적 구성 (Declarative Configuration): Jenkinsfile(젠킨스파일)과 JCasC(Jenkins Configuration as Code)를 통해 CI/CD 파이프라인과 Jenkins 자체 구성을 코드로 관리할 수 있습니다.

    Jenkins Kubernetes 마이그레이션, 실전 구현 단계

    자, 그럼 이제 제가 실제로 어떻게 Jenkins 현대화를 진행했는지 단계별로 알려드릴게요. 처음엔 어디서부터 손대야 할지 막막했는데, 하나씩 해나가다 보니 길이 보이더라고요.

    1. Kubernetes 클러스터 준비

    가장 먼저 할 일은 Jenkins를 올릴 Kubernetes 클러스터를 준비하는 겁니다. 클라우드 환경에서는 AWS EKS(Elastic Kubernetes Service), Azure AKS(Azure Kubernetes Service), Google GKE(Google Kubernetes Engine) 같은 관리형 서비스를 이용하는 게 편합니다. 저는 홈랩에서 K3s 클러스터를 운영하고 있어서 그걸 활용했어요. 온프레미스(On-premise) 환경이라면 kubeadm이나 OpenShift 등을 고려할 수 있겠죠.

    2. Helm을 이용한 Jenkins 설치

    Kubernetes에 애플리케이션을 배포하는 가장 일반적인 방법 중 하나가 Helm(헬름) 차트입니다. Jenkins도 공식 Helm 차트를 제공하고 있어서 쉽게 설치할 수 있어요. 물론, 설치 전에 PersistentVolume(영구 볼륨)과 PersistentVolumeClaim(영구 볼륨 클레임)을 설정해서 Jenkins 설정과 데이터를 보존할 수 있도록 해야 합니다. 이 부분이 제일 중요해요. 데이터 날리면 대형사고잖아요?

    # Helm 리포지토리 추가
    helm repo add jenkins https://charts.jenkins.io
    helm repo update
    
    # values.yaml 파일 커스터마이징 (예시)
    # persistentVolume 셋팅, resource limit, ingress 설정 등
    # 자세한 내용은 공식 Helm 차트 문서를 참고하세요!
    
    # Jenkins 설치
    helm install jenkins -f my-jenkins-values.yaml jenkins/jenkins -n jenkins --create-namespace
    

    위 명령어는 기본적인 설치 예시입니다. 실제 운영 환경에서는 `my-jenkins-values.yaml` 파일에 Ingress(인그레스, 외부 트래픽 진입점), 리소스 제한(Resource Limits), 플러그인 설정 등을 상세하게 정의해야 해요. 이 파일 하나로 Jenkins의 거의 모든 설정을 제어할 수 있거든요.

    Jenkins Helm values.yaml 설정 파일 예시

    Helm `values.yaml` 파일은 Jenkins 배포의 핵심입니다. 여기서 영구 스토리지, 리소스, 에이전트 설정을 세밀하게 제어할 수 있습니다.

    3. Kubernetes Cloud Plugin 설정

    Jenkins 마스터가 Kubernetes 클러스터와 통신하며 동적 에이전트를 생성하려면 Kubernetes Cloud Plugin(쿠버네티스 클라우드 플러그인)을 설치하고 설정해야 합니다. Jenkins UI에서 ‘Jenkins 관리’ → ‘시스템 설정’ → ‘클라우드’ 섹션으로 이동해서 Kubernetes 클러스터 정보를 입력합니다. 이때 Service Account(서비스 어카운트)와 RBAC(Role-Based Access Control) 설정을 통해 Jenkins가 Kubernetes API에 접근할 수 있도록 권한을 부여하는 것이 매우 중요합니다.

    여기서 Pod Template(파드 템플릿)을 정의하게 되는데, 이 템플릿이 바로 동적 에이전트 Pod의 설계도입니다. 어떤 도커(Docker) 이미지를 사용할지, 얼마나 많은 CPU와 메모리를 할당할지, 필요한 도구들은 무엇인지 등을 정의하죠. 예를 들어, Node.js 빌드가 필요하면 Node.js 런타임이 포함된 이미지를 지정하는 식이에요.

    4. Jenkinsfile 업데이트

    기존 Jenkinsfile도 약간의 수정이 필요할 수 있어요. 특히 `agent any`나 `agent { label ‘my-fixed-agent’ }` 같은 부분을 `agent { kubernetes { yaml ”’…”’ } }` 형태로 바꿔서 동적 Pod를 사용하도록 유도해야 합니다.

    // 기존 Jenkinsfile (예시)
    // pipeline {
    //     agent any
    //     stages {
    //         stage('Build') {
    //             steps {
    //                 sh 'npm install'
    //                 sh 'npm build'
    //             }
    //         }
    //     }
    // }
    
    // Kubernetes 동적 에이전트를 사용하는 Jenkinsfile (예시)
    pipeline {
        agent {
            kubernetes {
                // Kubernetes Pod 템플릿을 직접 정의
                yaml """
    apiVersion: v1
    kind: Pod
    spec:
      containers:
      - name: jnlp
        image: jenkins/inbound-agent:4.11.2-1
        resources:
          limits:
            memory: "512Mi"
            cpu: "500m"
      - name: nodejs
        image: node:16-alpine
        command: ["cat"]
        tty: true
        resources:
          limits:
            memory: "1Gi"
            cpu: "1000m"
    """
                defaultContainer 'nodejs' // 이 컨테이너에서 스크립트 실행
            }
        }
        stages {
            stage('Build Frontend') {
                steps {
                    container('nodejs') { // 'nodejs' 컨테이너에서 실행
                        sh 'npm install'
                        sh 'npm run build'
                    }
                }
            }
            stage('Package Docker Image') {
                // 다른 컨테이너 또는 스크립트 실행
            }
        }
    }
    

    위 Jenkinsfile 예시처럼, 하나의 Pod 안에 여러 컨테이너를 띄워서 각 컨테이너의 역할을 분리할 수 있어요. 예를 들어, `nodejs` 컨테이너에서 프론트엔드 빌드를 하고, `maven` 컨테이너에서 백엔드를 빌드하는 식이죠. 이 덕분에 빌드 환경을 더욱 유연하게 구성할 수 있거든요.

    5. Configuration as Code (JCasC) 적용

    Jenkins 설정을 UI에서 하나하나 하는 건 사실 귀찮고 실수를 유발하기 쉽습니다. JCasC(Jenkins Configuration as Code)는 Jenkins의 모든 설정을 YAML(야믈) 파일로 관리할 수 있게 해줘요. 이 파일을 버전 관리 시스템(VCS)에 커밋(Commit)해두면, Jenkins 인스턴스를 새로 띄우거나 설정을 변경할 때 코드로 관리할 수 있어서 매우 편리합니다. 저도 이걸 적용하고 나서 “이거 진짜 편하더라고요!”라고 감탄했었어요. Jenkins 현대화의 필수 요소라고 생각합니다.

    ⚠️ 주의사항 및 트러블슈팅

    마이그레이션 과정에서 저도 꽤 삽질 좀 했습니다. 여러분은 저 같은 시행착오를 겪지 않으시길 바라며 몇 가지 팁을 공유합니다.

    • Persistent Volume(PV) 설정: Jenkins 마스터의 홈 디렉토리(`JENKINS_HOME`)는 반드시 영구 볼륨으로 설정해야 합니다. 안 그러면 Jenkins Pod가 재시작될 때마다 모든 설정과 플러그인이 날아가는 대참사가 발생합니다. 😱
    • 리소스 제한 (Resource Limits): 에이전트 Pod 템플릿에 CPU와 메모리 리소스 제한을 명확하게 설정해야 합니다. 너무 적으면 빌드가 실패하고, 너무 많으면 클러스터 리소스가 고갈될 수 있어요.
    • 이미지 크기 및 빌드 시간: 동적 에이전트에 사용할 도커 이미지는 필요한 도구만 포함하여 최대한 가볍게 만드는 것이 좋습니다. 이미지가 너무 크면 Pod가 스케줄링(Scheduling)되고 컨테이너(Container)가 시작되는 시간이 길어져 빌드 성능에 악영향을 줄 수 있거든요.
    • 네트워크 문제: Jenkins 마스터에서 GitHub, Nexus, SonarQube 등 외부 서비스에 접근할 수 있는지, 또는 그 반대로 외부에서 Ingress를 통해 Jenkins UI에 접근할 수 있는지 네트워크 설정을 꼼꼼히 확인해야 합니다.
    • RBAC 권한: Jenkins 컨트롤러가 Kubernetes API에 접근할 수 있도록 적절한 Role(역할)과 RoleBinding(역할 바인딩)을 가진 Service Account를 생성하고 연결해야 합니다. 권한 부족으로 Pod 생성이 안 되는 경우가 많아요.

    ✅ 검증 및 마이그레이션 결과

    모든 설정을 마치고 파이프라인을 실행하면, Jenkins 대시보드에서 동적으로 생성되는 에이전트 Pod들을 확인할 수 있습니다. Kubernetes 클러스터에서도 `kubectl get pods -n jenkins` 명령어로 새로운 Pod들이 생성되었다가 작업 완료 후 사라지는 것을 볼 수 있을 거예요. 드디어 됐다! 하고 외쳤던 순간이 기억나네요. 🎉

    Jenkins 대시보드에서 Kubernetes 동적 에이전트 빌드 성공 확인

    Jenkins 대시보드에서 동적 에이전트의 효율적인 동작을 확인하는 것은 마이그레이션 성공의 중요한 지표입니다.

    Jenkins Kubernetes 마이그레이션을 통해 저희 팀은 다음과 같은 이점들을 누릴 수 있었습니다.

    • 빌드 시간 단축: 필요한 리소스를 즉시 할당받아 빌드 시간이 단축되었습니다.
    • 운영 비용 절감: 유휴 리소스가 없어 불필요한 클라우드 비용을 줄일 수 있었어요.
    • 안정성 향상: 특정 에이전트 문제로 인한 빌드 실패가 줄어들고, Kubernetes의 복원력 덕분에 전체 시스템의 안정성이 높아졌습니다.
    • CI/CD 파이프라인 관리의 용이성: JCasC와 Jenkinsfile을 통해 파이프라인과 Jenkins 자체를 코드로 관리하게 되면서, 변경 사항 추적 및 재현성이 크게 향상되었습니다.
    Jenkins on Kubernetes 마이그레이션 핵심 이점 인포그래픽

    Jenkins on Kubernetes 마이그레이션은 탄력적 확장성, 비용 효율성, 그리고 안정성을 동시에 달성하는 효과적인 방법입니다.

    마무리하며: 클라우드 네이티브 CI/CD의 미래

    오늘은 제가 직접 경험했던 Jenkins on Kubernetes 마이그레이션 사례를 공유해 드렸습니다. 처음엔 VM 기반 Jenkins 환경에 익숙해서 변화가 어렵게 느껴졌지만, 클라우드 네이티브 환경으로의 전환은 분명 더 나은 CI/CD 파이프라인을 위한 투자라고 생각해요.

    물론 Jenkins 외에도 Argo CD(아르고 CD)나 Tekton(텍톤) 같은 훌륭한 클라우드 네이티브 CI/CD 도구들이 많이 있습니다. 하지만 기존 Jenkins 환경에 익숙하고, 점진적인 Jenkins 현대화를 원한다면 Kubernetes 위로 Jenkins를 옮기는 것이 좋은 시작점이 될 수 있다고 확신합니다.

    이 글이 여러분의 인프라 여정에 작은 도움이 되었기를 바랍니다. 다음번에는 또 다른 삽질 경험과 해결책으로 찾아오겠습니다. 궁금한 점이나 공유하고 싶은 경험이 있다면 언제든지 댓글 남겨주세요! 😉