CI-CD

젠킨스 웹훅(Jenkins webhook)으로 깃헙(Github)과 연동하기

iKay 2020. 4. 22. 00:47
반응형

Jenkins 설치법에 이어 CI/CD 하기 위해 Jenkins 사용 법을 차근차근 정리할 예정이다. 이번에는 가장 기본인 github에 소스 코드가 push되면 Jenkins가 webhook으로 그것을 받아서 빌드, 테스트 등의 스크립트를 실행하는 방법에 대해 정리한다. 앞으로 NodeJS를 CI/CD하는 방법을 앞으로 정리할 예정이다.

 

 

깃헙(Github) 웹훅 키 발급

깃헙 오른쪽 상단 [ 프로필 > Settings > Developer settings > Personal access tokens ] 에서 Generate new token을 눌러서 웹훅 토큰을 생성한다. 이때, Note에는 적당히 이름을 넣어주고 repoadmin:repo_hook에 대한 권한을 준다. 생성된 토큰은 한 번만 볼 수 있으니 잘 메모해두자.

 

 

젠킨스 웹훅(Jenkins Webhook) 설정

젠킨스 홈 화면에서 [ Jekins 관리 > 시스템 설정 > Github ] 에서 GitHub Server를 설정한다.

 

Name은 적당히 입력한다.

 

API URL은 https://api.github.com 으로 일단 그대로 둔다. Enterprise로 사용하려면 API endpoint를 다르게 설정할 수 있는 것으로 보이는데 필요하면 그때 설정하도록 한다.

 

Credentials에 위 깃헙 웹훅 키를 발급 받은 것을 입력해야 한다. add를 누르고 키를 추가 하는 화면에서 kindsecret text를 선택하고, ID는 키를 식별할 수 있게 적당히 입력한 후, ID에 깃헙 웹훅 키를 입력한다.

 

입력 후 Test connection이 정상이면 잘 된 것이다.

 

깃헙(Github)에 SSH Public Key 등록

깃헙 오른쪽 상단 [ 프로필 > Settings > SSH and GPG Keys ] 에서 jenkins 전용 ssh 공개(pub)키를 등록했다. 개인적으로 깃헙에서 인증을 할 때 ssh 방식을 선호하기 때문이다. 계정이 아니라 레포지토리 단위로 ssh 키를 등록해서 사용해도 되지만 귀찮으니 계정에 등록했다.

 

* ssh 키 발급 방법[1]: https://help.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent

 

 

 

젠킨스에서 빌드 잡 생성

 

잡을 생성하는 방법은 대표적으로 Freestyle과 Pipeline 두 가지가 있는 것 같다. Jenkins doc[2]을 읽어보면 Freestyle이 아니라 Pipeline으로 사용 법이 소개되고 있는데 그래서 Freestyle보다 Pipeline 방식이 더 선호되는 것 같다. Pipeline이 Freestyle에 비해 어떤 점이 더 좋은 지는 다음에 비교해서 포스팅 해 봐야겠다.

 

Pipeline이든 Freestyle이든 두 가지 다 일단 동작은 하니, 두 방법으로 빌드 잡을 유발해 봤고, 둘 중 한 가지 방법을 취하면 될 것 같다.

1. Pipeline

[ 젠킨스 홈 > 새로운 Item > Pipeline ] 으로 빌드 잡을 하나 생성한다.

 

[ Build Triggers > GitHub hook trigger for GITScm polling 선택 ]

 

[ Pipeline > definition 에서 Pipeline script from SCM 선택

                 > SCM 에서 Git 선택

                 > Repositories > Repository URL > github 레포지토리 주소 입력(예,git@github.com:i-kay/build-test-1.git)

                 > Credentials > SSH Username with private key로 선택한 후 아까 깃헙에서 발급한 Jenkins용 SSH 공개 키와 쌍이 되는 개인키를 추가

                 > Branches to build > Branch Specifier 에 origin/master

                 > Script PathJenkinsfile (빌드 명령어가 명시된 Pipeline 스크립트 이름으로 상대 경로이다.)

]

 

 

Jenkins 스크립트 작성

