super app server - jenkinsfile
https://www.jenkins.io/doc/book/pipeline/syntax/
기존의 scripted(directive) 한 방식에서 조금 더 정통 Jenkins 문법에 가까운 Declarative 방식으로 refactoring.
현재 짜여져 있는 코드는 Scripted 방식
장점
단점
Jenkinsfile - scripted 방식
node {
def version = "${params.majorVersion}.${params.minorVersion}.${params.hotfixVersion}"
def branch = "release-${version}"
def dockerImgRemote = "${params.dockerImageRepo}"
def dockerUser = "${params.dockerUser}"
def dockerPassword = "${params.dockerPassword}"
def publishUrl = "http://${params.publishHost}:${params.publishPort}${params.publishDir}"
def repoUser = "${params.repoUser}"
def repoPassword = "${params.repoPassword}"
switch(distributionType){
case 'integrated':
BuildJar(version, branch)
UploadJar(version, publishUrl, repoUser, repoPassword)
BuildImg(version)
UploadImg(version, dockerImgRemote, dockerUser, dockerPassword)
break
case 'build-jar':
BuildJar(version, branch)
break
case 'build-and-upload-jar':
BuildJar(version, branch)
UploadJar(version, publishUrl, repoUser, repoPassword)
break
case 'build-img':
BuildJar(version, branch)
BuildImg(version)
break
case 'build-and-upload-img':
BuildJar(version, branch)
BuildImg(version)
BuildImg(version)
UploadImg(version, dockerImgRemote, dockerUser, dockerPassword)
break
default:
break
}
}
void BuildJar(version, branch){
stage('Build Jar') {
echo 'Git fetching...'
sh 'git fetch --all'
// sh 'git reset --hard origin/master'
sh "git reset --hard origin/${branch}"
// sh "git pull origin ${branch}"
echo 'Getting Commit ID...'
commitId = sh(returnStdout: true, script: "git log | head -1 | cut -b 7-15")
commitId = commitId.substring(1)
echo 'Building...'
sh 'chmod +x ./gradlew'
sh "./gradlew clean build jenkins -PbuildVersion=${version} -PcommitId=${commitId}"
}
}
void UploadJar(version, publishUrl, repoUser, repoPassword) {
stage('Upload Jar') {
sh "./gradlew publish -PbuildVersion=${version} -PpublishUrl=${publishUrl} -PrepoUser=${repoUser} -PrepoPassword=${repoPassword}"
}
}
void BuildImg(version) {
stage('Build Docker img') {
echo 'Building img...'
sh "sudo docker build --tag super-app-server:${version} --build-arg version=${version} ."
}
}
void UploadImg(version, dockerImgRemote, dockerUser, dockerPassword) {
stage('Upload Docker img') {
//////////////////////////////////////// testing docker img (img run)
sh "sudo docker ps -a"
// sh 'sudo docker stop $(sudo docker ps -a -q)'
// sh 'sudo docker rm $(sudo docker ps -a -q)'
sh "sudo docker run --name super-app-server-test -d -p 8888:8888 super-app-server:${version}"
sh "sudo docker ps | grep super-app-server"
sh 'sudo docker stop $(sudo docker ps -a -q)'
sh 'sudo docker rm $(sudo docker ps -a -q)'
////////////////////////////////////////
echo 'Uploading img...'
sh "sudo docker login -u ${dockerUser} -p ${dockerPassword}"
sh "sudo docker tag super-app-server:${version} ${dockerImgRemote}:${version}"
sh "sudo docker tag super-app-server:${version} ${dockerImgRemote}:latest"
sh "sudo docker push dohyunkim12/super-app-server:${version}"
sh "sudo docker push dohyunkim12/super-app-server:latest"
}
}
After refactor to Declarative way
Declarative pipeline syntax 특징
red box - 필수요소
black box - 선택요소
pipeline {
/* insert Declarative Pipeline here */
}
Section - 각 section은 하나 또는 그 이상의 Directives나 Step들로 구성됨.
agent - agent는 pipeline 전체 또는 특정 stage가 어느 jenkins env에서 실행될 것인지 정함.
Top Level Agent
node("myAgent") {
timeout(unit: 'SECONDS', time: 5) {
stage("One"){
sleep 10
echo 'hello'
}
}
}
agent가 이렇게 상위 레벨에서 선언되면, timeout은 agent에 들어온 이후에 호출됨. (agent에 들어와야지만 실행)
Stage Agent
timeout(unit: 'SECONDS', time: 5) {
stage("One"){
node {
sleep 10
echo 'Hello'
}
}
}
반대로 이렇게 timeout이 먼저 호출되고, stage 안에서 agent(node)가 선언되면 agent에 들어오기 이전에 timeout 호출 (agent할당 이전에 실행된다. )
위의 예제는 timeout이 agent provisioning 시간을 포함하고 있으므로 agent할당이 지연되고 pipeline은 fail될 것.
agent - parameter
agent는 몇가지 parameter 타입을 받을 수 있음. (top-level, stage 둘 다 사용 가능)
agent {label 'lb1 && lb2' }
또는 agent {label 'lb2 || lb2' }
agent {node {label 'labelName' } }
는 agent {label 'labelName' }
과 동일하게 작동한다. 그러나 node는 customWorkspace 같은 추가적인 option을 제공.args
field는 docker run
할 때 함께 줄 옵션 파라미터로 전달할 수 있음.agent {
docker {
image 'myregistry.com/node'
label 'my-defined-label'
registryUrl 'https://myregistry.com/'
registryCredentialsId 'myPredefinedCredentialsInJenkins'
args '-v /tmp:/tmp'
}
}
agent {
// Equivalent to "docker build -f Dockerfile.build --build-arg version=1.0.2 ./build/
dockerfile {
filename 'Dockerfile.build'
dir 'build'
label 'my-defined-label'
additionalBuildArgs '--build-arg version=1.0.2'
args '-v /tmp:/tmp'
}
}
이런식으로 사용하는데, 실 사용시 자세한 소스는 더 찾아봐야 겠다. filename은 Dockerfile 이름이 Dockerfile이 아닐 경우 명시, dir 는 path지정. 위 예에서는 도커파일이 /build/Dockerfile.build
에 존재하는 경우.
dockerfile agent도 역시 registryUrl
과 registryCredentialsId
를 사용할 수 있다.
agent {
kubernetes {
defaultContainer 'kaniko'
yaml '''
kind: Pod
spec:
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:debug
imagePullPolicy: Always
command:
- sleep
args:
- 99d
volumeMounts:
- name: aws-secret
mountPath: /root/.aws/
- name: docker-registry-config
mountPath: /kaniko/.docker
volumes:
- name: aws-secret
secret:
secretName: aws-secret
- name: docker-registry-config
configMap:
name: docker-registry-config
'''
}
examples
Stage-level agent section
pipeline {
agent none
stages {
stage('Example Build') {
agent { docker 'maven:3.8.1-adoptopenjdk-11' }
steps {
echo 'Hello, Maven'
sh 'mvn --version'
}
}
stage('Example Test') {
agent { docker 'openjdk:8-jre' }
steps {
echo 'Hello, JDK'
sh 'java -version'
}
}
}
}
top-level agent를 none으로 설정하여 executor가 초기에 할당되지 않음. (각 stage section에서 agent를 지정해 주어야 함)
stage Example Build 에서 해당 이미지 (maven~~)으로 새롭게 생성된 컨테이너를 agent로 사용.
stage Example Test에서 해당 이미지(openjdk:8-jre)로 새롭게 생성된 컨테이너를 agent로 사용.
post
post를 이용하여 추가적인 step에 대하여 정의할 수 있음.
conditions
example
pipeline{
agent{ label "node" }
stages{ // 1️⃣ stages
stage("A"){
steps{
echo "========executing A========" // 2️⃣ steps
}
post{
always{
echo "========always========" // 2️⃣ steps
}
success{
echo "========A executed successfully========"
}
failure{
echo "========A execution failed========"
}
}
}
}
post{ // 3️⃣ posts
always{
echo "========always========"
}
success{
echo "========pipeline executed successfully ========"
}
failure{
echo "========pipeline execution failed========"
}
}
}