이번 새롭게 시작하는 프로젝트에서 CI/CD를 도입하고자 한다. 이번 포스팅에서는 CI/CD에 대해 공부한 내용을 소개하고, Github Action을 통해 Android Project CI/CD를 구축하는 방법에 대해서 소개한다.
CI/CD
어플리케이션 개발에서부터 배포까지 자동화를 통해 더 효율적으로, 더 자주 사용자에게 배포하는 방법이다. 자동화를 통해 개발에 집중할 수 있도록 도와주며, 더 빠르고 자주 배포할 수 있게 만들어 주는 것이 특징이다.
CI : Continuous integration
버그 수정이나 새로운 기능을 빌드되고 테스트되고 공유되는 레포지토리에 통합하는 방법이다.
CI는 다음과 같은 특징을 가지고 있다.
코드 변경사항을 주기적으로 빈번하게 머지해야 한다.
- 새로운 기능보다 머지 충돌을 해결하기 위해 많은 시간을 사용할 지도 모른다.
- 작은 단위으로 나누어, 개발하고 통합하는 것이 중요하다.
통합을 위한 단계 (빌드, 테스트, 머지)의 자동화
- 코드의 변경사항이 자동적으로 빌드가 되는지 확인해야 한다.
- 기존 시스템의 버그를 초래하지 않는지 테스트를 통해 확인해야 한다.
CI를 통해 다음과 같은 이점을 얻을 수 있다.
- 머지 충돌을 피할 수 있어서, 개발에만 집중할 수 있다. -> 개발 생산성 향상
- 빌드 및 테스트를 통해, 문제점을 빠르게 발견할 수 있다.
- 테스트 코드가 통과된 코드만 통합되기 때문에, 코드 퀄리티를 향상시킬 수 있다.
CD : Continuous Deployment
CD는 Continuous Delivery와 Continuous Deployment 두 가지 의미를 가지고 있다.
작성된 코드가 CI Server에서 빌드와 테스트 과정을 거친 후 Release 준비과정에서 개발팀과 검증팀이 검증을 한다. 검증 후 문제가 없다고 판단되었을 때 수동으로 배포를 하는 방법을 Continuous Delivery라고 한다.
반대로, 검증 후 문제가 없다고 판단되자마자 바로 자동으로 배포하는 과정을 Continuous Deployment라고 한다.
Delivery와 Deployment 중 정답은 없고, 사용하는 팀마다 다르다고 한다!
CD를 통해 다음과 같은 이점을 얻을 수 있다.
- 배포시 발생하는 문제를 줄여, 개발에만 집중할 수 있다. -> 개발 생산성 향상
- 빌드, 테스트, 배포까지 자동화를 통해 효율적으로 개발할 수 있다.
Github Action
Github Action을 통해 외부 도구들 없이, 자동화 프로세스를 구축할 수 있다. Github Action에는 다음과 같은 요소가 포함된다.
Workflows
- 차상위 수준으로, YAML 파일로 저장된다.
- 자동화된 전체 작업 프로세스
- 하나 이상의 Job으로 구성되며, Event에 의해 트리거된다.
Events
- Workflow를 실행하는 특정 활동이나 환경
- Github에서 발생할 수 있는 이벤트, 특정 브랜치의 머지, 푸쉬, 이슈 생성과 같은 이벤트를 의미한다.
Jobs
- 가상머신에서 실행되는 작업 단위
- 작업을 기본적으로 병렬적으로 수행되며, 순차적으로도 가능하다.
- 하나 이상의 Step으로 구성된다.
Steps
- 순차적으로 실행되는 작업단위
- run 속성을 사용하여 명령어를 실행하거나 uses 속성을 사용하여 Action을 실행할 수 있다.
Actions
- 빈번하게 발생하는 작업을 재사용을 용이하게 만들어주는 작업 메커니즘
- 다른 워크플로우 간의 공유나 Github 상의 모든 곳에서 공유 가능하다.
- Github MarketPlace에서 다른 Action을 확인할 수 있다.
Runner
- Workflow에서 Jobs를 실행할 수 있는 가상환경이다.
그럼 CICD, 직접 에제를 통해 알아보자!
1. Workflow 생성하기
자동화 프로세스를 만들고 싶은 프로젝트의 Actions에 새로운 WorkFlow를 생성한다. Android CI를 선택하면 YAML 파일을 생성할 수 있다.
YamL 확장자는 key-value 타입으로 작성되는 데이터 직렬화 방식이다.
필자는 아래와 같은 양식으로 기본 CI workflow를 구현하였다.
name: Android CI
on:
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: set up JDK 17
uses: actions/setup-java@v3
with:
java-version: 17
distribution: zulu
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
코드를 설명하자면,
name은 현재 YAML 파일의 이름을 정의한다.
on은 위에서 설명한 Events를 정의하는 곳이다.
태그를 통해 다양한 이벤트를 트리거할 수 있으며, 작성된 코드는 main branch에 pull_request를 할 때 event가 발생하도록 정의하였다.
jobs는 실행할 작업을 정의하며, workflow는 다양한 jobs로 구성된다.
build를 통해, 빌드할 가상환경을 설정하고, uses를 통해 사용할 action을 정의할 수 있고, run을 통해 실행할 커맨드를 정의할 수 있다.
2. CI 실행하기
현재 Workflow에는 빌드가 자동으로 성공하는지 검사하는 코드만 들어있다.
Android 기본 프로젝트를 생성하여, 바로 푸쉬하고 main 브랜치에 PR을 전달했다.
자동으로 Github Action이 실행되고, 통과한 것을 확인할 수 있다.
3. local.properties
만약 현재 프로젝트에서 local.properties를 사용하고 있다면, Github에 저장되지 않으니 빌드 오류가 난다. 이런 경우 다음과 같이 해결할 수 있다.
1. local.properties 구현하기
// in local.properties
api_key= "jaino"
// in app build.gradle
buildConfigField("String", "API_KEY", getLocalProperty("api_key"))
2. Github Secrets 등록하기
사용한 local.properties와 같은 내용으로 Repository secrets를 만든다.
3. Workflow 등록하기
name: Android CI
on:
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: set up JDK 17
uses: actions/setup-java@v3
with:
java-version: 17
distribution: zulu
cache: gradle
- name: add local.properties
run: |
echo api_key=\"${{ secrets.API_KEY }}\" >> ./local.properties
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
다음과 같이 빌드 전 Github Secrets에서 API_KEY를 들고 올 수 있도록 구현하면, 성공적으로 빌드 된다!
4. KtLint
개발하다 보면, Lint를 까먹고 적용하지 않은 채 PR을 날리는 경우가 발생한다. 이런 경우를 방지하기 위해, Workflow에서도 Lint 체크를 할 수 있다.
1. 포맷팅 수행
Ktlint 플러그인을 설치하고, 터미널에서 다음과 같이 포맷팅을 수행한다.
2. workflow ktlint 등록하기
- name: Run ktlint
run: ./gradlew ktlintCheck
다음과 같이 workflow에 추가하여, Lint를 적용했는지 확인할 수 있다!
마치며
이번에는 CI/CD에 대해 공부해보고 직접 구현해보았다! CI/CD가 무엇인지는 알고 있었으나, 왜 사용하는지에 대해서는 잘 알지 못했다. 그러나 병합 및 배포에서 발생하는 문제를 줄이고, 개발에 집중할 수 있도록 하는 점이 크게 인상깊었다. 더 안정적인 서비스 개발을 위해 필수적이라고 느꼈다. 지금 예시는 CI에 대한 예제만 소개하였는데, 나중에 프로젝트에서 배포까지 할 때 CD를 추가적으로 포스팅할 예정이다!
작성한 코드는 다음 저장소에서 확인할 수 있습니다!
https://github.com/jeongjaino/GitExample
참고자료
https://zzsza.github.io/development/2020/06/06/github-action/