프로젝트 디렉토리 최상단에 Jenkins 파일을 만들고 다음과 같이 스크립트를 작성한다. Pipeline 스크립트 문법은 다음을 참고하자. https://jenkins.io/doc/book/pipeline/

 

// Jenkinsfile

pipeline {

    agent any

    tools { nodejs "nodejs12" }

    stages {

        stage('Get build information') {
            steps {
                sh 'echo $PATH'
                sh 'node --version'
                sh 'npm --version'
            }
        }

        stage('Install dependencies') {
            steps {
                sh 'npm install'
            }
        }

        stage('Test') {
            steps {
               sh 'npm test'
            }
        }

        stage('Build') {
            steps {
                sh 'npm run build'
            }
        }
    }
}

 

간단히 설명하면,

 

- agent: 잡을 실행할 node. any이면 어떤 node에서든 실행된다.

- stages: 일련의 잡이 실행 될 stage 이다. 보통 빌드/테스트/배포 세 개 이상의 stage로 구성된다.

- stage: 각 빌드/테스트/배포 등을 명시하는 곳이다.

 

pipeline script 을 작성하는 법은 따로 포스팅 해야겠다.

2. Freestyle

[ 젠킨스 홈 > 새로운 Item > Freestyle project ] 으로 빌드 잡을 하나 생성한다.

 

[ 소스 코드 관리 > GIt 선택 ] 후

 

Respository URL에 github 레포지토리 주소(예, git@github.com:i-kay/build-test-1.git)를 입력한다. 미리 github 레포지토리가 생성되어 있어야 한다.

 

Credentials에 Kind를 SSH Username with private key로 선택한 후 아까 깃헙에서 발급한 Jenkins용 SSH 공개 키와 쌍이 되는 개인키를 추가한다. Username은 Github계정 이름이다.

 

Branched to build가 있는데 일단 */master로 두자. 이 설정은 master 브랜치에 변화(push와 같은)가 일어나면 빌드를 하겠다는 것이다.더 궁금하다면, 물음표를 열어서 설명을 읽어보면 자세히 알 수 있다.

 

빌드 유발 > Github hook trigger for GITScm polling 선택, 깃헙으로 부터 발생된 웹 훅에 의해 빌드를 할 것이기 때문.

 

빌드 환경부터는 입 맛대로 하면 될 것 같다.

 

간단하게 node와 npm 커맨드라인디 동작하는지 테스트 해보고 typescript NodeJS 웹 애플리케이션의 테스트 스크립트를 동작시킨 후 javascript로 트랜스파일 해보는 과정을 해보도록 할 것이다. 

 

그래서 빌드 환경Provide Node & npm bin/folder to PATH를 선택해서 진행할 예정이다. 만약 이 빌드 환경이 없다면 플러그 인에서 nodejs를 다운 받고, nodejs를 사용하도록 설정해줘야 한다.

 

Build 에서 Execute shell을 선택했다.

 

echo $PATH
node --version
npm --version
npm install
npm test
npm run build

 

젠킨스에 빌드 설정을 저장한 후, 소스 코드를 작성하고 깃헙의 master branch에 push를 해보자.

 

소스 코드 작성 후 push

 

깃헙에 소스 코드 내용 작성은 생략한다. 아까 예로 들었던,git@github.com:i-kay/build-test-1.git 주소의 소스 코드를 로컬에서 clone(또는 pull)하고 수정 후 push 해보자.

 

참고로, package.json은 아래와 같고 scripts를 보면 알겠지만 test, build 등의 npm 스크립트가 준비되어 있다.

{
    "name": "build-test-1",
    "version": "1.0.0",
    "description": "",
    "main": "dist/index.js",
    "scripts": {
        "test": "jest",
        "start:dev": "ts-node src/index.ts",
        "build": "tsc"
    },
    
    ...
    
    "devDependencies": {
        "@types/jest": "^25.2.1",
        "@types/koa": "^2.11.3",
        "@types/node": "^13.13.1",
        "jest": "^25.4.0",
        "prettier": "^2.0.4",
        "ts-jest": "^25.4.0",
        "ts-node": "^8.9.0",
        "typescript": "^3.8.3"
    },
    "dependencies": {
        "koa": "^2.11.0"
    }
  }

 

