젠킨스 파이프라인 설정 가이드 - 멀티브랜치 프로젝트와 Jenkinsfile

English (N/A)

인증 정보를 설정했다면 이제 파이프라인을 구성할 차례다. 이 포스트에서는 멀티브랜치 프로젝트를 생성하고 Jenkinsfile로 빌드/배포 파이프라인을 구성하는 방법을 다룬다.

멀티브랜치 프로젝트 생성

멀티브랜치 파이프라인은 저장소의 여러 브랜치를 자동으로 인식하고, 각 브랜치에 있는 Jenkinsfile을 기반으로 빌드를 실행한다.

생성 방법

  1. 젠킨스 대시보드 → "새로운 Item" 클릭
  2. 이름 입력 후 Multibranch Pipeline 선택
  3. "OK" 클릭

Branch Sources 설정

  1. Branch Sources 섹션에서 "Add source" → GitHub 또는 Git 선택
  2. Repository URL 입력
  3. Credentials: 등록해둔 GitHub 크레덴셜 선택

특정 브랜치만 빌드하도록 필터링

모든 브랜치를 빌드하면 리소스 낭비가 될 수 있다. Behaviours 섹션에서 Discover branches 의 "Filter by name (with regular expression)"을 추가해서 특정 브랜치만 빌드하도록 설정할 수 있다.

예를 들어 master, qa, develop 브랜치만 빌드하려면:

master|qa|develop

정규표현식이므로 | 로 여러 브랜치를 나열하면 된다.

feature 브랜치 패턴을 포함하려면:

master|qa|develop|feature/.*

Build Configuration

Jenkinsfile의 위치를 지정한다. 기본값은 저장소 루트의 Jenkinsfile 이다.

다른 경로에 있다면 "Script Path"를 수정한다. (예: ci/Jenkinsfile)

Jenkinsfile 작성

Jenkinsfile은 파이프라인을 코드로 정의하는 파일이다. 저장소에 함께 버전 관리되므로 변경 이력을 추적할 수 있다.

기본 구조

pipeline {
    agent any

    environment {
        NODE_ENV = 'production'
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Install') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Build') {
            steps {
                sh 'npm run build'
            }
        }

        stage('Test') {
            steps {
                sh 'npm test'
            }
        }

        stage('Deploy') {
            when {
                branch 'master'
            }
            steps {
                // 배포 로직
            }
        }
    }

    post {
        success {
            slackSend(color: 'good', message: "Build succeeded: ${env.JOB_NAME} #${env.BUILD_NUMBER}")
        }
        failure {
            slackSend(color: 'danger', message: "Build failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}")
        }
    }
}

Node.js 프로젝트 예시

Node.js 플러그인을 설정했다면 아래처럼 사용할 수 있다.

pipeline {
    agent any

    tools {
        nodejs 'NodeJS 20'
    }

    stages {
        stage('Install') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Lint') {
            steps {
                sh 'npm run lint'
            }
        }

        stage('Test') {
            steps {
                sh 'npm test'
            }
        }

        stage('Build') {
            steps {
                sh 'npm run build'
            }
        }
    }
}

SSH를 통한 배포 설정

빌드된 결과물을 SSH로 배포 서버에 전송하려면 SSH Agent 플러그인을 사용한다.

SSH 크레덴셜 등록

  1. 젠킨스 관리 → Credentials → System → Global credentials
  2. "Add Credentials" 클릭
  3. Kind: SSH Username with private key 선택
  4. 입력 항목:
    • ID: deploy-server-ssh
    • Username: 서버 접속 유저 (예: ec2-user)
    • Private Key: pem 파일 내용 입력

Jenkinsfile에서 SSH 배포

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                sh 'npm run build'
            }
        }

        stage('Deploy') {
            when {
                branch 'master'
            }
            steps {
                sshagent(['deploy-server-ssh']) {
                    sh '''
                        scp -o StrictHostKeyChecking=no -r dist/* ec2-user@your-server:/var/www/html/
                        ssh -o StrictHostKeyChecking=no ec2-user@your-server 'pm2 restart all'
                    '''
                }
            }
        }
    }
}

서버 측 SSH 권한 설정

