본문 바로가기

Jenkins, Github Action으로 CI 환경 구축 경험기

공교롭게도 금주에 젠킨스와 Github Action으로 동시에 CI 환경을 구축할 일이 있었다.

 

사내 Github Enterprise에서는 아직 Github Action이 미지원이라 Jenkins를 사용했다.
기존에 사용하던 젠킨스가 있었지만 메모리 이슈가 잦아져, 우리 파트만 사용하는 Jenkins를 새롭게 구축하기로 했다.

(겸사겸사 물리 서버가 아닌 Docker 컨테이너 환경으로 이전도 포함)

 

Github Action은 사이드 프로젝트에서 새로 CI 설정을 위해 Github Action을 사용하기로 했다.

 

결론부터 말하면 젠킨스는 구축까지 대략 하루 걸리고, Github Action으로는 공부시간 포함 1시간 정도 걸렸다.

이건 젠킨스보다 Github Action이 쉽고 빠른 점도 있었지만
사내 망분리 환경으로 인해 플러그인 사용이 제한되면서 삽질한 시간도 있어서 더 오래 걸린것 같다ㅠㅠ

 

Jenkins와 Github Action의 자세한 비교는 아래 글을 참고하자.

[CI/CD] Jenkins 과 GitHub Actions의 개념, 차이점

 

어떻게 구축했는지 그 과정을 정리하였다.

 

Jenkins CI 설정 과정

 

1. Jenkins 설치

사내 클라우드 서비스에서 Jenkins CR을 제공하여 손쉽게 설치할 수 있었다.

 

2. Authentication

현재는 사내 계정으로 접속하면 누구나 접근가능하도록 되어있다.

그런데 이걸 추후에 Github Authentication으로 바꾸고, 우리 팀 Organization으로 들어올 수 있도록 수정해야 한다.

 

이슈는 기본 내장 플러그인에 GitHub Authentication 플러그인이 없어서 hpi 파일로 설치해야 한다.

그런데 설치하기 위해 필요한 deps가 너무 많아서 당장은 실패했다..

 

3. Github Pull Request Builder

Github의 event로 Job을 실행할 수 있도록 지원하는 플러그인 중 기본 내장되어 있는 Github Pull Request Builder을 사용하였다.

 

설정 방법은 매우 간단했는데, 먼저 Auth 설정 중 Github Server API URL에 https://{GITHUB 주소}/api 와 같이 서버 API URL을 입력한다.

Credential은 Github Personal Access Token을 활용하여 등록한다.

 

 

4. Item 생성 및 CI 생성

새로운 Item 을 등록하고, 'Project url'에 Job을 실행할 Repository URL을 입력한다.

 

구성 ▶︎ [소스코드관리] 에서 'Git'을 체크하면 Repository URL과 Credential을 입력해야 한다. 여기서 위에서 했던 방식대로 Github Token을 활용할 수도 있지만, 나는 젠킨스 서버에서 ssh 생성 후 해당 정보를 repository에 등록하여 사용하였다.

 

SSH Credential 생성

새로운 Item  ▶︎ 'create ssh credential' 생성 후, Build ▶︎ Execute Shell 클릭 후 다음 커맨드 실행

PATH-TO-HOME 은 젠킨스가 설치된 컨테이너에서 pwd 로 확인하여 내 경로에 맞게 입력한다.

rm -f {PATH-TO-HOME}/.ssh/id_rsa*
ssh-keygen -b 2048 -t rsa -f {PATH TO HOME}/.ssh/id_rsa -q -N ""
cat {PATH-TO-HOME}/.ssh/id_rsa.pub
cat {PATH-TO-HOME}/.ssh/id_rsa

 

빌드 후 Console Output에서 보이는 ssh 정보 중

id_rsa.pub 는 Github Repository의 Settings ▶︎ Deploy Key에 등록

id_rsa는 Jenkins의 Credential 로 입력한다.

 

ssh credential 생성과 관련하여 자세한 글은 이 글을 참고하였다.

[Jenkins] 5. SSH Private key를 이용한 Credentials 설정 추가하기

 

제대로 설정했다면 붉은색 Connect 오류가 뜨지 않을 것이다.

 

