여럿이 같이하는 프로젝트에서 코드를 통합할때 특정 부분에서 오류가 발생할 수 있습니다.
실수로 동료의 코드를 지웠다던지, 충돌 해결을 잘못했다던지, 나의 코드 변경으로 동료의 코드가 동작하지 않게 된다던지 등등... 많은 상황을 겪어보았는데요.
이때 CI(지속적 통합)를 통해 공통 브랜치로 코드가 push 될 때 마다 코드가 정상적으로 빌드되는지 확인할 수 있습니다.
선택지로 github actions 와 jenkins 두가지가 있었는데요.
자체 서버 자원을 사용해야하고 상대적으로 무거운 jenkins보다는, build용 가상 머신을 제공해주고 가벼운 github actions를 선택했습니다.
지원하는 기능은 jenkins가 더 많지만, 그 기능들에 대해 잘 모르기도 하고 지금 프로젝트 규모에서는 github actions만으로 충분하다고 생각했습니다.
앞에서 github actions는 빌드를 위한 가상 머신을 제공해준다고 했는데요. 이때 그 가상 머신 실행기가 github-hosted runners 입니다.
github-hosted runners는 아래와 같은 순서로 작업을 처리합니다.
github-hosted runners를 사용하기 위해서는 작업(job)을 만들고 runs-on
기능을 사용하여 작업을 처리할 가상 머신의 유형(ubuntu, windows, macOS)을 지정해야 합니다.
작업이 시작되면 깃허브는 해당 작업을 위한 가상 머신을 자동으로 프로비저닝하고 작업을 실행합니다. 작업이 완료되면 가상 머신이 자동으로 꺼집니다.
즉, push나 pull-request와 같은 이벤트에 따라 깃허브가 알아서 자원을 할당하고 해제합니다.
깃허브에서 발생하는 이벤트를 감지하고 이벤트에 따라 작업을 실행해주는 프로세스를 workflow라고 합니다.
레포지토리의 .github/workflows
디렉토리 안에 yaml 파일로 생성할 수 있습니다.
workflow 안에서 여러 github-hosted runners가 실행됩니다.
현재 진행중인 프로젝트에서의 빌드 과정을 그려보았는데요.
하나의 workflow에서 백엔드 관련 runner와 프론트엔드 관련 runner를 각각 작업하도록 둔 것을 볼 수 있습니다.
하나의 작업 안에 여러 step이 있는 것을 볼 수 있는데요. step은 순서대로 작업됩니다.
빌드를 위한 환경 설정을 초기 step에서 진행하고 마지막 step에서 빌드하는 흐름입니다.
name: continuous-integration
on:
pull_request:
branches:
- main
jobs:
build-spring:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Make application-dev.yml
if: ${{ github.event.pull_request.head.ref == 'dev' }}
run: |
cd ./src/main/resources
touch ./application-dev.yml
echo "${{ secrets.PROPERTIES_DEV }} > ./application-dev.yml
shell: bash
- name: Build with Gradle
uses: gradle/gradle-build-action@v2.6.0
with:
arguments: build
임의로 스크립트를 만들어 보았는데요. 위 스크립트를 예시로 하나씩 세세하게 살펴보도록 하겠습니다.
workflow는 이벤트를 감지하여 실행된다고 했는데요. 그 이벤트를 정의해주는 곳이 on
입니다.
on:
pull_request:
branches:
- main
스크립트를 해석하자면, main 브랜치로 pull-request 시에 이벤트를 발생시키겠다는 의미입니다.
workflow에서 job이란 독립된 환경에서 실행하는 하나의 처리 단위를 의미합니다.
즉, workflow 부분의 그림에서 백엔드 빌드 작업과 프론트엔드 빌드 작업은 독립적으로 실행됩니다!
여기서 필수적으로 정의해야 할 속성은 runs-on
과 steps
입니다.
runs-on
은 빌드할 환경을 뜻하고, steps
는 작업 목록 순서를 뜻합니다.
build-spring
은 그저 작업의 이름을 정의한 것입니다.
위의 스크립트를 보면 ubuntu-22.04 환경에서 빌드하도록 되어있고,
레포지토리 checkout -> JDK 17 세팅 -> application 환경 변수 설정 -> Gradle로 빌드 순으로 작업을 처리하도록 되어있습니다.
각각의 step을 의미하고 job과 마찬가지로 이름을 설정할 수 있습니다. name
속성으로 step의 이름을 명시하면 됩니다!
run
속성을 통해 스크립트 혹은 커멘드를 실행할 수 있습니다.
uses
속성을 통해서는 action을 사용할 수 있습니다.
if
속성으로 step에 대한 조건도 걸 수 있습니다!
PR을 만들면 자동으로 CI를 진행하는 것을 볼 수 있습니다.
검사가 끝나면 정상 코드라는 표시가 뜨게 됩니다.
actions 탭에 들어가면 아래와 같이 실행 순서가 step 순서와 같다는 것을 확인할 수 있습니다.
자원 정리는 역순으로 해주네요!
하지만 특이점이 보이죠? application-dev.yml
에는 체크 표시가 뜨지 않습니다.
if 조건문의 조건이 만족하지 않으면 실행하지 않습니다.
스크립트대로라면 조건을 만족하기 때문에 읽혀야 정상입니다! 저는 일단 성공시키기 위해 위의 스크립트에서 조건만 슬쩍 바꿔 실행 안되도록 해보았습니다.
위 application-dev.yml 파일을 읽는 것에 성공하지 못하는 이유는 아직 secrets를 설정하지 않아서 그렇습니다.
이제 github secrets로 application-dev.yml
을 읽게끔 해보겠습니다.
github actions는 base64로 인코딩된 값을 읽는다고 합니다. 따라서 환경 변수에 대한 인코딩 작업을 진행한 후에 환경변수를 만들도록 하겠습니다.
인코딩 사이트를 통해 인코딩을 진행했습니다.
그 후에 환경 변수를 설정하기 위해 레포지토리로 다시 이동합니다!
레포지토리 페이지의 settings -> Secrets and variables -> Actions 로 들어가면 환경 변수를 설정할 수 있는 페이지가 나옵니다.
New repository secret 버튼을 클릭하여 application.yml 환경 변수를 넣어보도록 하겠습니다.
다시 actions를 실행시켰습니다.
만세~ 환경 변수 파일까지 실행시켰습니다:)
CI 만든지 꽤 됐는데 이제야 작성하고 있습니다. 빠른 시일 내에 CD도 작성해볼까 합니다.
글 잘 봤습니다.