CircleCI란?
CircleCI
는 VCS(Version Control System)와 연동하여 빌드, 테스트 및 배포를 자동화하는 데 도움이 되는 지속적인 통합(Continuous Integration)을 제공하는 플랫폼입니다.
또한, 캐싱, 도커 레이어 캐싱, 리소스 클래스 등을 사용하여 매우 복잡한 파이프라인을 효율적으로 실행하도록 구성할 수 있습니다.
config.yml 설정키 (version 2.1 기준)
version
version은 CircleCI의 버젼을 나타냅니다. 2.1에서는 orbs, commands, executors를 추가로 사용할 수 있습니다.
version: 2.1
jobs:
// ...
workflows:
// ...
orbs
orbs
는 반복되는 프로세스를 자동화하고 설정속도를 높이며 다른 툴(ex. slack, jira....)과 쉽게 통합할 수 있도록 도와줍니다.
version: 2.1
orbs:
hello: circleci/hello-build@0.0.5
workflows:
"Hello Workflow":
jobs:
- hello/hello-build
commands
commands
는 job에서 사용할 명령어들을 Map으로 저장해 여러 job들에서 재사용 할 수 있도록 합니다.
version: 2.1
commands:
sayhello:
description: "A very simple command for demonstration purposes"
parameters:
to:
type: string
default: "Hello World"
steps:
- run: echo << parameters.to >>
executors
excutors
는 job이 실행될 환경을 정의할 수 있습니다. excutors에서 선언한 executor를 통해서 여러 job들에서 재사용할 수 있습니다.
- docker:
executor
가 사용할 docker를 정의합니다. - machine:
executor
가 사용할 machine을 정의합니다. - macos:
executor
가 사용할 macos을 정의합니다. - windows:
executor
가 사용할 windows을 정의합니다. (docker, machine, macos, windows 중 하나는 정의해야 합니다.) - resource_class :
job
에 할당 될 CPU와 RAM의 크기를 정의합니다. - working_directory:
job
이 실행 될 작업공간을 정의합니다(절대경로) - shell:
command shell
을 정의합니다. - environment:
환경변수
name과 value의 Map을 정의합니다.
version: 2.1
executors:
android-executor:
docker:
- image: circleci/android:api-30
resource_class: medium
working_directory: ~/code
jobs:
build:
executor:
name: android-executor
workflows:
// ...
jobs
job
은 workflow의 기본단위입니다. job은 더 작은단위인 step으로 이루어져 있습니다.
- steps:
job
에서 커맨드를 실행하는 독립적인 단위입니다. - resource_class:
job
에 할당 될 CPU와 RAM의 크기를 정의합니다. - working_directory:
step
이 실행 될 작업공간을 정의합니다(절대경로) - environment:
환경변수
name과 value의 Map을 정의합니다.
steps
steps
는 job에서 커맨드를 실행하는 독립적인 단위입니다.
- checkout:
저장소
를 checkout 합니다. - run:
command
를 통해 실행할 shell 명령어를 실행합니다. - steps:
수행할 동작
들을 리스트로 나열합니다. - save_cache:
종속성
을 캐싱합니다. 캐싱함으로써 파이프라인을 효율적으로 구성할 수 있고 빌드시간을 단축시킬 수 있습니다. - restore_cache:
캐시
를 불러옵니다. - store_artifacts:
아티팩트
들을 저장합니다. - store_test_results:
테스트 결과
를 저장합니다. - persist_to_workspace: 다음 workflow에서 사용하고 있는
workspace
를 저장하고 싶을 때 사용합니다. - attach_to_workspace: 저장했던
workspace
를 불러옵니다.
jobs:
build:
working_directory: ~/canary-python
environment:
FOO: bar
steps:
- run:
name: Running tests
command: make test
Workflows
- triggers:
workflow
가 실행될 트리거를 지정합니다. (cron식 혹은 branch에 따른 조건을 지정할 수 있습니다.) - jobs:
workflow
에서 실행될 job을 지정합니다.- requires:
job
의 수행조건을 지정합니다.(지정하지않으면 job들은 병렬처리) - filters: branch 혹은 tag를 통해 job이 실행될 지
필터링
합니다. - matrix: 여러 다른설정의
반복 테스트
를 작업하고 싶을 때 사용합니다.
- requires:
workflows의 속성들을 조합하면 정말 다양한 방법으로 처리할 수 있습니다
하지만, 이번 포스트에서는 간단하게 순차처리, 병렬처리를 어떻게 수행할 것이냐만 정리하겠습니다!
Workflows 순차처리 예시
workflows:
version: 2
build-test-and-deploy:
jobs:
- build
- test1:
requires:
- build
- test2:
requires:
- test1
- test3:
requires:
- test2
- test4:
requires:
- test3
- deploy:
requires:
- test4
Workflow 수행 순서
build -> test1 -> test2 -> test3 -> test4 -> deploy
Workflows 병렬처리 예시
workflows:
version: 2
build_accept_deploy:
jobs:
- build
- test_1:
requires:
- build
- test_2:
requires:
- build
- test_3:
requires:
- build
- test_4:
requires:
- build
- deploy:
requires:
- test_1
- test_2
- test_3
- test_4
Workflow 수행 순서
build -> test1, test2, test3, test4 -> deploy
Project에 CircleCI 적용해보기(Android 기준)
1) version 설정
version: 2.1
// ...
2) orbs 설정
orbs
를 지정해줍니다. 안드로이드 기준으로 최신 orbs는 2.0.0입니다. circleci/android@2.0.0를 지정해주겠습니다.
orbs:
android: circleci/android@2.0.0
// ...
3) Excutors 설정
excutors
를 지정해줍니다. 도커 이미지는 circleci에서 이미 빌드되어있는 이미지를 지정하겠습니다.
executors:
android-executor:
docker:
- image: circleci/android:api-30
resource_class: medium
// ...
4) build job 작성
checkout을 해준 후, 빌드를 해줍니다. 이 과정에서 캐싱
을 통해 성능을 높이고, 빌드속도를 최적화 하도록 해줍니다.
commands:
restore_gradle:
steps:
- run:
command: |
find . -name 'build.gradle' | sort | xargs cat |
shasum | awk '{print $1}' > ./tmp_gradle_cache_seed
name: Generate cache checksum
- restore_cache:
key: gradle-v1a-{{ arch }}-{{ checksum "./tmp_gradle_cache_seed" }}
name: Restore gradle cache
- restore_cache:
name: Restore gradle properties
key: gradle-properties-${CIRCLE_WORKFLOW_ID}_21
save_gradle:
steps:
- save_cache:
name: Save gradle cache
key: gradle-v1a-{{ arch }}-{{ checksum "./tmp_gradle_cache_seed" }}
paths:
- ~/.gradle/caches
- ~/.gradle/wrapper
- save_cache:
key: gradle-properties-${CIRCLE_WORKFLOW_ID}_21
name: Save gradle properties
paths:
- ~/.gradle/gradle.properties
jobs:
build:
executor:
name: android-executor
working_directory: ~/code
steps:
- checkout
- restore_gradle
- run:
name: Assemble release build
command: |
./gradlew assembleRelease
- save_gradle
// ...
빌드 과정을 통해 나온 app bundle을 비롯한 artifacts
들을 저장해줍니다.
그 뒤, persist_to_workspace
를 통해 workspace를 저장해줍니다.
jobs:
build:
// ...
steps:
// ...
- run:
name: Make App Bundle
command: ./gradlew bundleRelease
- store_artifacts:
path: app/build/outputs/bundle/release
destination: bundle
- store_artifacts:
path: app/build/outputs/mapping/release
destination: mapping
- store_artifacts:
path: app/build/reports
destination: reports
- store_test_results:
path: app/build/test-results
- persist_to_workspace:
root: .
paths:
- .
5) test job 작성
unit test
와 ui test
를 진행해줍니다.
jobs:
build:
// ...
test:
executor:
name: android/android-machine
resource-class: medium
tag: 2021.10.1
steps:
- attach_workspace:
at: .
- android/run-tests:
test-command: ./gradlew lint testDebug --continue
- android/start-emulator-and-run-tests:
test-command: ./gradlew connectedDebugAndroidTest
system-image: system-images;android-30;google_apis;x86
- android/create-avd:
avd-name: myavd
system-image: system-images;android-29;default;x86
install: true
- android/start-emulator:
avd-name: myavd
no-window: true
restore-gradle-cache-prefix: v1a
- android/run-tests
- android/save-gradle-cache:
cache-prefix: v1a
// ...
5) deploy job 작성
fastlane을 통해 deploy
합니다.
jobs:
build:
// ...
test:
// ...
deploy:
executor:
name: android-executor
steps:
- attach_workspace:
at: .
- run:
name: Install fastlane
command: bundle install
- run:
name: Execute fastlane
command: bundle exec fastlane playstore
6) workflows 작성
build와 test는 순차처리
로 진행을 하고, deploy는 master 브랜치
만 동작하도록 해주었습니다.
workflows:
version: 2
build_deploy:
jobs:
- build
- test:
requires:
- build
- deploy:
requires:
- build
- test
filters:
branches:
only:
- master
전체 코드
version: 2.1
orbs:
android: circleci/android@2.0.0
executors:
android-executor:
docker:
- image: circleci/android:api-30
resource_class: large
commands:
restore_gradle:
steps:
- run:
command: |
find . -name 'build.gradle' | sort | xargs cat |
shasum | awk '{print $1}' > ./tmp_gradle_cache_seed
name: Generate cache checksum
- restore_cache:
key: gradle-v1a-{{ arch }}-{{ checksum "./tmp_gradle_cache_seed" }}
name: Restore gradle cache
- restore_cache:
name: Restore gradle properties
key: gradle-properties-${CIRCLE_WORKFLOW_ID}_21
save_gradle:
steps:
- save_cache:
name: Save gradle cache
key: gradle-v1a-{{ arch }}-{{ checksum "./tmp_gradle_cache_seed" }}
paths:
- ~/.gradle/caches
- ~/.gradle/wrapper
- save_cache:
key: gradle-properties-${CIRCLE_WORKFLOW_ID}_21
name: Save gradle properties
paths:
- ~/.gradle/gradle.properties
jobs:
build:
executor:
name: android-executor
working_directory: ~/code
steps:
- checkout
- restore_gradle
- run:
name: Assemble release build
command: |
./gradlew assembleRelease
- save_gradle
- store_artifacts:
path: app/build/reports
destination: reports
- store_test_results:
path: app/build/test-results
- run:
name: Make App Bundle
command: ./gradlew bundleRelease
- store_artifacts:
path: app/build/outputs/bundle/release
destination: bundle
- store_artifacts:
path: app/build/outputs/mapping/release
destination: mapping
- persist_to_workspace:
root: .
paths:
- .
test:
executor:
name: android/android-machine
resource-class: medium
tag: 2021.10.1
steps:
- attach_workspace:
at: .
- android/run-tests:
test-command: ./gradlew lint testDebug --continue
- android/start-emulator-and-run-tests:
test-command: ./gradlew connectedDebugAndroidTest
system-image: system-images;android-30;google_apis;x86
- android/create-avd:
avd-name: myavd
system-image: system-images;android-29;default;x86
install: true
- android/start-emulator:
avd-name: myavd
no-window: true
restore-gradle-cache-prefix: v1a
- android/run-tests
- android/save-gradle-cache:
cache-prefix: v1a
deploy:
executor:
name: android-executor
steps:
- attach_workspace:
at: .
- restore_gradle
- run:
name: Install fastlane
command: bundle install
- run:
name: Execute fastlane
command: bundle exec fastlane playstore
workflows:
version: 2
build_deploy:
jobs:
- build
- test:
requires:
- build
- deploy:
requires:
- build
- test
filters:
branches:
only:
- master