Jenkins with Node

THXX·2023년 10월 6일
0

Jenkins with Node.js Project

기존에 있던 Node 기반의 API 서버 프로젝트에 CI/CD를 적용시켜 보았다. 많은 삽질이 있었으나 아무튼 기분 좋은 결과가 있었던 것 같아 성취감이 들었다.
GitHub 상의 소스코드 변동을 감지하면, 즉시 pull하고 사용된 모듈을 다운로드 및 설치하며(npm install) 백그라운드 상에 데몬 프로그램으로 돌아갈 수 있도록 했다.

준비한 것

  • Jenkins Tool 설정
  • Jenkins Config File Provider 설정
  • PM2
  • GitHub WebHook 설정
  • Jenkins Job 설정
  • Node(Agent) 설정

Jenkins Tool

여기서 Tool은 빌드에 사용되는 도구를 의미한다. 우리는 Node를 사용할 것이므로, Jenkins가 Node 환경을 사용할 수 있도록 Tool을 추가해줘야 한다.

  1. Jenkins 관리 > Tools > NodeJS Installations

위와 같이 설정하고 Save를 누르면 끝이다. Add NodeJS를 눌러 여러 버전의 Node 환경을 취급할 수 있다.

Config File Provider

아직까지도 많은 사람들이 dotenv를 사용할 것이라고 믿어 의심치 않는다. 이는 .env 파일에 담긴 비밀 정보(DB 접속 정보 및 여러 Secret)를 스크립트가 실행될 때 환경변수로 가져오는 역할을 한다. 내 프로젝트 역시 dotenv를 사용하고 있었으므로, 이를 Jenkins job에 적용해줄 필요가 있었다.

  1. Jenkins 관리 > Managed files
    기본적으로 "Config File Provider Plugin"이라는 플러그인이 설치되어 있을 것이다. (아니라면 설치) 그렇다면 아래와 같이 파일을 관리하는 페이지에 접근할 수 있다.
    새로운 설정 파일을 만들 것이므로 Add a new config 버튼을 클릭한다.

  2. Custom file을 선택
    .env 파일은 기본적으로 텍스트파일이므로 Custom file 옵션을 선택한다.
    ID는 알아서 정해지니 바로 Next 버튼을 눌러 진행한다.

  3. 이제 Config File의 Name과 Comment, Content를 임의로 설정한다.
    이름과 설명, 그리고 텍스트파일 내용을 입력하는 것이다.

    대충 이런 식이 될 것이다. 여기까지 했다면 Config File의 준비는 완료된다.

PM2

PM2란? Node 기반의 프로젝트의 프로세스를 관리하는 시스템 전역적으로 사용하는 프로그램이다.
npm install -g PM2로 설치할 수 있다.
PM2는 name 기반으로 프로젝트의 프로세스들을 관리할 수 있다. 여러 개의 인스턴스를 만들어서 로드 밸런싱을 위한 기능도 마련되어 있다. (clustering mode) 우리는 일반 모드(fork)를 사용할 것이다.

사용할 PM2 명령어는 다음과 같다.

pm2 ls 										// 프로세스 목록 확인
pm2 start src/app.js --name TrainAPI		// TrainAPI라는 이름으로 프로세스 생성
pm2 restart TrainAPI --update-env			// TrainAPI라는 이름을 가진 프로세스 전부 재시작, 환경변수 업데이트

아래 --update-env를 넣는데에 실패한다면 .env 파일을 업데이트했을 때 변경사항이 적용되지 않는다.

pm2 ls의 예시다. 이쁘게 표로 잘 나온다.

GitHub Webhook 설정

Jenkins에 추가하고 싶은 GitHub 리포지터리의 설정에 들어가야 한다.

Webhooks 라고 보일 것이다. 클릭한다. 왼쪽 위의 Add webhook라는 버튼을 클릭한다. Webhook 추가에는 sudo mode에 들어갈 필요가 있으므로 github 비밀번호를 요구할 것이다. 알아서 잘 처리한다.

위와 같이 설정하면 된다. Jenkins를 HTTPS로 서비스하고 있다면 Secret과 SSL Verification이 나오지만, HTTP로 서비스하고 있다면 나오지 않는다.

