Jenkins의 CICD활용법
CI : GitOps-Jenkins
CD : Argo
Jenkins를 활용한 빌드 및 배포까지의 과정
Jenkins를 활용한 배포 플로우
: 빌드 된 프로젝트를 POD로 올리기 위해 배포 전 도커파일로 컨테이너 이미지 생성, 컨테이너 이미지가 나오면 컨테이너 레지스트리에서 push 이후 ArgoCD가 해당 이미지를 k8s에 배포하게 된다.
ArgoCD
: 소스코드를 깃에 push 하면 build 및 test 가 트리거되고 container registry에서 업로드 된 Docker 이미지를 pull하여 k8s에 배포하면 업데이트 된 manifest file을 ArogoCD가 k8s와 싱크를 맞춘다.
GitOps에서는
배포 정의를 한곳에서 관리하고 한가지 방법으로 배포
ArgoCD가 배포에 유리한 이유
: 문제 발생시 롤백이 유용하며 버전 업그레이드가 쉽다. 또한 지속적 빌드/배포가 자동으로 실행되고 원하는 배포 state를 작성해두면 해당 상태에 맞게 배포상태의 지속적 확인과 변경 사항을 체크하여 운영에 반영함에 있어 용이하다.
Jenkins 설치
- 터미널에
brew install jenkins-lts 로 젠킨스를 설치
- 젠킨스실행
brew services start jenkins

