Jenkins?
✏️ 빌드, 테스트, 배포와 관련된 모든 종류의 작업을 자동화하는데 사용할 수 있는 독립형 오픈 소스 자동화 서버, 대부분의 CI/CD 배포 라이브러리들의 기본적인 구조는 Jenkins와 비슷합니다.
프론트엔드 페이지를 배포하거나, 내부 SDK를 배포할 때 배포 단계를 자동화 시키고 싶어서 사용해보게 됐습니다. 사내 git 저장소로는 bitbucket을 사용하고 있어서 bitbucket pipeline을 사용할 수도 있지만 오히려 Jenkins로 설정하는게 추후 확장성에 좋을 것 같아서 Jenkins를 선택했습니다.
젠킨스를 이용한 배포 단계를 크게보면 이렇습니다.
- 개발자가 특정 저장소에 push
- 저장소와 연결된 web hook이 해당 push 이벤트를 젠킨스에게 전달
- push 이벤트를 전달받은 젠킨스가 작성된 스크립트에 따라 빌드, 테스트, 배포 진행
세부사항은 물론 저장소마다, 배포하려는 프로젝트마다 다르겠지만 이렇게 이해하고 다가가야 장벽이 좀 낮아지는 느낌이고, 어디에 뭘 연결해서 무슨 데이터를 보내는지 이해가 됩니다.
1. 연결하기
✏️ 이벤트가 흘러가는 흐름을 따라 연결해줍니다.
2. 파이프라인 시나리오 작성하기
✏️ 확장성이 좋다는 말은, 플러그인도 많고 옵션도 많고 이런저런 선택지가 많아서 그 중에 프로젝트에 맞는 선택을 해야한다는 뜻입니다. 개발자가 원하는 시나리오를 먼저 정확히 알고 있어야 스크립트 작성 중간에 파이프라인 종류를 바꿔야하거나 하는 불상사를 막을 수 있습니다.
3. 스크립트 작성하기
✏️ push 이벤트를 받아서 젠킨스가 트리거된 후, 젠킨스가 실행시킬 파이프라인을 작성합니다. 파이프라인 문법에는 선언적 파이프라인과 스크립트 파이프라인이 있습니다. 구조는 비슷합니다. 저는 선언적 파이프라인 안에 스크립트 파이프라인을 작성했습니다.
- 스크립트 예시
- git message와 npm version을 체크해서 배포하려고 고군분투 했던 JenkinsFile ….
pipeline {
agent any
environment {
GIT_MESSAGE = get_commit_msg()
}
tools {nodejs "NodeJS"}
stages {
stage('Hello') {
steps {
echo 'Hello...'
}
}
stage('Build') {
steps {
sh "git log -1"
script {
def npmVersion = get_npm_version()
echo "${npmVersion}"
echo "${env.GIT_MESSAGE}"
echo "${env.GIT_MESSAGE}"
echo "${env.GIT_COMMIT}"
echo "${GIT_COMMIT}"
def isUpdate = get_commit_subject("Update")
def isFeature = get_commit_subject("Feature")
def isMajor = isFeature == 0
echo "${isUpdate}"
echo "${isFeature}"
echo "${isMajor}"
if(isMajor){
sh "npm version major"
} else {
sh "npm version minor"
}
echo "${npmVersion}"
sh "git pull"
sh "git pull origin ${BRANCH_NAME}"
sh "git fetch origin ${BRANCH_NAME}"
sh "git status"
sh "git push --set-upstream origin ${BRANCH_NAME} --force"
sh "git tag"
sh "git config --list"
sh "git push origin --tags"
sh "npm publish"
}
}
}
}
}
def get_commit_msg(){
script{
return sh(script:"git show -s --format=%B ${env.GIT_COMMIT}", returnStdout:true).trim()
}
}
def get_commit_subject(subject){
script{
return sh(script:"git show -s --format=%B ${env.GIT_COMMIT}", returnStdout:true).trim().indexOf(subject)
}
}
def get_commit_author(){
script{
return sh(script:"git --no-pager show -s --format=%an ${env.GIT_COMMIT}",returnStdout:true).trim()
}
}
def get_npm_version(){
script{
return sh(script:"npm show dummy-jenkins version",returnStdout:true).trim()
}
}
- 처음에 젠킨스 설정 후 테스트하려고 작성했던 Jenkins file
pipeline {
agent any
tools {nodejs "NodeJS"}
stages {
stage('Hello') {
steps {
echo 'Hello..'
}
}
stage('for the fix branch') {
when {
branch "fix-*"
}
steps {
echo 'this only runs for the fix branches'
}
}
stage('for the PR branch') {
when {
branch "PR-*"
}
steps {
echo 'this only runs for the PR branches'
}
}
}
}
4. 저장소에 push해서 테스트하기
✏️ 설정한 저장소에 새 push commit을 넣어서 실제로 테스트해봅시다!
새 push commit을 넣고 Jenkins에서 Stage 별로 진행되는 것을 UI로 확인해볼 수 있습니다.
-
Stage View
파이프라인에서 설정한 Stage 별 경과 시간과 실행한 step을 간결하게 확인할 수 있습니다. Stage ‘for the fix branch’에서는 브랜치 명이 fix로 시작할 때만 step을 실행하도록 파이프라인을 작성했기 때문에 현재 브랜치인 PR-1에서는 건너뛴 모습입니다. -
Scan Oragnization Folder Log (위의 UI에서 소비 시간을 클릭하면 log를 볼 수 있습니다)
처음에 연결하는 단계에서 잘못되거나, 스크립트가 잘못된 경우 로그를 확인하면서 따라가면 디버깅할 수 있습니다.