젠킨스란 무엇인가, CI(Continuous Integration) 서버의 이해
Credit: Getty Images Bank
젠킨스는 다른 일상적인 개발 작업을 자동화할 뿐 아니라 파이프라인(Pipeline)을 사용해 거의 모든 언어의 조합과 소스코드 리포지토리에 대한 지속적인 통합과 지속적인 전달 환경을 구축하기 위한 간단한 방법을 제공한다.
젠킨스가 각각의 단계에 대한 스크립트 작성의 필요성을 없애주지는 않지만, 사용자가 쉽게 구축할 수 있는 것보다 더 빠르고 더 강력하게 빌드(Build), 테스트, 그리고 배포(deployment) 도구 등 체인 전체를 통합할 수 있는 방법을 제공해 준다.
"나이틀리 빌드(Nightly Build)를 망가뜨리지 말라!"는 말은 매일 아침 테스터들을 위해 새로 빌드된 일일 제품 버전을 게시하는 소프트웨어 개발 조직의 기본 규칙이다. 젠킨스가 나오기 전에는, 나이틀리 빌드를 망가뜨리지 않기 위해 개발자가 할 수 있는 최선의 작업은 코드를 커밋(Commit)하기 전에 로컬 머신 상에서 조심스럽고 성공적으로 빌드해 테스트하는 것이었다. 하지만, 이는 다른 모든 사람들의 일일 커밋 없이, 혼자서 누군가의 변경사항을 테스트하는 것을 의미했다.
젠킨스, 원래는 허드슨(Hudson)은 이런 제한에 대한 직접적인 대응이었다.
허드슨과 젠킨스
2004년에 코스케 가와구치는 썬(Sun Microsystems)의 자바 개발자였다. 가와구치는 개발 작업에서 빌드를 깨는 것에 질려서, 코드를 리포지토리에 커밋하기 전에 해당 코드의 동작 여부를 알 수 있는 방법을 찾고 싶었다. 그래서 가와구치는 자바에서 이를 가능케 하는 자동화 서버를 자바로 개발했고, 허드슨이라는 이름을 붙였다. 허드슨은 썬에서 유명해졌으며, 오픈소스로 다른 기업들에게 확산됐다.
2011년으로 접어들면서, (썬을 인수한) 오라클 그리고 독자적인 허드슨 오픈소스 커뮤니티 간의 분쟁으로 젠킨스란 새로운 이름을 달고 갈라지게 되었다. 두 분류 모두 존속했지만, 젠킨스가 훨씬 더 활동적이었다. 2014년에 가와구치는 젠킨스 기반의 지속적 배포(Continuous Delivery, CD) 제품을 공급하고 있는 클라우드비즈(CloudBees)의 CTO가 되었다.
젠킨스 자동화
오늘날 젠킨스는 온갖 종류의 개발 작업을 지원하기 위한 약 1,400가지의 플러그인을 가지고 있는 선두적인 오픈소스 자동화 서버다. 가와구치가 애초에 해결하려 했던 지속적인 통합과 지속적인 자바 코드 전달, 즉 프로젝트 빌드, 테스트 실행, 정적 코드 분석 시행, 그리고 배포 작업은 사람들이 젠킨스를 사용해 자동화하고 있는 여러 가지 프로세스들 가운데 한가지일 뿐이다. 이 1,400개의 플러그인은 5가지 영역을 포괄하고 있다(플랫폼, UI, 관리, 소스코드 관리, 그리고 가장 많이 사용되는 빌드 관리).
젠킨스 동작 방식
젠킨스는 주요 운영체제용 자바 8 WAR 아카이브와 설치 패키지, 홈브루(Homebrew) 패키지, 도커 이미지, 그리고 소스코드 형태로 사용할 수 있다. 소스코드는 대부분 자바이며, 몇 개의 그루브(Groovy), 루비(Ruby), 그리고 앤틀러(Another Tool For Language Recognition, ANTLR) 파일이 들어 있다.
젠킨스 WAR를 단독으로 또는 톰캣 같은 자바 애플리케이션 서버에서 서버렛(Serverlet)으로 실행할 수 있다. 둘 가운데 어느 경우든, 웹 사용자 인터페이스(UI)를 생성하며 REST API에 대한 호출을 받아들인다.
젠킨스 플러그인
설치되고 나면, 젠킨스는 사용자가 기본 플러그인 목록을 수용하거나 원하는 플러그인을 선택할 수 있게 해준다.
Credit: IDG
초기 플러그인 세트를 고른 다음에, 설치 버튼을 클릭하면 젠킨스가 선택한 플러그인들을 추가한다.
Credit: IDG
젠킨스 메인 화면은 현 빌드 큐(Build Queue)와 실행기(Executor) 상태를 표시하며, 신규 항목(작업: Job) 생성, 사용자 관리, 빌드 이력 보기, 젠킨스 관리, 사용자의 맞춤형 뷰 보기, 그리고 사용자의 인증서를 관리할 수 있는 링크를 제공한다.
Credit: IDG
신규 젠킨스 항목은 6가지 유형의 작업 + 항목 관리를 위한 폴더 중 아무 것이나 될 수 있다.
Credit: IDG
젠킨스 관리(Manage Jenkins) 페이지에서는 명령어 줄 인터페이스를 열기 위한 옵션을 포함해 18가지 일을 할 수 있다. 하지만, 본 기사에서는 대개 스크립트로 정의되는 개선된 워크플로우인 파이프라인을 살펴보기로 하자.
Credit: IDG
젠킨스 파이프라인
젠킨스를 구성했다면, 이제는 젠킨스가 빌드할 수 있는 몇 가지 프로젝트를 생성할 시점이다. 스크립트를 작성하기 위해 웹 UI를 사용할 수도 있지만, 현재 최고의 공부는 Jenkinsfile이란 이름의 파이프라인 스크립트를 생성해 그것을 리포지토리에 체크인 하는 것이다. 다음 스크린샷은 멀티브랜치(Multibranch) 파이프라인에 대한 구성 웹 양식을 보여준다.
Credit: IDG
그림에서 볼 수 있듯이, 필자의 기본 젠킨스 설치본에서 이런 종류의 파이프라인에 대한 브랜치 소스(Branch Source)는 깃허브(GitHub)를 포함해, 깃(Git) 또는 서브버전(Subversion)일 수 있다. 다른 종류의 리포지토리 또는 다른 온라인 리포지토리가 필요한 경우, 적절한 플러그인을 추가하고 젠킨스를 재부팅하기만 하면 된다. 필자도 시도해 봤지만, 목록에 있는 젠킨스 플러그인이 없는 SCM(Source Code Management System)은 생각해 볼 수도 없었다.
젠킨스 파이프라인은 선언적 또는 스크립트일 수 있다. 두 가지 가운데 더 간단한 선언적 파이프라인은 그루비 호환 구문을 사용하며, 원하는 경우, 코드 편집기를 올바른 방향으로 이끌기 위해 #!groovy로 파일을 시작할 수 있다. 선언적 파이프라인은 다음의 3단계 예제처럼, pipeline 블록으로 시작해, agent를 정의하고, 실행 가능한 steps를 포함하는 stages를 정의한다.
pipeline {
agent any
stages {
stage(‘Build’) {
steps {
echo ‘Building..’
}
}
stage(‘Test’) {
steps {
echo ‘Testing..’
}
}
stage(‘Deploy’) {
steps {
echo ‘Deploying....’
}
}
}
}
pipeline은 젠킨스 파이프라인 플러그인을 호출하기 위한 필수 외부 블록(Outer Block)이다. agent는 파이프라인을 실행하고 싶은 위치를 정의한다. any는 파이프라인이나 스테이지(stage)를 실행하기 위해 사용 가능한 어떤 에이전트(agent)도 사용할 수 있음을 나타낸다. 예를 들어 좀 더 구체적인 에이전트라면 다음과 같이 사용할 컨테이너를 선언할 것이다.
agent {
docker {
image ‘maven:3-alpine’
label ‘my-defined-label’
args ‘-v /tmp:/tmp’
}
}
stages에는 한 개 이상의 스테이지 지시어(Directive)가 들어있다. 앞의 예에서, 세 개의 스테이지는 Build, Test 그리고 Deploy이다.
steps가 실제 작업을 수행한다. 앞서 예에서 steps는 메시지만 표시했다. 더 유용한 빌드 스텝이라면 다음과 같을 것이다.
pipeline {
agent any
stages {
stage(‘Build’) {
steps {
sh ‘make’
archiveArtifacts artifacts: ‘**/target/*.jar’, fingerprint: true
}
}
}
}
이 예에서 우리는 셸(Shell)에서 make를 호출한 다음에, 생성된 JAR 파일을 젠킨스 아카이브로 아카이빙하고 있다.
post 세션은 파이프라인 실행 또는 스테이지 끝에 실행될 동작을 정의한다. 포스트 세션 안에서 여러 개의 포스트-조건 블록을 사용할 수 있다(always, changed, failure, success, unstable, 그리고 aborted).
예를 들어, 다음의 젠킨스는 Test 스테이지 다음에 항상 Junit을 실행하지만, 파이프라인이 실패하는 경우에는 이메일만 보낸다.
pipeline {
agent any
stages {
stage(‘Test’) {
steps {
sh ‘make check’
}
}
}
post {
always {
junit ‘**/target/*.xml’
}
failure {
mail to: team@example.com, subject: ‘The Pipeline failed :(‘
}
}
}
지시어 파이프라인은 사용자가 파이프라인을 정의하기 위해 필요한 대부분의 것을 표현할 수 있으며, 그루비 기반 DSL인 스크립티드 파이프라인 구문보다 훨씬 더 배우기 쉽다. 실제로 스크립티드 파이프라인은 모든 특성을 갖춘 프로그래밍 환경이다.
선언적(Declarative) 파이프라인
pipeline {
agent { docker ‘node:6.3’ }
stages {
stage(‘build’) {
steps {
sh ‘npm ?version’
}
}
}
}
스크립티드(Scripted) 파이프라인
node(‘docker’) {
checkout scm
stage(‘Build’) {
docker.image(‘node:6.3’).inside {
sh ‘npm ?version’
}
}
}
젠킨스 GUI, 블루 오션
최신의 가장 멋진 젠킨스 UI를 원한다면, 블루 오션(Blue Ocean) 플러그인을 사용할 수 있으며, 이 UI는 그래픽 사용자 경험을 제공한다. 기존 젠킨스 설치본에 블루 오션을 추가하거나 젠킨스/블루 오션 도커 컨테이너를 실행할 수 있다. 블루 오션이 설치되면, 젠킨스 메인 메뉴에 추가 아이콘이 생길 것이다.
Credit: IDG
원하는 경우, 블루 오션을 직업 사용할 수 있다. 젠킨스 서버 상의 /blue 폴더에 들어있다. 블루 오션에서 파이프라인 생성은 평범한 젠킨스에 비해 좀 더 그래픽하다.
Credit: IDG
젠킨스 도커
앞서 언급했듯이, 젠킨스는 도커 이미지로도 배포되고 있다. 그 과정에 별다른 것은 없다. SCM 유형을 선택하고 나서, URL과 인증서를 제공한 다음에, 단일 리포지토리에서 파이프라인을 생성하거나 그룹 저장소(Organization)에 있는 모든 리포지토리를 스캔 한다. Jenkinsfile을 가지고 있는 모든 브랜치가 파이프라인을 갖게 될 것이다.
Credit: IDG
몇 개의 파이프라인을 실행하면, 블루 오션 플러그인이 위와 같이 파이프라인들의 상태를 표시할 것이다. 스테이지와 스텝을 보기 위해 각각의 파이프라인을 확대할 수 있다.
Credit: IDG
브랜치(맨 위)와 작업상황도 확대할 수 있다.
Credit: IDG
Credit: IDG
젠킨스를 사용하는 이유
우리가 사용하고 있는 파이프라인 플러그인은 일반적인 CICD(Continuous Integration/Continuous Delivery) 사용 사례를 지원하고 있으며, 아마도 이것이 가장 흔한 젠킨스 사용법일 것이다.
자바 프로젝트가 원래의 젠킨스 존재 이유였다. 우리는 이미 젠킨스가 메이븐(Maven)을 사용한 빌드작업을 지원한다는 것을 보았다. 앤트(Ant), 그래들(Gradle), J유닛(JUnit), 넥서스(Nexus), 그리고 아티팩토리(Artifactory)와도 동작한다.
안드로이드는 일종의 자바를 실행하고 있지만, 광범위한 안드로이드 기기 상에서 테스트하는 방법 문제를 제기하고 있다. 안드로이드 에뮬레이터 플러그인은 사용자가 정의하고 싶어하는 수만큼의 에뮬레이트 된 기기 상에서 빌드와 테스트를 할 수 있게 해준다. 구글 플레이 퍼블리셔(Publisher) 플러그인은 릴리즈를 위해 또는 실제 기기 상에서의 더 많은 테스트를 위해 구글 플레이의 알파 채널로 빌드를 보낼 수 있게 해준다.
필자는 파이프라인에 대한 에이전트로 도커 컨테이너를 지정하고 도커 컨테이너에서 젠킨스와 블루 오션을 실행한 예를 보여주었다. 도커 컨테이너는 젠킨스 환경에서 속도, 확장성, 그리고 일관성을 개선하는데 매우 유용하다.
젠킨스와 깃허브에는 2가지 중요한 용도가 있다. 한 가지는 빌드 통합으로, 깃허브 리포지토리에 커밋을 할 때마다 젠킨스를 작동시키기 위한 서비스 훅(Hook)을 포함할 수 있다. 두 번째는 오쓰(OAuth)를 통해 젠킨스에 대한 액세스를 제어하기 위해 깃허브 인증을 사용하는 것이다.
젠킨스는 자바 외에도 다수의 언어들을 지원한다. C/C++의 경우, 오류와 콘솔의 경고 메시지를 캡처하고, CMake를 사용해서 스크립트를 빌드하며, 단위 테스트를 실시하고, 정적 코드 분석을 수행할 수 있는 플러그인들이 있다. 젠킨스는 PHP 도구들과 다방면으로 통합된다.
가령, 싸이썬(Cython)을 사용하고 있거나, 설치를 위해 파이썬 휠(Wheel)을 생성하는 경우가 아닌 한 파이썬 코드는 빌드가 필요없지만, 젠킨스가 파이썬 테스트와 노즈2(Nose2), 파이테스트(Pytest) 같은 보고서 작성 도구 그리고 파이린트(Pylint) 같은 코드 품질 향상 도구와 통합된다는 것은 유용하다. 마찬가지로, 젠킨스는 레이크(Rake), 큐쿰버(Cucumber), 브레이크맨(Brakeman), 그리고 CI::리포터(Reporter) 같은 루비 도구들과도 통합된다.
젠킨스 대 뱀부(Bamboo)
사람들은 종종 CICD 서버용으로 젠킨스나 아틀라시안 뱀부 가운데 어떤 것을 사용하는 것이 더 나은지를 묻는다. 컨설턴트로서 필자의 답변은 "그때그때 달라요"다.
우선, 젠킨스는 무료 오픈소스이고, 뱀부는 상용 소프트웨어다. 젠킨스가 더 큰 커뮤니티와 더 많은 플러그인을 가지고 있다. 반면에, 뱀부 상용 라이선스에는 아틀라시안의 지원이 포함되어 있으며, 뱀부는 빗버킷(Bitbucket), 지라(Jira), 그리고 컨플루언스(Confluence) 같은 다른 아틀라시안의 제품들과 기본적으로 잘 통합되어 있다.
예전에는 뱀부를 온프레미스 환경뿐 아니라 클라우드 서비스로도 사용할 수 있었다. 2017년 1월자로 뱀부 클라우드는 더 이상 사용할 수 없게 되었다. 대신, 아틀라시안은 클라우드 기반 소프트웨어 개발용으로 빗버킷 파이프라인을 제공하고 있다. 뱀부 서버는 아직 온프레미스 설치용으로 사용할 수 있으며, 클라우드 기반 컨테이너나 VM에 호스팅할 수 있다. editor@itworld.co.kr