- localhost:8080 으로 접속 후 해당 경로의 secrets 폴더에서 패스워드 확인
cat /Users/hjeen/.jenkins/secrets/initialAdminPassword
- Gradle wrapper 추가
- Build Success
Jenkins PlugIn
- 추천 플러그인(1) :
Gitlab
- 프로젝트를 커밋 또는 merge, update/pull 실행시 빌드가 트리거 된다.
- Groovy 스크립트를 생성하거나, Groovy Maven Project에 묶어서 사용해도 된다.
- webhook을 통해 빌드 작업을 실행하려면 파라미터를 구성해야 한다. (Groovy 스크립트 필드에 추가)
def env = currentBuild.getEnvironment(currentListener)
def map = [:]
if (env.gitlabSourceBranch != null) {
map['sourceBranch'] = env.gitlabSourceBranch
}
if (env.gitlabTargetBranch != null) {
map['targetBranch'] = env.gitlabTargetBranch
}
return map
- 추천 플러그인(2) :
Telegram Bot
- Nara Way Bot 과 같은 기능.
- telegram @BotFather
- 젠킨스 config 파일에 botName과 userName을 입력한다.
- commit 메시지와 함께 빌드,테스트,릴리스,배포의 파이프라인 단계에 대한 노티가 온다.
- maven 설정파일에 dependecy 추가
<dependency>
<groupId>
org.jenkins-ci.plugins
</groupId>
<artifactId>
telegram-notifications
</artifactId>
<version>
1.4.0 //최신버전
</version>
</dependency>
젠킨스의 선언적 파이프라인 : groovy 호환 script를 사용
- 선언적 파이프라인의 필수 구조
- Pipeline ⊃ agent ⊃ stage ⊃ steps
- pipeline은 젠킨스 파이프라인 플러그인을 호출하기 위한 필수 outer block이다.
- jenkins Pipeline에 비해 최근에 추가 되었다.
- pipeline 하위 시스템 위에서 더 간단한 문법 제공
- 유효한 syntax들은 모두
pipeline{}
블록 안에 존재한다.
- 블록은 : Section, Directives, Steps, AssignmentStatement 로 구성됨
pipeline{}
블록 내에서 코드 최대크기를 제한하는 문제가 있다.
pipeline {
agent any # 실행하기 위해 사용가능한 agent
stages { # pipeline 에서의 work
stage ('Build') {
steps { # stage 지시문에서 실제 실행 될 steps 정의
echo 'Building...'
}
}
stage ('Test') {
steps {
echo 'Testing...'
}
}
stage ('Deploy') {
steps {
echo 'Deploying...'
}
}
}
}
- 위 pipeline Syntax로 가상의 'ntree'프로젝트로 파이프라인을 작성
pipeline {
agent any
options {
# 빌드가 동시에 올라올때 이전 빌드는 중단하는 option 설정
disableConcurrentBuilds(abortPrevious: true)
}
stages {
# git clone을 진행할때 실제 실행 될 steps
stage('Clone git') {
steps {
# private repository 접근을 위해 crefentialId 명시
git branch: "${branchName}", credentialsId: "ntree-ci-bot", url: "${gitUrl}"
}
steps ('check version'){
steps {
sh """
# shell에서 호출할 내용
if [ ! -d ${buildVersionPath} ]
then
mkdir -p ${buildVersionPath}
fi
if [ -f version.properties.ini ]
then
cp version.properties.ini ${buildVersionPath}/${projectName}_version.properties
rm version.properties.ini
fi
if [ ! -f ${buildVersionPath}/${projectName}_version.properties]
then
cp version.properties ${buildVersionPath}/${projectName}_version.properties
fi
cat ${buildVersionPath}/${projectName}_version.properties > version.properties
export VERSION=\$(cat version.properties)
if [ ${enviroment} == "DEV" ]
then
yarn version --no-git-tag-version --new-version \$VERSION
yarn version --no-git-tag-version --prerelease
elif [ ${environment} == "PRD" ]
then
yarn version --no-git-tag-version --new-version \$VERSION
yarn version --no-git-tag-version --path
fi
"""
script {
version = sh(returnStdot: true, script: """
VERSION=\$(node -pe "require('./package.json').version")
echo \$VERSION
""").trim()
echo "version is $version"
tagVersion = version
}
}
}
stage('Build package') {
parallel {
# pipeline은 기본적으로 순차 실행이지만 parallel{} 안의 stage는 병렬 수행
stage('Build package - DEV') {
when {expression {enviroment == "DEV"}}
steps {
sh 'yarn install && yarn upgrade --pattern "ntree" $$ yarn list --pattern "ntree" --depth=0'
sh 'yarn build-dev'
}
}
stage('Build package - PRD') {
when {expression {environment == "PRD"}}
steps {
sh 'yarn install'
sh 'yarn build-prod'
}
}
}
}
stage('Image Build') {
steps {
# pod로 올리기 위해 배포 전 만든 도커이미지파일(Dokerfile은 프로젝트의 Directory 'devops'에 생성)
sh "docker buid -f devops/Dockerfile -t ${env,IMAGE_REGISTRY}/${repositoryName}:${tagVersion} ."
}
post {
failure {
echo 'Docker image build failure'
}
success {
echo 'Docker image build success'
}
}
}
stage('Push image') {
steps {
# 빌드된 Docker image를 push
sh "aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${env.IMAGE_RESISTRY}"
sh "docker push ${env.IMAGE_RESISTRY}/${repositoryName}:${tagVersion}"
sh "docker image rm ${env.IMAGE_REGISTRY}/${repositoryName}:${targetVersion}"
}
post {
failure {
echo 'Docker image build failure'
}
success {
echo 'Docker image build success'
}
}
}
stage('Push version info') {
steps {
sh "echo ${version} > version.properties"
sh "git config --global user.email \"ntree-ci-bot@ntree.io\""
sh "git config --global user.name \"ntree-ci-bot\""
# 요청에 보낼 인증정보
withCredentials([gitUsernamePassword(credentialsId: 'ntree-ci-bot', gitToolName: 'Default')]) {
sh "git add version.properties && git commit -m \"[ci-skip] Version info updated\" && git push origin HEAD:${branchName}"
}
sh "cat version.properties > ${buildVersionPath}/${projectName}_version.properties"
}
}
}
}
}