본문 바로가기
CI.CD/Jenkins

[Jenkins] 파이프라인 Agent 설정 노하우 (의존성 충돌의 지옥에서 벗어나기)

반응형

성공적으로 `Jenkinsfile`을 생성하고 Declarative Pipeline 구조의 뼈대를 잡았다면, 가장 맨 윗줄에 반드시 선언해야 하는 단어가 있습니다. 바로 agent 지시어입니다.
에이전트(Agent)란 쉽게 말해 "이 파이프라인에 정의된 수많은 빌드 작업들을 실제로 어떤 서버(머신)에서, 어떤 환경을 기반으로 실행할 것인가?"를 젠킨스 마스터(Master)에게 알려주는 핵심 명령어입니다.
이 한 줄을 어떻게 적느냐에 따라 쾌적한 빌드 자동화를 누릴 수도 있고, 알 수 없는 버전 충돌에 시달리며 매일 밤을 새울 수도 있습니다.

이번 [Jenkins 실무 완벽 가이드]에서는 대규모 실무 환경에서 강력하게 권장되는 파이프라인 Agent 설정의 3가지 진화 단계와, 도커(Docker) 기반 1회용 멸균 빌드 환경을 구축하는 노하우를 3,000자 분량으로 아주 상세히 딥다이브 해보겠습니다.

🚫 1. 1단계: Agent Any (초보자의 가장 흔하고 치명적인 실수)

대부분의 튜토리얼이나 인터넷 블로그 예제를 보면 파이프라인의 시작이 agent any로 되어 있습니다.

pipeline {
    agent any // 가장 흔하지만 위험한 설정
    stages { ... }
}

의미: 젠킨스와 연결된 Master 노드 혹은 여러 대의 Slave(Worker) 노드들 중에서 현재 유휴 상태인 아무 노드(Any)에나 대충 이 빌드를 던져서 실행하라는 뜻입니다.

치명적 문제점: 노드가 단 한 대뿐인 개인 토이 프로젝트라면 아무 문제가 없습니다. 하지만 실무에서는 리눅스, 윈도우 서버 등 여러 대의 노드가 물려 있습니다. 만약 A 프로젝트는 Node.js 18 버전이 필요하고, B 프로젝트는 Node.js 14 버전이 필요한 상황을 가정해봅시다. agent any를 쓰면 어떨 때는 Node 18이 깔린 서버에 배정되어 빌드가 성공하지만, 다음번 빌드 때는 무작위로 Node 14가 깔린 서버에 배정되어 코드 수정이 전혀 없었음에도 뜬금없이 문법 에러(Syntax Error)를 뿜으며 빌드가 터져버립니다. 이른바 '원인을 알 수 없는 핑퐁 장애'의 주범이 바로 agent any입니다.


🏷️ 2. 2단계: Label 기반 Agent 명시 (중급자의 통제)

위와 같은 랜덤 배정 문제를 막기 위해, 실무 중급자들은 젠킨스의 라벨(Label) 기능을 활용합니다. 젠킨스 관리 메뉴에서 각 워커 노드 머신에 고유한 이름표(Label)를 붙여줄 수 있습니다. (예: `linux-node18-builder`, `windows-dotnet-builder`, `mac-ios-builder` 등)

pipeline {
    // 젠킨스 시스템에 등록된 'linux-node18' 이라는 라벨을 가진 서버(노드)에서만 이 빌드를 실행하라!
    agent { 
        label 'linux-node18' 
    }
    stages { ... }
}

장점: 이제 Node.js 18 버전 환경이 완벽하게 세팅된 서버에만 빌드 작업이 고정되어 할당되므로 랜덤하게 빌드가 터지는 문제는 완전히 해결됩니다. 또한 iOS 앱 빌드를 위해 반드시 macOS 환경이 필요할 때 label 'mac-ios-builder'로 명확히 타겟팅할 수 있습니다.

한계점: 인프라 관리자가 죽어납니다. 회사에 새로운 프로젝트가 생겨서 파이썬 3.9 환경이 필요해지면, 인프라 관리자는 서버에 접속해서 apt-get install python3.9를 치고 환경변수를 잡고 라벨을 달아주어야 합니다. 만약 프로젝트가 50개라면? 서버 안에 온갖 버전의 Java, Node, Python 패키지들이 짬뽕이 되어 서버 환경 자체가 심각하게 오염(Pollution)됩니다.


