[Webhook] Github Webhook을 통한 빌드/배포 자동화[완]
배포 사전 준비
배포를 하는 방법에는 여러가지가 있을 수 있다. 가령 웹어플리케이션을 배포하려하고, Container 이미지를 이용한다면 Build 된 WAS 파일과 Dockerfile 을 작성해야한다. 이 경우 Jenkins에서 Docker Plugin 을 추가 설치하여 스크립트를 작성할 수 있다.
여기서는 간단하게 SSH Agent 를 이용하여 WAS가 구동중인 서버에 빌드된 스프링부트 어플리케이션 JAR 파일을 전송하는 것 까지만 진행한다. 개인 홈페이지가 도커로 구동되고는 있으나 임베디드 시스템 방식이라 Docker 이미지가 커지면 부트 타임이 길어져 실행 환경까지만 구축해두고 파일을 직접 Volume으로 연결해 구동하고 있다.
build.gradle 수정
...
#Before
version = "0.0.1-SNAPSHOT"
#After
version = System.getenv("APP_VERSION")
...
생성되는 파일의 버전명을 자동으로 붙여주기 위함이다.
Webhook 신규 생성 및 Jenkins 설정
- 신규 Jenkins 파이프라인 생성 -> Post 변수 생성
- Variable name : action, Expression : $.action
- Variable name : version, Expression : $.release.tag_name
- Optional
- Expression : ^(published:v*), Text : $$action:$version
- Github에서 Webhook 생성 -> release 일때만 발생하도록 설정
위 Jenkins Post content variables 설정은 release 가 published 되었을 때 v.. 등의 형식으로 생성된 tag 에 대해서만 파이프라인을 트리거 하기 위함이다.
SSH Agent Plugin
SSH Agent Plugin 은 Jenkins에서 ssh를 이용하게 해주는 Plugin 이다. 아래의 경로를 따라 들어가 설치한다. Manage Jenkins -> Plugins -> Available Plugins -> SSH Agent
SSH Keypair 생성
SSH Agent 를 사용하기 위해서는 공개키/개인키 방식을 통한 접근만 허용한다. 따라서 ssh-keygen 을 이용한 공개키/비밀키 생성이 필요하다. 여기서 공개키는 접속 대상이 되는 그러니까 서버로 이용되는 머신에 저장하고, 개인키는 Jenkins에서 소유한다.
## SSH Keypair 생성
$ ssh-keygen -t rsa -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key ($HOME/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in $HOME/.ssh/id_rsa
Your public key has been saved in /Users/terrapin/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:[Protected]
그리고 Jenkins의 홈 디렉토리를 찾아 들어간다. MacOS의 경우 brew를 통해 사용자 권한 서비스를 실행시킨 경우라면 유저의 홈 디렉토리에 있는 .jenkins 가 Jenkins의 홈 디렉토리이다. 리눅스의 경우 직접 설치한 경우라면 기본 /var/lib/jenkins 가 홈 디렉토리이고 변경 가능하다. Docker로 구동한 경우 /home/jenkins 일 것이다.
여기에 .ssh 디렉토리를 생성하고 그 안에 방금 생성된 키들을 적절한 이름을 붙여 이동한다. 위의 예제 Shell Command를 입력했다면 $HOME/.ssh에 id_rsa 라는 이름으로 생성되어있다.
$ mkdir .jenkins/ssh
$ mv $HOME/.ssh/id_rsa jenkins_ssh
$ mv $HOME/.ssh/id_rsa.pub jenkins_ssh.pub
$ ssh-copy-id -i $HOME/.jenkins/jenkins_ssh.pub <사용자 명>@<서버 호스트>
이제 개인키를 이용하여 서버에 접근이 가능할 것이다. 테스트를 해보자
$ ssh -i $HOME/.jenkins/jenkins_ssh <사용자명>@<서버 호스트> ls
bin
dev
etc
init
lib
lib64
libexec
linuxrc
media
mnt
opt
proc
root
run
sbin
sys
tmp
usr
var
정상적으로 접근이 된다면, Jenkins에서 credentials를 생성해주자.
- Manage Jenkins -> Credentials -> Add Credential -> SSH username with private key 를 선택
- ID를 입력하고, Keypair 생성 단계에서 Passphrase 를 입력했다면 그 부분도 작성해준다.
- Private Key를 선택하고 Enter Directly 를 선택한 뒤 생성한 개인키의 파일 내용을 복사해서 붙여넣기 한다.
- 저장
이제 파이프라인에서 테스트를 해볼 차례다.
Jenkins pipeline
우선 SSH Agent를 이용하여 서버 머신에 접근이 가능한지 확인을 해보자
pipeline {
agent any
stages {
stage("SSH Agent") {
steps {
sshagent(credentials: ['<ssh_private_key_credentials_id>']) {
sh '''ssh -o StrictHostKeyChecking=no <username>@<host> "pwd"'''
}
}
}
}
}
정상적으로 서버의 사용자 홈 디렉토리 경로가 출력될것이다.
이제 배포를 위한 스크립트를 작성해보자
pipeline {
agent any
environment {
app_name='demo'
APP_VERSION=$version
server_host=credentials('server_host')
}
stages {
stage('Checkout') {
steps {
checkout changelog: false,
poll: false,
scm: scmGit(
branches: [[name: 'refs/tags/$version']],
extensions: [],
userRemoteConfigs: [[url: 'https://github.com/dhkim92-dev/multibranch-test.git']])
}
}
stage('Build') {
steps {
sh '''./gradlew clean compileKotlin'''
sh '''./gradlew bootJar'''
}
}
stage('Deploy') {
steps {
sshagent(credentials: ['<ssh_private_key_credentials_id>']) {
sh '''scp build/libs/$app_name-$version.jar <server_host>:<path/to/jarfile>
}
}
}
}
post {
...
}
}
위 스크립트를 작성한 뒤 Github에서 release를 생성한다.
결과




이러한 과정을 통해 배포를 할 수 있다.
후기
회사에서 Jenkins를 이용하여 진행중이던 프로젝트 중 하나를 자동화 했었는데, 기록으로 남겨두질 않아서 간소화한 시나리오를 작성해서 내용을 정리해보았다. Upstream/Downstream을 다루지는 않았지만 파이프라인의 내용을 세분화 시켜서 일종의 모듈화를 시킬 수 있고, Jenkinsfile 또한 형상 관리를 할 수 있다. 또한 공통적으로 사용되는 부분들을 Library화 해서 @Library 등을 이용해서 파이프라인에서 사용할 수 있다.
전체적으로 빠진 내용이 많지만 한번 세팅하고 거의 수정할 일이 없다보니 기억에서 지워진 부분이 많아 다시 정리를 했다. 항상 정리하는 습관을 들이는게 좋을것 같다.