Repository를 정상적으로 연결했다면 [빌드 유발]에서 Github Pull Request Builder를 체크하고, 전에 등록한 Github API URL을 API Credential에 연동한다. Admin list에는 CI 빌드를 트리거할 계정들을 입력한다.

 

 

우측 하단 (고급) 탭에서는 Trigger Phrase를 입력할 수 있는데, PR에서 재빌드하고 싶을 때 입력할 문구 및 설정을 정의할 수 있다.

바로 아래의 (Trigger Setup) 에서는 빌드명과 빌드 성공/실패/에러 에 대해 Github 에서 보이는 문구 등을 정의할 수 있다.

 

[Build]에서 실행할 Job을 정의하면 된다. 린트 설정을 예로 들면, Execute Shell을 클릭한 후, 린트 실행 커맨드를 입력한다.

npm ci
npm run lint
npm run prettier

 

정상적으로 CI 환경 설정이 끝났다면 Github에서 새로운 PR을 생성해보면 빌드 Job이 실행됨을 확인할 수 있다.

그런데 여기까지 진행했을 때 빌드는 무조건 실패한다. NodeJS 설치를 누락했기 때문이다.

 

5. NodeJS 설치

처음엔 권장하는 방식대로 NodeJS 플러그인을 사용하려 했다.

그런데 사내 망분리 환경으로 인해 nodejs.org 에 접근할 수 없어서 NodeJS를 자동으로 설치할 수 없었다 😭

(여기서 시간을 잡아먹게 되었다...)

 

NodeJS 바이너리 파일이 있는 path를 연결하는 등 이것저것 별짓을 다하다가 결국은 컨테이너에 직접 접속해서 NodeJS를 설치하였다.

방법은 이렇다.

 

먼저 젠킨스 서버 내 userContent/에 NodeJS 압축파일을 다운받는다.

파일을 지정한 위치에 압축해제하고, 설치한 위치를 PATH 환경변수로 .bashrc에 등록하고 export한다.

(버전 관리가 어렵게 되었지만 어쩔 수 없었다ㅠㅠ)

 

이러면 끝...!일줄 알았는데 왠걸 환경변수 설정이 Job에는 적용이 되지 않아 NodeJS가 실행되지 않았다.

젠킨스 빌드에서 실행하는 job에 대한 PATH 설정은 .bash_profile(.bashrc)에 설정해도 사용이 되지 않았기 때문이었다..

Jenkins agent(slave) 환경 변수 사용

 

따라서 Jenkins 관리 ▶︎ 노드 관리 의 master 노드에 PATH 환경 변수를 등록해주었다.

 

(참고) userContent에 파일을 업로드하는 Item을 생성하여 진행하면 더 쉽고, 앞으로 userContent에 파일을 업로드하고 싶을 때에도 유용하다.

userContent에 파일을 업로드하는 Item 생성

매개변수로 파일이름(FILE_NAME), 파일(tmpFile), 액션(ACTION, 생성/삭제)을 등록하면 [Build] ▶︎ 'Execute Shell' 에서 매개변수 이름대로 환경변수를 사용할 수 있게 된다.

$FILE_NAME
$tmpFile
$ACTION

따라서 아래 명령어를 입력하여 파일을 userContent/ 로 옮긴다.

[[ -z "$FILE_NAME" ]] && { echo "FILE_NAME is required" ; exit 1; }

if [ "$ACTION" == "UPLOAD" ]; then
  FILE=tmpFile
  [[ ! -f "$FILE" ]] && { echo "The file does not exist" ; exit 1; }
  mv $FILE $JENKINS_HOME/userContent/$FILE_NAME
else
  [[ $FILE_NAME == *"-rf"* ]] && { echo "'-rf' cannot be included in the FILE_NAME" ; exit 1; }
  rm $JENKINS_HOME/userContent/$FILE_NAME
fi

 

그리고, userContent 목록은 왼쪽 사이드바에서 기본적으로 보이지 않으므로 아래 글을 참고하여 등록한다.

Jenkins에서 왼쪽메뉴 (Left Sidebar) 추가 방법

 

