💡 CICD 과정LINK의 개요에 따라 작성되었습니다.
순서를 따르면 순조롭게 진행할 수 있습니다.

Jenkins에서 Build 진행하기

Jenkins는 Jenkinsfile을 읽고 여러 stage를 순서대로 실행하게 된다.

Jenkins의 배포 기본 과정은 다음과 같다.

  1. github에서 소스파일을 checkout해온다.
  2. 암호화된 파일을 git secret을 이용해 복호화 시킨다.
  3. 프로젝트가 실행될 포트를 파싱한다.
  4. 소스파일을 테스트, 빌드한다.
  5. 빌드된 jar파일을 도커 이미지로 만들고 도커 허브에 push한다.
  6. 개발/운영 서버에 접속해 도커 이미지를 내려받고 기존 컨테이너를 내린 후 새 컨테이너를 실행한다. 위에서 말했듯이 순서대로 적용해 보겠다.

위의 과정대로 stage를 하나하나 작성해보자.

Checkout

가장 먼저 프로젝트 최상위에 Jenkinsfile이라는 파일을 생성하자. 첫 stage에서는 GIthub 원격 리포지토리에서 변경이 감지된 브랜치를 checkout 해올 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pipeline {

    agent any

    stages {
        stage('Git Checkout') {
            steps {
                echo 'Checkout Remote Repository'
                git branch: "${env.BRANCH_NAME}",
                url: '[원격 레포지토리 URL]'
            }
        }
    }
}

위 처럼 작성하면 변경이 감지된 브랜치를 checkout해오는 stage가 완성된다. 기본적인 pipeline syntax는 공식 문서를 참고하자.

git은 jenkins git plugin인데 Jenkins를 처음 실행할 때 기본적으로 설치되는 플러그인이다. 공식 문서에서 jenkins git plugin의 checkout pipeline 작성 예시를 확인할 수 있다.

env는 Jenkins의 기본적인 환경변수이다. env의 variable들은 공식 문서에서 다음과 같이 확인할 수 있다.

  • BUILD_ID
  • BUILD_NUMBER
  • BUILD_TAG
  • BUILD_URL
  • EXECUTOR_NUMBER
  • JAVA_HOME
  • JENKINS_URL
  • JOB_NAME
  • NODE_NAME
  • WORKSPACE

또한 공식 문서에 따르면 Multibranch Pipelines에서는 추가적으로 다음과 같은 variable을 추가로 가진다.

  • BRANCH_NAME
  • CHANGE_ID

따라서 위에 있는 BRANCH_NAME을 활용해 변경이 감지된 브랜치를 checkout해 올 수 있다.

참고 : groovy의 double-quoted-string과 single-quoted-string의 차이

single-quoted-string은 java.lang.String과 같은 클래스이고, double-qouted-string은 org.codehaus.groovy.runtime.GStringImpl 클래스로서, GString이라고 불린다. GString은 lazy loading을 지원해 ${변수명}을 포함시켜 toString()이 호출될 때 실제 문자열로 변환된다. 예시로 동적 SQL문을 생성할 때 사용할 수 있다.

위와 같은 이유로 branch명을 불러올 때 double-qouted-string을 사용했다.

복호화

이제 checkout해온 소스파일에서 암호화된 파일을 복호화 하는 과정을 해야한다.

가장 먼저 아까 만들어 두었던 test-jenkins의 private key를 jenkins의 credential로 등록해 줄 것이다.

가장 먼저 private-key를 복사해 보자

1
$ gpg --export-secret-key test-jenkins > private.key

위의 명령어를 입력하면 private.key라는 파일에 private-key가 추출된다.

이제 credential을 만들어 jenkins에 private-key를 등록 시키자.

해당 private key는 cicd-test라는 프로젝트에 국한된 것이기 때문에, cicd-test item 스코프에 국한된 credential을 생성해보자.

cicd-test item의 credential에 들어간다.

cicd-test를 눌러 해당 아이템에서 접근 가능한 도메인 목록에 들어간다.

현재는 Global credentials밖에 존재하지 않는다. Add domain버튼을 눌러 도메인을 생성해 준다.

위처럼 도메인 폴더를 생성한다. 이제 해당 item에서만 접근할 수 있는 도메인이 생성되었다.

Add Credentials버튼을 눌러 Credential을 추가한다.