jenkins 유저가 pem 파일에 접근할 수 있어야 한다.

# pem 파일 권한 설정
sudo chown jenkins:jenkins /var/lib/jenkins/.ssh/deploy.pem
sudo chmod 600 /var/lib/jenkins/.ssh/deploy.pem

# jenkins 유저로 SSH 접속 테스트
sudo -u jenkins ssh -i /var/lib/jenkins/.ssh/deploy.pem ec2-user@your-server

브랜치별 배포 전략

Jenkinsfile의 when 조건을 사용해서 브랜치별로 다른 배포 전략을 적용할 수 있다.

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                sh 'npm run build'
            }
        }

        stage('Deploy to QA') {
            when {
                branch 'qa'
            }
            steps {
                // QA 서버 배포
            }
        }

        stage('Deploy to Production') {
            when {
                branch 'master'
            }
            steps {
                // 프로덕션 서버 배포
            }
        }
    }
}

In-process Script Approval

Jenkinsfile에서 특정 Groovy 메서드나 Java 클래스를 사용하다 보면 이런 에러를 마주칠 수 있다:

Scripts not permitted to use method ...

이건 Jenkins의 보안 기능 이다. 악의적이거나 위험한 코드가 실행되는 걸 막기 위한 장치다.

왜 필요한가

Jenkins는 기본적으로 파이프라인 스크립트를 샌드박스 모드 로 실행한다. 샌드박스 밖의 메서드나 클래스에 접근하려 하면 자동으로 차단된다.

예를 들어:

// 파일 시스템 직접 접근 - 차단됨
new File('/tmp/test.txt').text

// Java 정규식 클래스 사용 - 차단됨
import java.util.regex.Pattern
Pattern.compile('.*')

이런 코드는 Jenkins 서버의 파일 시스템이나 환경 변수에 접근할 수 있어서 보안 위험이 있다.

승인 방법

  1. 젠킨스 관리 → In-process Script Approval 으로 이동
  2. 대기 중인 스크립트/메서드 확인
  3. Approve 버튼 클릭

보안 주의사항

⚠️ 함부로 승인하면 안 된다.

악의적인 코드가 승인되면 Jenkins 서버 전체를 장악할 수 있다. 신뢰할 수 있는 스크립트만 승인한다.

우회 방법 (권장 순서)

승인 없이 문제를 해결하는 게 더 안전하다.

  1. Declarative Pipeline 사용 - 샌드박스 안에서 대부분 해결 가능
  2. Jenkins Plugin 사용 - 검증된 플러그인 활용
  3. Shared Library - 관리자가 승인한 공용 라이브러리
  4. Script Approval - 정말 필요할 때만 승인

예를 들어 파일을 읽고 싶다면:

// ❌ 승인 필요
new File('test.txt').text

// ✅ 승인 불필요
readFile 'test.txt'

정규식이 필요하다면:

// ❌ 승인 필요
import java.util.regex.Pattern
Pattern.compile('.*')

// ✅ Groovy 내장 기능 사용
def pattern = ~/.*/ 

대부분의 작업은 Pipeline DSL의 기본 기능으로 해결할 수 있다.

트러블슈팅

agent any와 deadlock

agent any 를 사용하면 사용 가능한 아무 에이전트에 작업이 할당된다. executor 수가 부족하면 여러 빌드가 서로 대기하면서 deadlock이 발생할 수 있다.

해결 방법:

  • executor 수를 충분히 확보
  • 또는 agent를 명시적으로 지정 (예: agent { label 'build-server' })

자세한 내용은 초기 설정 가이드의 동시 실행 설정 섹션을 참고한다.

Jenkinsfile을 찾지 못하는 경우

  1. Jenkinsfile이 저장소 루트에 있는지 확인
  2. 파일명이 정확히 Jenkinsfile 인지 확인 (대소문자 구분)
  3. 다른 경로에 있다면 Build Configuration의 Script Path 수정

참고

이 포스트는 젠킨스 완벽 가이드 시리즈의 일부다. CI/CD 파이프라인의 전반적인 개념은 Jenkins를 활용한 CI/CD 파이프라인 구축하기를 참고한다.