Jekyll Project에 CI 적용기

이 포스트는 MeuWorks 페이지에서도 확인할 수 있습니다.

문제

현재 당신이 보고 있는 MeuWorks의 사이트는, jekyll serve 기능을 이용해 작동하고 있었다. 그러나 이럴 경우, Jekyll의 프로세스가 죽으면 더 이상 사이트를 표시할 수 없다는 단점을 가지게 된다.

그래서 필자는 jekyll build 명령어를 이용해서 빌드된 사이트를 Nginx를 통해 바로 표시할 수 있게끔 방향을 틀었다.

근데 여기서 또다른 문제가 생겼다. 파일이 라이브로 업데이트 되지 않기 때문에 이 Jekyll 사이트에 포스트를 추가한 사람이 매번 Build 스크립트를 돌려주어야 한다는 것이다.

해결 전 두뇌 속 삽질

필자는 본 Jekyll 사이트의 소스 백업 목적으로 개설한 Git을 활용해보기로 했다.

Github, Gitlab 그리고 Bitbucket 같은 온라인 레포지터리 저장소들은, Webhook이라는 것을 지원한다.

본 사이트의 소스코드를 담고있는 1) Gitlab 저장소에 새로운 Commit이 Push되면, 2) Jekyll을 호스팅하는 서버에 이를 알리고 3) jekyll build 명령어를 이용하여 새로 서버를 빌드한다.

즉, 우리가 할 일은 그냥 _post 폴더에 게시글 작성하고 이를 깃에 추가하면 사이트가 자동으로 새로고침 되는 것이다!

구상도

data

해결 과정

1. Webhook 생성하기

Gitlab의 Jekyll 프로젝트에서 Webhook을 생성했다. 아래의 사진에도 나왔지만, Project - Settings - Intergration으로 가면 된다.

data1

URL은 이 Webhook을 받아 처리해야할 서버로 연결되는 URL 주소다.

새로운 커밋이 Push 되었을 때, 이를 알려주는 역할을 수행하면 되므로 Trigger에 Push events를 체크한다. 이 설정에 따라 새로운 커밋이 올라오면 Gitlab이 Webhook의 URL에 요청을 보낼 것이다.

필요한 설정을 한 뒤, Add webhook을 눌러 설정을 저장한다.

2. Webhook 핸들링

Gitlab에서 보낸 Webhook을 받아서 처리하는 부분을 만들어야한다.

자신이 주로 사용하는 웹 프레임워크를 이용하면 금방 만들 수 있을 것이라 생각한다.

핸들링을 위해 서버가 갖추어야 할 최소 요구조건을 정리해보았다.

1. POST 요청을 받아야한다.

2. 헤더의 x-gitlab-token이 서버 내에 정의된 토큰값과 일치하는지 확인해야한다.

3. 정의된 토큰값과 일치하면, Git 저장소를 pull 할 수 있는 함수와 빌드 함수를 실행할 수 있어야 한다.

필자가 추천하는 프레임워크는 node.js다. 위 링크를 타고 들어가면 보이는 스니펫을 조금만 수정한다면, 바로 서버 하나를 만들어낼 수 있다.

MeuWorks의 킹갓엠페러충무공마제스티제네럴디벨롭먼트마스터이신 Syr이 node.js를 기반으로 서버를 쉽게 만들어주셨다. 간단하게나마 소스코드를 참고하고 싶다면, 여기를 참조하라.

3. Node.js 서버 포트포워딩 및 테스트

포트포워딩을 설정하기 이전에 Syr이 알려준 아이디어로, ‘어차피 같은 로컬 네트워크 안에 있으니, URL을 로컬 주소로 설정하면 되지 않겠냐’ 라는 의견을 줬다.

그 방법이 더 안전할 것이라고 생각해서, Gitlab의 URL을 로컬주소로 바꾸고 테스트를 해보았는데 오류가 발생했다.

Gitlab::HTTP::BlockedUrlError (URL 'http://10.0.1.102:3001/push' is blocked: Requests to the local network are not allowed):
  lib/gitlab/proxy_http_connection_adapter.rb:17:in `rescue in connection'
  lib/gitlab/proxy_http_connection_adapter.rb:14:in `connection'
  ...
  (생략)

Requests to the local network are not allowed 즉, 로컬네트워크로 요청을 보내는 것이 허용되지 않았다. 라는 의미다.

그래서 그냥 포트포워딩을 이용해 Node.js가 사용하는 포트를 열어주기로 했다.

캡처1

설정 하나를 건드릴 때 마다 재시작을 요구하는 멋진 공유기를 통해 다운타임을 만들고, 설정을 끝냈다!

이제 테스트를 진행하자.

테스트를 위해 Syr가 만들어준 Node.js 프로젝트를 수정했다.

서버를 띄우고, Webhook 요청이 들어오면 echo "Hi!" 를 실행하도록 프로젝트 내의 config.json 파일을 수정했다.

이제, Gitlab의 Intergration 설정에서 Webhook을 테스트해보자.

위에서 Add한 웹훅은, 새롭게 Webhook을 만드는 곳 아래에 리스팅된다.

캡처3

오른쪽의 Test 버튼을 눌러 드롭다운 리스트를 열고, Push events를 눌러 테스트를 진행하자.

캡처2

Hook이 성공적으로 작동됐다는 알림이 나왔다! 이제, 서버의 출력에 “Hi!”가 나왔는지 확인해보자.

캡처4

Hi!

잘 작동된다!

4. Webhook 요청을 받았을 때, Jekyll 빌드 시키기

이제 Webhook을 받았을 때 실행되는 스크립트를 수정하고, 위의 Node.js 서버를 계속 구동시키면 우리가 원하던 구성을 만들 수 있다.

config.json 파일을 열어, 기존의 echo "Hi!"를 지우고, Jekyll을 업데이트 하고 빌드 할 스크립트로 대체했다.

### UPDATE_JEYKLL.sh
#1. Jekyll 폴더로 이동해야 한다.
cd /home/****/*****/****
#2. Jekyll 폴더 내의 파일들을 Git 저장소에서 Pull 해 업데이트 해야한다.
git pull
#3. Build된 파일들은 다른 위치에 저장되어야한다.
JEKYLL_ENV=production bundle exec jekyll build --destination /home/****/*****/

그리고 서버는, nohup npm run start &로 실행해서, 백그라운드에서 돌아가게끔 했다.

5. 실제로 잘 작동하는지 확인하기.

Git에 새로운 포스트(이 포스트)를 추가하고 추가 후 Push 한다면, MeuWorks 페이지의 모든 게시글에서 이 글을 확인할 수 있을 것이다.

이 글이 보인다면 성공!