Jenkins
수정·

[Webhook] Github Webhook을 통한 빌드/배포 자동화[완]

by Dohoon Kim · 23년 08월 24일 09:00:00

배포 사전 준비

배포를 하는 방법에는 여러가지가 있을 수 있다. 가령 웹어플리케이션을 배포하려하고, 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를 생성해주자.

  1. Manage Jenkins -> Credentials -> Add Credential -> SSH username with private key 를 선택
  2. ID를 입력하고, Keypair 생성 단계에서 Passphrase 를 입력했다면 그 부분도 작성해준다.
  3. Private Key를 선택하고 Enter Directly 를 선택한 뒤 생성한 개인키의 파일 내용을 복사해서 붙여넣기 한다.
  4. 저장

이제 파이프라인에서 테스트를 해볼 차례다.

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를 생성한다.

결과

imageURL

imageURL

imageURL

imageURL

이러한 과정을 통해 배포를 할 수 있다.

후기

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

전체적으로 빠진 내용이 많지만 한번 세팅하고 거의 수정할 일이 없다보니 기억에서 지워진 부분이 많아 다시 정리를 했다. 항상 정리하는 습관을 들이는게 좋을것 같다.