이번 포스트에서는 CI/CD 구성에 대해서 다루겠습니다. 저는 Circle CI를 이용해 구성해보겠습니다. 진행은 다음과 같습니다.

  • CircleCI 빌드하기
  • API로 Artifact 가져오기
  • CircleCI에 가상머신 SSH 키 등록하기
  • Azure 배포하기

시작에 앞서

CircleCI를 이용한 것은 저의 기존 프로젝트를 활용하기 위해서인데, 꼭 이와 동일하게 구성할 필요는 없습니다. 만약 선호하는 솔루션이 있거나 기존 사용하던 것이 있다면 다른 것을 사용하는 것도 무방합니다.

CI 구성이 처음인 분들을 위해 다른 옵션을 소개드리면 Travis CI, Jenkins 등이 있습니다. 장단점이 있는데, 복잡한 것이 싫고 간단하게 해결하고싶은 분들은 Travis CI 또는 CircleCI를 사용하시고 본인이 CI용 서버를 별도 구축하여 세부적인 컨트롤 및 최적화를 하고싶은 분들은 Jenkins를 사용해보시길 추천드립니다.

CircleCI 빌드하기

  1. CircleCI 대시보드에 접속합니다. 처음이라면 회원가입을 해줍시다.
  2. 우상단 클릭 > User Settings > Account Integration에서 Github 계정과 연동하여 access permission이 있는지 확인합니다. 없다면 연결해줍니다.
  3. 좌측 ADD PROJECTS를 클릭합니다. 본인의 Github 프로젝트 리스트를 볼 수 있습니다. 이 중에 배포하기 위한 프로젝트를 찾아 Set Up Project를 누릅니다.
  4. 환경은 Linux, Node를 선택합니다.
  5. CircleCI에서는 설정을 읽어오기 위해 프로젝트 내의 .circleci/config.yml 파일을 참조합니다. 아래 내용을 복사하여 프로젝트의 .circleci/config.yml 파일에 붙여 넣습니다.
    cd /path/to/project
    mkdir -p .circleci
    vi .circleci/config.yml
    version: 2
    jobs:
    build:
      docker:
        - image: circleci/node:7.10
      working_directory: ~/repo
      steps:
        - checkout
        - restore_cache:
            keys:
            - v1-dependencies-{{ checksum "package.json" }}
            - v1-dependencies-
        - run: yarn install
        - save_cache:
            paths:
              - node_modules
            key: v1-dependencies-{{ checksum "package.json" }}
        - run: yarn test
        - run: yarn build
        - run:
            command: |
              tar cvf application.tar.gz -C build .
        - run:
            command: |
              mkdir -p /tmp/artifacts
              mv application.tar.gz /tmp/artifacts
        - store_artifacts:
            path: /tmp/artifacts
    deploy:
      machine:
        enabled: true
      steps:
        - run:
            command: |
              echo "Deploy Over SSH"
    workflows:
      version: 2
      build-and-deploy:
        jobs:
          - build
          - deploy:
            requires:
              - build
            filters:
              branches:
                only: master
  6. 변경사항을 커밋하고 github에 푸시합니다.
    git commit -a -m "Add CircleCI configuration file"
    git push
  7. Start building을 누릅니다. config.yml에 정의한 과정대로 첫 번째 build가 수행되는 것을 볼 수 있습니다.
  8. jobs 탭을 확인합니다. success로 초록색 표시가 있다면 성공입니다. 이제 Artifacts 탭을 보면 application.tar.gz 파일이 생성된 것을 볼 수 있습니다. 다음으로 이 파일을 가상머신으로 가지고 와서 서버 기동까지 이어지는 작업을 해보겠습니다.

API로 Artifact 가져오기

  1. 위에서 생성된 Artifacts를 CircleCI API를 통해 가져오기 위해서는 Personal Token이 필요합니다. 우상단 아이콘 > User settings로 이동합니다.
  2. Personal API Tokens를 클릭합니다.
  3. Create New Token 버튼을 클릭합니다.
  4. Token name에 적당한 이름을 입력하고 Add API Token을 클릭합니다.
  5. 생성된 토큰 값을 복사하여 적당한 곳에 메모해둡시다. 한 번 보여준 뒤로 다시 볼 수 없기 때문에, 분실할 경우 복구가 불가능합니다. 만약 분실한 경우 삭제 및 재생성을 하시기 바랍니다.
  6. 가상머신에 접속합니다.
    ssh chancethecoder@52.141.36.128
  7. 생성된 토큰 값을 환경변수로 저장합니다.
    echo 'export CIRCLE_TOKEN="your_token"' >> ~/.bashrc
    source ~/.bashrc
  8. curl로 API 호출을 해봅시다. 예제에서 각각 vcs_type에 github, bitbucket 등 사용하는 VCS를, username에 CircleCI의 좌상단 유저 닉네임을, project에 VCS의 타겟 프로젝트 이름을, build_num에 호출하고자 하는 빌드 번호를 넣어주면 됩니다. 성공적으로 호출된다면 아래와 같은 값이 출력됩니다.
    # example
    curl https://circleci.com/api/v1.1/project/:vcs_type/:username/:project/:build_num/artifacts?circle-token=$CIRCLE_TOKEN
    [ {
    "path" : "tmp/artifacts/application.tar.gz",
    "pretty_path" : "tmp/artifacts/application.tar.gz",
    "node_index" : 0,
    "url" : "https://52-131691113-gh.circle-artifacts.com/0/tmp/artifacts/application.tar.gz"
    } ]
  9. 이제 artifact를 가져와봅시다. curl 명령어 결과와 wget을 조합해 아래와 같이 입력합니다. application.tar.gz 파일이 생성된다면 정상 호출된 것입니다.
    curl https://circleci.com/api/v1.1/project/github/chancethecoder/playground/52/artifacts?circle-token=$CIRCLE_TOKEN | grep -o 'https://[^"]*' | xargs -P4 -I % wget %?circle-token=$CIRCLE_TOKEN
    application.tar.gz?circle-token=...
    ls -al | circle-token
  10. 이제 빌드 결과 파일을 구동시켜봅시다. 이 부분은 각자의 리액트 프로젝트 구성에 따라 다르겠습니다만, 저는 빌드를 통해 생성된 static 파일만을 서빙하도록 구성했기 때문에 pm2의 serve 명령어를 사용하겠습니다.
    mkdir -p myapp
    tar xvf application.tar.gz?circle-token=... -C myapp
    pm2 delete all
    # myapp은 static 파일 디렉토리 경로, 3000은 포트번호 지정입니다.
    pm2 serve myapp 3000
  11. 이제 브라우저에서 본인의 도메인 혹은 공용 아이피로 접속해봅시다. 본인이 작성한 리액트 앱이 보인다면 잘 따라오신 것입니다.

