Jenkins 설치법에 이어 CI/CD 하기 위해 Jenkins 사용 법을 차근차근 정리할 예정이다. 이번에는 가장 기본인 github에 소스 코드가 push되면 Jenkins가 webhook으로 그것을 받아서 빌드, 테스트 등의 스크립트를 실행하는 방법에 대해 정리한다. 앞으로 NodeJS를 CI/CD하는 방법을 앞으로 정리할 예정이다.
깃헙(Github) 웹훅 키 발급
깃헙 오른쪽 상단 [ 프로필 > Settings > Developer settings > Personal access tokens ] 에서 Generate new token을 눌러서 웹훅 토큰을 생성한다. 이때, Note에는 적당히 이름을 넣어주고 repo와 admin:repo_hook에 대한 권한을 준다. 생성된 토큰은 한 번만 볼 수 있으니 잘 메모해두자.
젠킨스 웹훅(Jenkins Webhook) 설정
젠킨스 홈 화면에서 [ Jekins 관리 > 시스템 설정 > Github ] 에서 GitHub Server를 설정한다.
Name은 적당히 입력한다.
API URL은 https://api.github.com 으로 일단 그대로 둔다. Enterprise로 사용하려면 API endpoint를 다르게 설정할 수 있는 것으로 보이는데 필요하면 그때 설정하도록 한다.
Credentials에 위 깃헙 웹훅 키를 발급 받은 것을 입력해야 한다. add를 누르고 키를 추가 하는 화면에서 kind는 secret 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 Path 에 Jenkinsfile (빌드 명령어가 명시된 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에 배포하는 시나리오를 포스팅 할 예정이다.
참고
'CI-CD' 카테고리의 다른 글
젠킨스(Jenkins) 설치하기(with Nginx on Docker container) (3) | 2019.12.22 |
---|