다양한 종류의 Credential을 생성할 수 있다. private.key를 등록해 줄것이기 때문에 위와 같이 Secret file로 Credential을 등록해준다. 이제 private.key는 필요 없으니 삭제해준다.

1
$ rm private.key

jenkins에서 gpg와 git-secret을 이용해 파일을 복호화 해야 하니 jenkins에 접속해 gpg와 git-secret을 설치해 준다.

1
2
3
4
5
6
7
8
# Jenkins bash 접속
$ docker exec -it jenkins /bin/bash

# gpg, git-secret 설치
$ apt update
$ apt install gpg git-secret -y

$ exit

Jenkinsfile 의 agent any 다음에 다음 환경변수 설정을 해준다.

1
2
3
4
5
agent any

environment {
    GPG_SECRET_KEY = credentials('GPG_SECRET_KEY')
}

만들어 놓았던 Credential을 GPG_SECRET_KEY라는 변수에 저장한다. 이제 Jenkinsfile에 복호화 stage를 추가해 준다.

1
2
3
4
5
6
7
8
stage('Git Secret Reveal') {
    steps {
        echo 'Git Secret Reveal'  
        sh(script:  
            ('gpg --batch --import ' + GPG_SECRET_KEY + ' && '  
            + ' git secret reveal -f'))
    }
}

private.key를 등록시켜둔 Credential을 gpg-key로 import 시킨다. 그리고 checkout해온 소스파일에서 암호화된 파일을 복호화 시킨다.

String들을 + 문법을 사용해 연결시켰는데 이는 Credential을 직접 double-quoted-string안에 호출하면 다음과 같은 Warning이 생기기 때문이다.

해당 방법은 insecure하므로 +문법을 사용해 더해주자.

sh에 관한 문법은 공식 문서에서 확인할 수 있듯이 String 타입인 script만 필수이고 나머지는 optional이므로 sh 'aaa'의 형식으로 입력하면 된다.

'''는 groovy의 Triple-single-quoted String으로 여러줄의 문자를 입력하는 데 용이한 문법이다. 현재 커맨드는 여러줄이 아니지만 시인성을 위해 사용했다. (참고 : LINK)

Build

복호화 다음 stage는 포트를 파싱하는 것이지만 나중에 필요성이 생길 때 작성하고 build stage를 먼저 작성하겠다.

이제 받아온 프로젝트 소스파일을 gradlew를 이용해 빌드한다. 다음과 같은 stage를 추가해준다.

1
2
3
4
5
6
7
8
stage('Build') {
    steps {
        echo 'Build With gradlew'
        sh '''
            ./gradlew clean build
        '''
    }
}

위와 같이 작성하면 ./gradlew clean build라는 명령어를 이용해 build를 진행한다. 특별한 설정을 만지지 않았다면 여기서 test가 진행되게 되고 test를 통과하지 못하면 build stage가 중단되고 배포가 실패하게 된다.

최종적인 Jenkinsfile의 내용은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
pipeline {

    agent any

    environment {  
        GPG_SECRET_KEY = credentials('GPG_SECRET_KEY')  
    }

    stages {
        stage('Git Checkout') {
            steps {
                echo 'Checkout Remote Repository'
                git branch: "${env.BRANCH_NAME}",
                url: '[원격 레포지토리 URL]'
            }
        }

        stage('Git Secret Reveal') {
            steps {
                echo 'Git Secret Reveal'  
                sh(script:  
                    ('gpg --batch --import ' + GPG_SECRET_KEY + ' && '  
                    + ' git secret reveal -f'))
            }
        }

        stage('Build') {
            steps {
                echo 'Build With gradlew'
                sh '''
                    ./gradlew clean build
                '''
            }
        }
        
    }
}

이제 변경사항을 push하고 결과를 확인해보자.

1
2
3
$ git add .
$ git commit -m "chore: Jenkinsfile 생성 및 checkout, secret reveal, build stage 추가"
$ git push

push 후 Jenkins를 확인해 보자.

성공적으로 진행된 것을 확인할 수 있다.

Console Output을 확인해보면 위처럼 checkout, 복호화, build 과정이 잘 진행되었다는 로그를 확인할 수 있다.

다음 포스트에서는 Build된 결과를 Docker Image로 Build하고 Docker Hub에 Push하는 과정을 진행해 보자.

댓글남기기