매우 주의해야 할 점은, github-webhook 뒤에 무조건 /를 붙여야 한다. 이에 실패할 시 웹훅이 Jenkins에 전달되지 못한다.

최종적으로 Add webhook 버튼을 누르면 GitHub Webhook의 준비는 완료된다.

Jenkins Job 설정

이제 몸통을 완성할 때다. Job을 만듬으로써 비로소 Jenkins가 일을 할 수 있게 된다.

Freestyle project로 만들어줄 것이다. 사실 Pipeline을 도전하려고 했으나, 뭔가 잘 안되서 접었다. 다시 하면 될 것 같긴 한데, 굳이 Pipeline으로 나눌 그러한 단계들이 보이지 않기 때문에 일단 Freestyle로 결정했다.

이러면 즉시 Job이 생성되고, 세부 설정 페이지로 진입한다.

GitHub project를 선택해준다. 이를 선택하면 Jenkins job에 GitHub Repository로 가는 링크 버튼이 만들어진다.

그 다음 소스 코드 관리에서 Git을 선택하고, Repository 주소와 Credentials를 선택한다.

처음 Job을 생성할 경우 Credentials이 없을 것이다. 다음과 같이 설정한다.

  1. Add -> Jenkins

  2. Username: github 유저명, Password: Personal Access Token

Personal Access Token은 github 계정 설정 > Developer Settings > Personal access tokens 에서 발급받을 수 있다.
Generate new token (classic) 을 선택하고, 아래와 같이 토큰에 권한을 할당하면 된다.

이제 토큰을 Password에 넣으면 된다.

Credentials도 준비가 되면 아래와 같은 Repository URL 밑에 뜨던 빨간색 오류들이 없어질 것이다.

이제 빌드를 어떻게 유발할 지 설정해준다.

우리는 GitHub WebHook을 사용하기로 결정했다. 해당 옵션을 선택해줬다.

빌드 환경에 대해서 설정해준다.

우리는 이미 사용할 .env 파일에 대해서 설정을 해놨었으므로, Provide Configuration Files 옵션을 체크하고 만들어 놨던 파일을 선택한다.
Target은 작업 공간(workspace)에서 어디에 설정 파일이 위치할지 결정한다. 저렇게 써놓으면 workspace의 root에 .env 파일로 저장될 것이다.
Variable은 그냥 설명이다. 어떤 환경변수를 설정하고 있는 지 사람이 알기 쉽게 적어놓는 공간이다.

Console Output에 시간이 적혀 있는 것이 좋을테니까 해당 옵션을 선택해주고, Node 환경을 사용할 것이므로 해당 옵션을 선택해준다. 만들어놨던 Tool이 보일 것이다. 선택해준다. 이 옵션을 이용하여 어떤 노드 환경을 사용할 지 결정할 수 있다.

최종적으로 중요한 Build Steps를 결정할 차례이다.

npm 및 pm2 명령어를 직접 실행할 것이므로, Execute Shell 옵션을 선택하고 아래와 같이 작성했다.

이러면 끝이다! 가 아니다.


문제에 봉착했었다. 지금 나의 Jenkins 환경은 Docker에서 돌아가고 있었고, 그의 Built-in Node는 Docker 환경이나 마찬가지였다. 나는 그곳에 내 프로젝트가 돌아가길 원치 않았다. 따라서 Docker 바깥에서 빌드가 실행되어야만 했다. 그 방법은 Agent를 설정하는 것이다. 허접하지만 아래의 그림을 보도록 하자.

원래는 이러면 안된다. Jenkins를 서비스하는 머신(Controller)과 빌드가 이뤄지는 머신(Agent)은 달라야 한다. 보안상 이유 때문이다. 그러나 나에겐 머신이 없어서, 어쩔 수 없이 Jenkins를 Docker로 돌리고 있는 Ubuntu 운영체제 상에 Jenkins 유저를 생성하고 거기에 SSH로 연결하여 그곳에 Agent를 만들기로 결정한 것이다.

굳이 인터넷을 안거쳐도 되긴 할 것 같은데 Docker의 네트워크 이용에 익숙치 않아 그냥 인터넷을 한 번 거치는 것으로 했다.

