CircleCI Configuration! 막 붙여서 때우지 말고 알고 씁시다 😎
자동배포 구성은 크게 두 단계로 진행됩니다.
프로젝트 빌드의 경우에는 로컬에서 직접 빌드할때와 거의 같은 방법으로 진행됩니다. 다만, 매번 패키지를 install 해 주는 것이 시간도 오래 걸리고 불필요한 작업이기 때문에 캐시를 이용하는 과정이 추가됩니다.
업로드의 경우, CircleCI Orb를 이용합니다. Orb는 CircleCI의 프로세스 중 자주 사용되는 것을 라이브러리처럼 만들어 둔 것이라고 생각하시면 편합니다.
yarn 대신 npm을 사용해도 똑같이 진행할 수 있습니다. 아래에서는 문맥상의 편리함을 위하여 yarn을 사용하는 경우로만 전제하고 진행합니다.
아시다시피 yarn은 node.js 패키지 매니저입니다. 프로젝트의 정상적인 빌드 과정을 위해서는 node.js가 필요합니다. CircleCI가 node.js를 사용할 수 있도록, 아래와 같이 node.js의 도커 이미지를 불러와 줍니다.
build-static-project:
docker:
- image: circleci/node:lts
환경 세팅 후 첫 번째 step으로 checkout
이 있습니다. checkout
은 현재 CircleCI의 cli가 실행될 디렉토리를 코드가 있는 위치로 변경합니다.
물론, 다른 옵션을 이용해서 다른 구성을 할 수도 있지만 간단한 배포에는 기본값으로도 잘 동작하도록 할 수 있습니다.
steps:
- checkout
yarn을 이용해 설치한 패키지 (/node_modules
) 를 매번 새로 설치하게 되면 시간도 오래 걸리고 불필요한 연산도 늘어납니다. package.json을 해싱한 값을 key로 삼아 캐시를 저장하고 불러올 수 있습니다. (CircleCI의 패키지 캐시는 마지막 touch로부터 최대 30일까지 유지된다고 하는 것 같습니다.)
아래와 같이 캐시를 불러와 줍니다.
- restore_cache:
key: dependency-cache-live-{{ checksum "package.json" }}
(일러두기) 앞에 붙은 dependency-cache-live-
는 편의상 붙인 string입니다. {{ checksum "package.json" }}
구문이 해싱된 스트링에 해당하며, key string이 일치하는 과거 cache가 있으면 불러오는 구조입니다. 이후에 캐시 등록 부분에서도 똑같은 이름으로 캐시를 등록합니다!
로컬과 거의 똑같은 방법으로 dependency 설치 및 빌드합니다.
- run: yarn --ignore-optional
- run: yarn build
이 때, 시간을 단축하기 위해 @devDependencies
등의 optional dependency는 설치하지 않습니다. CircleCI에서 사용하는 인스턴스가 (당연하게도) 맥북보다 느리고, 빌드에 시간이 오래 소요되기 때문에 조금이라도 줄이는 편이 정신건강에 도움이 됩니다.
앞에서 소개한 것 처럼 캐시의 key를 지정하고, 어떤 파일들을 캐시할 것인지 작성합니다.
- save_cache:
key: dependency-cache-live-{{ checksum "package.json" }}
paths:
- ./node_modules
캐시 복구에 작성한 키와 완전히 동일한 키를 사용하며, dependency들이 저장되는 ./node_modules
디렉토리를 저장하도록 합니다.
빌드 스텝의 마지막 과정입니다. 다음 단계에서 S3에 업로드 할 빌드 결과물을 정상적으로 찾을 수 있도록 하기 위해 현재 작업중인 디렉토리를 다시 찾아 올 수 있도록 해 주어야 합니다.
- persist_to_workspace:
root: .
paths:
- .
여기서는 특정 디렉토리를 지정하지 않고 기본값(working_directory
)을 사용하도록 .
을 넣어 줍니다.
이제 빌드된 패키지를 S3에 업로드할 차례입니다.
(공식문서) CircleCI Developer - Orbs
*이번 단계에서는 위 공식 링크에 있는 AWS S3 업데이트 방법을 따라 구축한 내용을 소개합니다.
AWS CLI를 사용해야 CircleCI에서 CLI를 이용해 각종 동작을 수행할 수 있습니다. 프로세스 이름을 지어주고 아래와 같이 executor를 불러와 줍시다.
deploy-project-to-S3:
executor: aws-cli/default
빌드된 파일을 찾아 업로드 하기 위해서, 아까 빌드를 수행한 디렉토리를 다시 찾아갑니다.
steps:
- attach_workspace:
at: .
갑자기 업데이트라고 해 놓고 sync와 copy가 등장하니 당황스러울 수 있습니다. 각각은 다음과 같은 과정을 뜻합니다.
즉, 폴더 구조를 맞춘 후에 파일 업로드가 실시되며, 두 과정을 별도로 호출하도록 되어 있는 것입니다.
캐시 정책이나 퍼블릭 설정 등은 예제에 있는 값을 그대로 다라갑니다.
- aws-s3/sync:
arguments: |
--acl public-read \
--cache-control "max-age=86400"
aws-access-key-id: AWS_ACCESS_KEY_ID
aws-region: AWS_REGION
aws-secret-access-key: AWS_SECRET_ACCESS_KEY
from: 'build'
to: 's3://my-s3-bucket-name'
- aws-s3/copy:
arguments: '--dryrun'
from: 'build'
to: 's3://my-s3-bucket-name'
이 때, AWS_ACCESS_KEY_ID
, AWS_REGION
, AWS_SECRET_ACCESS_KEY
세 개의 환경변수가 등장합니다. 해당 값들은 congifuration 파일에 직접 넣기에는 보안상의 문제가 발생할 수 있는 값이기에 CircleCI에 별도로 등록하여 관리합니다.
Project Settings > Environment Variables 에 들어가면 새 키를 추가할 수 있습니다. AWS 키 발급 방법은 저의 다른 포스트를 참조하세요 😉
사족) --dryrun
옵션에 대해서는 아래 공식 문서에서 좀 더 자세히 확인할 수 있습니다. 작업할 내용을 우선 표시한 뒤 실제로 작업을 수행하는 옵션으로 보입니다.
https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html
https://docs.aws.amazon.com/cli/latest/reference/s3/cp.html
--dryrun
: Displays the operations that would be performed using the specified command without actually running them
어려운 부분은 다 끝났습니다! 마지막으로 사용한 orb를 import 해 줄 일만 남았습니다.
version: 2.1
orbs:
aws-cli: circleci/aws-cli@1.3.1
aws-s3: circleci/aws-s3@2.0.0
위 코드를 yaml 최상단에 붙여넣으면 모든 CI 작성이 마무리됩니다.
version: 2.1
orbs:
aws-cli: circleci/aws-cli@1.3.1
aws-s3: circleci/aws-s3@2.0.0
jobs:
build-static-project:
docker:
- image: circleci/node:lts
steps:
- checkout
- restore_cache:
key: dependency-cache-live-{{ checksum "package.json" }}
- run: yarn --ignore-optional
- run: yarn build
- save_cache:
key: dependency-cache-live-{{ checksum "package.json" }}
paths:
- ./node_modules
- persist_to_workspace:
root: .
paths:
- .
deploy-project-to-S3:
executor: aws-cli/default
steps:
- attach_workspace:
at: .
- aws-s3/sync:
arguments: |
--acl public-read \
--cache-control "max-age=86400"
aws-access-key-id: AWS_ACCESS_KEY_ID
aws-region: AWS_REGION
aws-secret-access-key: AWS_SECRET_ACCESS_KEY
from: 'build'
to: 's3://my-s3-bucket-name'
- aws-s3/copy:
arguments: '--dryrun'
from: 'build'
to: 's3://my-s3-bucket-name'
workflows:
globalization-frontend-autodeploy:
jobs:
- build-static-project:
filters:
branches:
only: master
- deploy-project-to-S3:
requires:
- build-static-project
filters:
branches:
only: master