CircleCI에 가상머신 SSH 키 등록하기

  1. 빌드 타임에 CircleCI에서 가상머신에 배포 및 구동까지 하도록 하기 위해서는 SSH 통신이 가능해야 합니다. 따라서 SSH 설정을 먼저 해줍시다. 먼저 가상머신에 접속합니다.
    ssh chancethecoder@52.141.36.128
  2. ssh 키를 생성합시다. ssh-keygen 옵션은 본인에 맞게 변경하셔도 무방합니다. 엔터키를 계속 눌러주면 기본값으로 생성됩니다. 주의할 점으로, passphrase는 빈 값으로 두어야 합니다.
    ssh-keygen -t rsa -b 4096 -C "chancethecoder@gmail.com"
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/chancethecoder/.ssh/id_rsa):
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in /home/chancethecoder/.ssh/id_rsa.
    Your public key has been saved in /home/chancethecoder/.ssh/id_rsa.pub.
    ...
  3. public 키를 authorized_keys에 추가합니다.
    cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
  4. private 키파일을 복사합니다.
    cat ~/.ssh/id_rsa
  5. CircleCI에서 대시보드 > 프로젝트 설정(기어 버튼) > PERMISSIONS > SSH Permisions로 이동합니다.
  6. Add SSH Key 버튼을 클릭합니다.
  7. Hostname을 빈칸으로 두고 Private Key에 복사한 내용을 붙여넣습니다. 정상적으로 등록되면 Fingerprint가 보이는데, 해당 값을 복사합니다.
  8. 리액트 프로젝트의 .circleci/config.yml에 아래 코드를 추가합니다. your_fingerprints 부분에 복사한 값을 넣으시면 됩니다.
    ...
      deploy:
        machine:
          enabled: true
        steps:
          - add_ssh_keys:
              fingerprints:
                - "your_fingerprints"
          - run:
              command: |
                echo "Deploy Over SSH"
    ...

Azure 배포하기

  1. 마지막으로 CircleCI에서 가상머신 배포까지 구성해봅시다. 마찬가지로 .circleci/config.yml에 아래 코드를 추가합니다.
    ...
      deploy:
        machine:
          enabled: true
        steps:
          - add_ssh_keys:
              fingerprints:
                - "your_fingerprints"
          - run:
              command: |
                echo "Deploy Over SSH"
                ssh $SSH_USER@$SSH_HOST << EOF
                  rm -f application.tar.gz*
                  curl https://circleci.com/api/v1.1/project/github/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/$CIRCLE_PREVIOUS_BUILD_NUM/artifacts?circle-token=$CIRCLE_TOKEN | grep -o 'https://[^"]*' | xargs -P4 -I % wget %?circle-token=$CIRCLE_TOKEN
                  pm2 delete all
                  rm -rf myapp/*
                  tar xvf application.tar.gz?circle-token=$CIRCLE_TOKEN -C playground
                  pm2 serve myapp 3000
                EOF
  2. CircleCI에서 대시보드 > 프로젝트 설정(기어 버튼) > BUILD SETTINGS > Environment Variables로 이동합니다.
  3. Add Variable 버튼을 누릅니다. Name과 Value가 있는데, 각각 아래의 값으로 추가해줍시다.
    1. SSH_USER: 가상머신 접속 계정
    2. SSH_HOST: 가상머신 아이피 주소
    3. CIRCLE_TOKEN: Personal Token
  4. 리액트 프로젝트의 .circleci/config.yml 변경사항을 푸시합니다.
  5. 소스 커밋 > CircleCI 워크플로우 실행 > 가상머신 ssh 배포 (다운로드, 재기동) 까지 일련의 과정이 잘 진행되는지 확인합니다.

여기까지 잘 오셨다면 CI/CD 구성까지 완료된 것입니다. 이제 본인만의 어플리케이션을 구축해보시기 바랍니다. 저의 경우 리액트도 공부할 겸 이력서용 사이트를 만들어 두었는데요, Azure를 활용해 1년 동안 무료 호스팅이 가능하기 때문에 이를 잘 활용해서 본인만의 사이트를 만들어보시길 바랍니다.