Jenkins Node(Agent) 설정

  1. Jenkins 관리 > Nodes 로 들어간다.

  2. 오른쪽 위 New Node 버튼을 클릭한다.

  3. 이름을 지어주고, Permanent Agent를 지정한다.

  1. Node 설정을 진행한다.
  • Name : 젠킨스 노드 이름
  • Description: 노드 설명
  • Number of executors: 해당 노드에서 동시에 실행될 수 있는 빌드의 수
  • Remote root directory: Jenkins가 사용할 원격지의 디렉토리 경로를 적어준다. 나는 jenkins라는 유저의 홈을 이용하기로 했으므로, /home/jenkins 로 설정해줬다.
  • Labels: 노드에 라벨을 붙여서 그룹화할 수 있다. 예를 들어 windows라는 label을 붙인 노드들은 그룹화되어 나중에 빌드할 때 이 라벨을 이용하여 그 그룹을 빌드에 사용할 수 있게 된다.
  • Usage: 해당 라벨이 지정되었을 때만 노드가 작동할 수 있게 설정할 수 있다. 나는 그렇게 쓰진 않을 것이므로, Use this node as much as possible 옵션을 사용한다.
  • Launch method: 노드가 실행되는 방법을 결정한다. 두 가지의 방법이 있는데, 나는 두 번째를 이용하기로 했다. (1. Controller를 이용하여 실행 2. SSH로 연결하여 실행)
  • Host/Credentials/Host Key Verification Strategy: SSH 옵션을 선택했을 경우 SSH 호스트와 계정 증명 정보를 제공해야 한다. Credentials는 위에서 만들어본 적 있으므로 생략한다. Host Key Verification Strategy에서 해당 키 증명 전략에 실패할 경우 접속이 되지 않으므로, 설명을 잘 읽어야 한다. 예를 들어, Known hosts file Verification Strategy의 경우, 일단 먼저 SSH로 해당 호스트에 접속한 적이 있어야 Known hosts file에 목록이 추가되므로, Docker commandline을 이용하여 ssh로 호스트에 접속한 기록을 만들기를 바란다.
  • Availability: 노드를 계속 가용할 수 있는 상태로 유지시킬지 결정하는 옵션이다. 작업이 있거나 일정에 맞춰서 노드를 킬 수도 있다.
  1. 새로운 Node 에 대한 설정이 완료되었으므로 기존 Built-in Node에 대해서 Usage 옵션을 두 번째 옵션으로 바꿔준다. 이제 명시적인 라벨로 Built-in Node를 호출하지 않는 이상 해당 노드가 사용될 일은 없다. 새로운 Node가 이제 사용될 수 있는 것이다.

PM2 사전 설정

일단 파일을 가져오기 위해서 만들어뒀던 Job에서 '지금 빌드'를 실행한다.

이것은 실패할 것이다. 왜냐면 아직 PM2 프로세스가 만들어지지도 않았는데 restart를 하기 때문이다. 따라서 먼저 Node(Agent)에 접속하여 pm2 start app.js --name [NAME] 명령을 실행해줘야 한다. 비로소 pm2 프로세스가 생성되었으니, 이제 Job의 Build step에 있던 명령들이 전부 잘 작동할 것이다.


결과

작업공간에 .env 파일도 잘 들어가있는 모습, 아주 좋다.

GitHub Hook Log의 모습이다. 제대로 push webhook를 받은 것을 확인할 수 있었다.

빌드 로그이다. 깔끔하게 재시작이 잘 되었다.

이제 Git 소스코드에 커밋하고 push하는 것만으로도 원격지 서버에서 자동적으로 pull하고, 배포된다. 원격지 환경을 계속해서 만져야 했던 나날들과는 다른 삶이 펼쳐지는 것이다. 이것을 내 서버에서 구축할 수 있어서 매우 기쁜 마음이다. GitHub Actions를 이용할 수 있었지만, 그냥 오기로 On-Premise CI/CD 서버를 구축해보고 싶었다. 잘 된 것 같아 기쁘다.

~完~

profile
THXX FOR EVERYTHING

0개의 댓글

관련 채용 정보