GitHub과 CircleCI를 활용한 자동배포

github circleci docker

기술블로그를 오픈하고, 그래도 대장으로써 뭔가를 쓰긴 써야되는데 이왕이면 재미있는걸로 하고싶어서 그 첫번째 주제에 대해 많은 고민을 했었다.

그러던 와중에, 이 분야에 많은 영감을 준 Wake.Alan의 도움으로, 흔한 개발자라면 누구라도 할 고민인 소스를 빌드하고 배포하는 작업에 대해, 매우 효율적으로 처리할 수 있는 솔루션인 CircleCI에 대한 조사를 진행하고 그 것을 첫번째 포스트로 다뤄볼까 한다.

Overview

  1. CircleCI에 대해 알아본다
  2. 지속적인 배포 (Continuous Deploy)
  3. 배포 시나리오 작성
  4. CircleCI 가입 및 프로젝트 연결
  5. Job workflow작성

1. CircleCI에 대해 알아본다

CircleCI는 GitHub 혹은 BitBucket등의 Git형상관리 시스템에 소스를 이용하여 CI(Continuous Integration) / CD(Continuous Deploy)를 할 수 있도록 제공하는 서비스이다.
여기서 다룰 내용은 우리 회사같이 소기업이나 개인은 CI보다는 CD가 더 주된 목적이 될 것이고, 우리 회사는 Git형상관리로 GitHub을 사용 중이다. 그러므로, 이 포스트에서는 GitHub + CircleCI환경에서 자동 배포환경을 설정하는 것을 정리해보고자 한다.

2. 지속적인 배포 (Continuous Deploy)

소스코드를 배포한다는 것은 각각의 소스에 따라 다른 형태의 결과물을 만들어낸다. vue.js나 react등은 webpack을 통해 빌드한 결과물을 웹서버에 올려야 하고, node.js은 빌드할 필요는 없지만 package.json에 새로운 dependency가 발생했으면, 해당 내용이 반영을 위해 npm install을 실행해야 한다. 또한 node.js도 typescript을 사용했다면, 빌드하는 과정이 필요하다.
CircleCI는 소스의 통합과 배포과정을 실행 하기위해, docker기반의 가상화 OS를 실행시킬수 있는 리눅스 혹은 맥OS의 컨테이너를 랜탈해준다고 생각하는 것이 이해하기 쉽다. 그러므로, 뒤이어 나오는 jobs이나 workflow등의 역할은 이 렌탈한 리눅스 OR 맥OS 에서 내 작업물을 빌드하기 위해 하는 작업을 매크로 형태로 실행한다고 생각하면 된다. 참고로 CircleCI의 유료정책은 이 컴퓨팅 파워에 따라 올라간다고 생각하면 된다. CircleCI유료 정책

(2019-11-23 추가 - CircleCI에 유료 정책이 최근 변경되었는데, docker와 같은 가상머신을 빌드에 사용하는 경우 컴퓨팅파워가 늘었다고 판단하는건지 유료 사용자 아니면 빌드과정에서 실패하는 이슈가 있다. 이 때문에 새로 출시한 github action으로 갈아탈지 고민중이다. )

그럼 여기서 가상 시나리오를 하나 만든다. 프론트엔드 개발자가 만든 vue.js 소스 GitHub에 게시한 상태인데, 이를 받아서 배포 한다면 어떤 과정을 거쳐야 할까? 아마 다음과 같을 것이다.

1. git clone명령을 사용하여 소스를 받는다. (변경된 경우에는 git pull)
2. npm install을 실행하여 필요한 라이브러리를 받는다.
3. npm 명령으로 빌드한다.
4. 서버에 ssh등으로 연결한다.
5. 아파치나 nginx을 설치한다.
6. web소스 경로에 위에서 빌드한 소스를 scp등으로 복사한다.

이 프로젝트가 아직 진행 중인 프로젝트이고, 계속 커밋이 이루어 진다면 자주 반복될 작업이다.
5번 항목으로 서버가 설치된 경우에는 4, 5번은 생략이 가능하겠지만, 1,2,3,6은 자주 반복될 것이다. 예전과 다르게 요즘세상에는 HTML도 빌드를 해야 하는 세상이므로, 이런 일련의 작업들은 매우 귀찮게 느껴진다. CircleCI를 통한 자동 배포환경은 이런 귀찮은 작업들을 자동으로 실행해준다.

3. 배포 시나리오 작성

그럼 여기서 위에서 설정한 가상 시나리오 대로 진행중인 프로젝트의 빌드를 위한 쉘스크립트를 한번 만들어보자. 가상의 GitHub 프로젝트 주소는 bearkim36, 프로젝트는 myfirstci다. 웹서버는 리눅스 서버에 nginx로 설치되어 있다고 가정한다.

# 소스 내려받기
$ git clone https://github.com/bearkim36/myfirstci.git

# 소스폴더로 이동
$ cd myfirstci

# 의존성 설치
$ npm install

# 빌드
$ npm run build