이제 NodeJS도 설치되었으니, Job에 등록했던 npm 명령어가 정상적으로 동작할 것이다.

 

Github Action CI 설정 과정

Github Action은 Github에서 제공하는 워크플로우 자동화 도구로, yaml 로 손쉽게 job을 설정할 수 있었다.

 

기본 용어를 알아야 진행이 가능해서 정리했다.

더보기
  • Workflow : 자동화된 프로세스로, 여러 개의 Job으로 구성되고 Event에 의해 트리거됨.
    .github/workflows 에 추가
  • Event : Workflow를 트리거하는 특정 활동(규칙), PR 생성, push 등. (전체 규칙)
  • Job : workflow 내 가상의 인스턴스에서 실행하는 step들의 집합. 병렬 실행 및 종속적으로 실행하는 것 또한 가능.
  • Steps : Job 내부에서 실행하는 커맨드 혹은 Action. 동일한 Job에서의 step들은 내부 데이터를 공유할 수 있음.
  • Action : 최소 Workflow building block 단위로 step에 결합되는 독립적인 커맨드. 반드시 step에 위치.
  • Runner : Workflow가 실행될 인스턴스

 

다음은 prettier와 lint를 체크하는 간단한 스크립트 예시이다.

 

 

 

 

상세 설명

on:
  pull_request:
    branches: [develop]

on 커맨드는 Event에 해당한다.  타겟브랜치를 develop으로 하여 PR을 생성할 때 Workflow가 트리거된다.

 

jobs:
  check: # job id
    name: Prettier & Lint Check
    runs-on: ubuntu-latest # job 가상 인스턴스

Job 설정 부분으로, job이 실행될 가상의 인스턴스를 설정할 수 있다.

 

    steps:
      - name: Check out Git repository
        uses: actions/checkout@v2

      - name: Set up Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 16

      - name: Install packages
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Prettier
        run: npm run prettier --if-present

 

step들을 정의한다. uses 는 Action을 사용한 부분으로, Github에서 제공하는 Actions이나 마켓플레이스에서 검색 가능하다.

run 커맨드는 액션에 없는 커스텀 실행을 하고 싶을 때 사용한다. 

 

나는 아주 간단하게 사용했지만 CD에서 사용하는 예시를 보면서 자동배포에 대해 공부해야 겠다.

참고 : AWS S3에 배포하는 예제코드

 

느낀 점 및 TODO

 

비슷한 시간에 비슷한 작업을 두 개의 도구로 설정해보았다.

젠킨스는 플러그인 설치 및 GUI로 입력해야 할 사항들이 많았던 반면, Github Action은 전적으로 스크립트로 관리 가능했다.

 

어떤게 더 낫다고 단정하긴 어렵지만 CI/CD 관리만큼은 코드로 보는게 익숙한 개발자들에게는 Github Action이 더 편하게 와닿을 수도 있겠다. 또한 사이드 프로젝트처럼 작은 규모의 프로젝트에서 젠킨스 설치는 상대적으로 비용이 크게 느껴지기도 한다.

 

이번주에 써보진 못했지만 젠킨스 또한 등록한 Job들에 대한 연속적인(혹은 병렬적인) 실행이 가능하다. 파이프라인이 이것을 가능하게 해주는데 파이프라인을 통해 자동 배포를 구성할 수 있다. 파이프라인을 손쉽게 생성할 수 있도록 도와주는 BlueOcean 플러그인 또한 보았는데 역시나 망분리 환경으로 인해 설치가 녹록치 않아보였다ㅠㅠ

 

다음주에 E2E 환경을 구축하고, 이를 CI에 등록해보려 한다. (testcafe 혹은 Cypress 👀) 젠킨스에서는 BrowserStack이라는 플러그인으로 웹/모바일 디바이스에서 테스트하는 것과 동일한 환경을 제공할 수 있다고 하는데 테스트 CI를 구축하면서 사용해보려 한다.

BrowserStack gives instant access to 2000+ real mobile devices and browsers that enables developers to test their websites and mobile applications without requiring to install or maintain an internal lab of virtual machines, devices, or emulators.

역시나 망분리 환경때문에... 플러그인 설치에 애먹을까봐 걱정이다 ㅠㅠ