소스 코드를 적당히 수정하고 master에 push를 해보자. 나는 test 코드를 몇 줄 작성해서 저장, 커밋 후 push했다.

// src/test.ts
describe('add', () => {
    test('1+1=2', () => {
        expect(1 + 1).toBe(2);
    });
    test('1+2=3', () => {
        expect(1 + 2).toBe(3);
    });
    test('1+3=4', () => {
        expect(1 + 3).toBe(4);
    });
});

 

$ git add .

$ git commit -m "write test code"

$ git log

commit 7bc5db886666e93c7cc9a2e808db9aba75bccff1 (HEAD -> master)
Author: 황규순 (Kay) <ks.hwang@ecubelabs.com>
Date:   Wed Apr 22 00:37:48 2020 +0900

    write test code

$ git push

Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 4 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 404 bytes | 404.00 KiB/s, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To github.com:i-kay/build-test-1.git
   5a5feef..7bc5db8  master -> master

 

그러면 젠킨스가 빌드를 시작하게되고, 빌드 잡의 Console Output에서 다음과 같이 위에서 정의한 빌드 스크립트가 정상적으로 동작했음을 확인할 수 있다.

 

Started by GitHub push by i-kay
Running as SYSTEM
Building in workspace /var/jenkins_home/workspace/build-test-1
using credential github-jenkins
Cloning the remote Git repository
Cloning repository git@github.com:i-kay/build-test-1.git
 > git init /var/jenkins_home/workspace/build-test-1 # timeout=10
Fetching upstream changes from git@github.com:i-kay/build-test-1.git
 > git --version # timeout=10
using GIT_SSH to set credentials 
 > git fetch --tags --progress -- git@github.com:i-kay/build-test-1.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git config remote.origin.url git@github.com:i-kay/build-test-1.git # timeout=10
 > git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git config remote.origin.url git@github.com:i-kay/build-test-1.git # timeout=10
Fetching upstream changes from git@github.com:i-kay/build-test-1.git
using GIT_SSH to set credentials 
 > git fetch --tags --progress -- git@github.com:i-kay/build-test-1.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git rev-parse refs/remotes/origin/master^{commit} # timeout=10
 > git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
Checking out Revision 7bc5db886666e93c7cc9a2e808db9aba75bccff1 (refs/remotes/origin/master)
 > git config core.sparsecheckout # timeout=10
 > git checkout -f 7bc5db886666e93c7cc9a2e808db9aba75bccff1 # timeout=10
Commit message: "write test code"
First time build. Skipping changelog.
[build-test-1] $ /bin/sh -xe /tmp/jenkins8028217650682187447.sh
+ echo /var/jenkins_home/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs12/bin:/usr/local/openjdk-8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
/var/jenkins_home/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/nodejs12/bin:/usr/local/openjdk-8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+ node --version
v12.16.2
+ npm --version
6.14.4
+ npm install
npm WARN build-test-1@1.0.0 No description
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.2 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

added 568 packages from 432 contributors and audited 258251 packages in 33.107s
12 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

+ npm test
> build-test-1@1.0.0 test /var/jenkins_home/workspace/build-test-1
> jest

PASS src/test.ts
  add
    ✓ 1+1=2 (8ms)
    ✓ 1+2=3
    ✓ 1+3=4 (1ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        3.89s
Ran all test suites.
+ npm run build
> build-test-1@1.0.0 build /var/jenkins_home/workspace/build-test-1
> tsc

Finished: SUCCESS

결론

CI/CD 기본이 되는 젠킨스와 깃헙을 연동해봤다. 다음 번에는 좀 더 실용적인 예제인 NodeJS 앱을 도커라이징 한 후 kubenates에 배포하는 시나리오를 포스팅 할 예정이다.

 

참고

[1] https://help.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent

[2] https://jenkins.io/doc/

반응형

'CI-CD' 카테고리의 다른 글

젠킨스(Jenkins) 설치하기(with Nginx on Docker container)  (3) 2019.12.22