🐳 3. 3단계: Docker Agent (상위 1% 실무자의 Best Practice)

서버 환경 오염 문제를 원천 차단하는 궁극의 해결책이 바로 도커 컨테이너를 Agent로 띄워버리는 방식입니다. 이 방식은 젠킨스 워커 노드(호스트 머신) 안에 Docker 엔진 단 하나만 설치되어 있으면 작동합니다.

pipeline {
    agent {
        docker {
            // Docker Hub에 있는 node:18-alpine 이미지를 즉석에서 당겨와(Pull) 컨테이너로 띄웁니다.
            image 'node:18-alpine'
            
            // 실무 꿀팁: 빌드 속도 개선을 위해 npm 캐시 폴더를 호스트 머신과 마운트(공유)합니다.
            args '-v $HOME/.npm:/root/.npm'
        }
    }
    stages {
        stage('Build and Test') {
            steps {
                // 아래 명령어들은 젠킨스 호스트 서버가 아닌, 방금 뜬 'node:18 컨테이너 내부'에서 실행됩니다!
                sh 'node -v'
                sh 'npm ci'
                sh 'npm run build'
            }
        }
    }
}

🔥 이 방식이 실무에서 압도적으로 찬양받는 이유:

  • 1회용 멸균 빌드 환경(Clean Environment): 빌드가 시작되는 순간 깨끗한 Node 18 컨테이너가 짠 하고 나타나 그 안에서 소스코드를 컴파일하고, 빌드가 끝나면 컨테이너가 스스로 삭제(rm)되며 흔적 없이 사라집니다. 이전 빌드에서 남겨놓은 쓰레기 파일이나 캐시가 다음 빌드에 영향을 미치는 끔찍한 현상을 100% 차단합니다.
  • 인프라 관리자의 해방: 개발팀에서 갑자기 "저희 내일부터 Java 17로 버전업 할게요"라고 통보해도, 인프라 팀은 서버에 들어가 Java를 새로 깔 필요가 없습니다. 개발팀 스스로 Jenkinsfileimage 'openjdk:17-jdk' 한 줄만 수정해서 커밋하면 끝입니다. 이것이 진정한 DevOps의 분업화입니다.
  • 완벽한 멱등성 보장: 내 로컬 PC에서 띄운 도커 컨테이너와 젠킨스 서버에서 띄운 도커 컨테이너는 완벽히 동일한 환경(OS, 패키지)을 가집니다. 즉, "내 PC에서는 잘 빌드되는데 왜 젠킨스 서버에만 올라가면 에러가 나지?"라는 변명을 원천 봉쇄할 수 있습니다.

🎯 4. 마무리 및 다음 단계

지금까지 Jenkins Pipeline의 시작과 끝을 결정짓는 Agent 설정 노하우에 대해 3,000자의 밀도 높은 내용으로 살펴보았습니다. agent any의 치명적인 함정을 피하고, 라벨 지정을 거쳐, 현대 CI/CD의 꽃인 Docker 컨테이너 기반의 1회용 격리 빌드 환경까지 단계별로 완벽히 이해하셨을 것입니다. 이제 더 이상 서버에 패키지를 깔다가 의존성이 꼬여 주말 출근을 하는 일은 사라질 것입니다.

빌드를 수행할 완벽한 공간(Agent)을 확보했으니, 이제 소스코드를 외부 서버(AWS EC2 등)에 배포하거나 Docker Hub에 이미지를 푸시해야 합니다. 이때 무조건 필요한 것이 바로 타겟 서버의 비밀번호나 SSH 인증키, 즉 자격 증명 데이터입니다. 이 민감한 정보들을 Jenkinsfile에 평문(Plain Text)으로 적어 깃허브에 올렸다간 다음 날 9시 뉴스에 회사 이름이 나올 수도 있습니다. 이어지는 10단계 포스팅에서는 해킹 걱정 없는 완벽한 보안의 핵심, 'Jenkins Credentials(자격 증명) 완벽 가이드'에 대해 아주 치밀하게 파헤쳐 보겠습니다!

반응형