# nginx 서버로 포팅 (참고로 이 접속정보는 없다.)
$ scp -r dist/. testuser@dkant.net:/usr/share/nginx/html/

로컬에서 혼자 개발한다면, 위 쉘스크립트를 한번씩 실행하면 별 문제가 안되지만 만약에 다수의 개발자와 동시에 개발한다면, 누가 배포할지가 애매하기 때문에 매번 배포 누가했냐고 묻는 상황을 마주하게된다. 빌드자동화를 쓰지 않은 경우에는 실무에서는 매우 흔한경우이다. 아니면 누군가가 push하고 몇 번 더 소스push가 이루어지고, 빌드하면서 에러가 났는데 누구 소스 때문인지 모른다거나… 이런 참사를 최대한 막아보기 위해 우리는 CircleCI를 사용한다.

CircleCI에서 수행할 빌드 작업은 GitHub의 형상관리에 새로운 commit이 push가 되었을 때 자동으로 CircleCI가 GitHub에서 hook하여 실행된다., 이와같은 배포 작업을 최신 소스로 대신 실행해주는 것이다.

4. CircleCI 가입 및 프로젝트 연결

CircleCI 웹사이트 위 사이트에 접속해서 우측의 상단의 SignUp 버튼을 선택한다.

CircleCI SignUp Page 여기서 Sign Up with GitHub를 선택한다.

CiecleCI Dashboard Page 로그인 후, CircleCI 대시보드에 진입하면 다음과 같은 화면이 나타난다. 좌측 중간에 ADD PROJECTS를 선택한다.

CiecleCI AddProject Page CircleCI와 연결할 GitHub 프로젝트 목록이 자동으로 표출된다. 연결할 프로젝트 우측의 Set Up Project 버튼을 선택한다.

CiecleCI Setup project Page 위 코드를 긁어서 myfirstci 프로젝트에 .ciecleci 폴더를 만들고, 그 안에 config.yml파일을 만들어서 붙여넣는다.
그리고 아래의 Start Building 버튼을 선택하면, CircleCI와 GitHub프로젝트의 연결이 완료되었다.

config.yml을 추가하고, GitHub에 소스를 푸시한다.

$ git add .circleci/.
$ git commit -m "CircleCI config 적용"
$ git push

CiecleCI job success 기본 값으로 넣은 config.yml의 workflog의 job이 성공적으로 실행된 것을 볼 수 있다.
여기의 내용은 일반적인 welcome 메시지이므로, 이제 본격적인 job workflow를 만들어보자.

5. Job workflow작성

CircleCI에서 하나의 단위 작업을 job이라 하고, job은 workflow로 구성된다. workflow는 위에 배포 시나리오에서 작성한 쉘스크립트를 단계별로 실행하며, step별로 진행할 수 있다.
쭉 이어서 작성해도 되지만, 이럴경우에는 빌드과정중에 문제가 생기면 찾기가 어렵다. 다음은 위의 배포 시나리오에 맞게 작성한 config.yml이다.

# yml 문법은 들여쓰기만 틀려도 오류나므로, 편집에 주의한다.
version: 2
# 빌드 작업을 수행한 job을 작성해 넣는다.
jobs:
  # job의 이름이다. build가 아니어도 상관없다. 아래의 workflows에서 실행할 때 사용된다.
  build:
    # 위에 언급한대로, 렌탈할 서버를 선택하는 부분이다.
    # docker 가상화 이미지를 설정할 수 있는데,
    # circleci에서 미리 빌드해놓은 제공된 이미지 목록에서 선택해야 한다.
    # 다음의 주소에서 선택할 수 있는 이미지를 확인할 수 있다. https://circleci.com/docs/2.0/circleci-images/
    docker:
      # npm 빌드를 해야하므로, nodejs로 설정했다.
      - image: circleci/node:latest
    steps:
      # 배포할 때 사용할 쉘 스크립트를 step별로 입력한다.
      # 소스를 checkout 하여, 리눅스 머신에 소스를 적용한다.
      - checkout
      # 의존성 설치
      - run: npm install
      # vue 빌드
      - run: npm run build
      # nginx 서버로 포팅 (참고로 이 접속정보는 없다.)
      - run: $ scp -r dist/. testuser@dkant.net:/usr/share/nginx/html/
#workflows에는 위에 선언한 job을 실행시킬 수 있다. 설정하기에 따라서는 병렬로 빌드하거나, 여러개의 job을 실행하는것도 가능하다.
workflows:
  version: 2
  build:
    jobs:
      # 위에서 작성한 job명칭을 입력한다.
      - build

BUILD result Page 위의 config.yml을 적용하고 GitHub에 푸시하고 확인한 빌드 결과이다. 모든 프로세스가 성공한 것을 확인할 수 있다.

마치며

CircleCI에 다양한 빌드환경를 설명하기에는 글이 너무 길어졌다. 그렇지만 빌드 시나리오는 프로젝트마다 천차만별이므로, 빌드 job의 스텝은 상황에 맞게 리눅스 쉘스크립트처럼 작성해서 쓰면 될 것이다.