이 블로그는 개인의 공부 목적으로 작성된 블로그입니다. 왜곡된 정보가 포함되어 있을 수 있습니다.
CI/CD
백엔드 개발을 학습하다 보면 CI/CD라는 개념을 듣게 된다. CI/CD를 검색해보면 지속적 통합, 배포라는 추상적인 개념으로 나온다. 더 찾아보면 통합과 배포에 각각 프로세스가 존재해서 좋은 유지보수가 가능한 개발을 할 수 있다고 한다. 실제로 인터넷 상에서는 좋은 유지보수와 같은 개발 형태보다는 배포와 통합을 자동화한다는 의미로 더 많이 사용되고 있었다.
당연히 자동화 하면 좋겠지? 라는 생각이 들지만 기존 협업 방식에 대해 생각해보면서 CI/CD를 최대한 쉽게 이해해보자
기존 협업의 방식
협업을 생각해본다면 가장 먼저 떠오르는 것은 github이다. 깃허브와 같은 SVM 형상 관리 툴로 협업을 진행하게 된다. 그렇다면 과연 형상 관리만으로 협업을 진행하는데 문제가 없을까? 아래 사진을 보자
실제로 내가 참여하고 있는 프로젝트의 PR 메세지 이다. 본인이 구현한 내용을 정리하고 생각해볼 것들을 메세지에 포함하여 PR 간에 의논하는 형태로 진행한다.
핵심적인 부분은 코드리뷰를 진행하는 것이다. 구현을 올바르게 하였는지 검토하고 질문하면서 협업을 진행하게된다.
중요한 부분은 내가 코멘트로 단 따봉 이모티콘이다. 저 따봉은 어떤의미일까?
- 구현을 잘했고, 문제가 없습니다!
- 구현을 잘했고, 문제가 없어 보입니다!
1,2번 중 어느 것이 따봉의 의미일까? 당연히 2번이다. "보입니다!" 라는 말로 코드를 잘 작성했다고 생각하는 정도 인것이지 확신하는 것은 아니기 때문이다. 관련 용어로 Looks Good To Me LGTM이 있다.
직접 저 코드를 실행해보기 전까지 우리는 저 코드가 문제 없다고 확신할 수 없다.(있다면 당신은 재능이 있는 것이다...)
그렇다면 수정된 코드가 반영된 프로그램을 실행해볼 수 있다면 코드에 문제가 없음을 보장할 수 있지 않을까?
CI
프로그램을 실행하는 가장 좋은 방법은 빌드하는 것이다. 또한 빌드과정에서 테스트 코드를 실행할 수 있다면 단순한 애플리케이션의 의존성 뿐만 아니라 비즈니스로직을 실행해 볼 수 있다. 변경된 내용을 지속적으로 빌드 테스트하여 통합하는 것 CI이다! 이제 우리는 CI를 이해한 것이다. 이제 CI를 구현 해보자
글쓴이는 spring boot project를 CI/CD에 적용하였다. spring boot CI/CD workflow 툴로 다음 두가지를 많이 사용한다.
- 젠킨스
- github action
젠킨스의 경우 상대적으로 초심자가 사용하기 어렵다고 한다. 젠킨스 서버를 구축해야 한다. 대신에 github action보다 빠르다고 한다. 당연히 빠를 수 밖에 없는게 workflow를 실행하기 위한 컴퓨팅 환경을 github에 제공되는 것이 직접 구축한 젠킨스 서버보다 느리기 때문이다.
github action은 상대적으로 구현하기 쉽고, github 의존적인 action을 사용할 수 있다. 다만 workflow가 제한되어 있고(소규모 프로젝트의 경우 문제 없다) 대신 생각보다 지원하는 action이 엄청 많지 않았다.(사용해봤을때 그랬다)
글쓴이는 github action으로 workflow를 구성하기로 하였다.
이외에도 배포과정에 대해서도 여러가지가 있는데 보통 다음 3가지를 사용한다.
- 도커
- code deploy
- 스크립트 (스크립트로 jar 파일을 실행)
글쓴이는 도커를 사용하였다.
Github action
작성 CI workflow를 보면서 CI 과정을 이해 해보자
github 페이지의 action tab에 들어가면 다양한 workflow를 추천해준다. 내가 만든 레포가 java라 관련 workflow 를 추천해주고 있었다. 선택하여 workflow를 구성할 수도 있고, 직접 yml파일을 추가하여 workflow를 생성할 수 도 있다.
다만 반드시 workflow 파일은 .github/workflows/ 에 위치해야한다.(PR template과 같이 이해하였다)
작성은 CI.yml 파일을 보면서 github action을 이해해보자
name: Java CI with Gradle
on:
pull_request:
branches: [ "main" ]
name: workflow 이름을 정의한다.
on: workflow의 조건을 정의한다. push, pull_request와 같이 조건을 명세한다. 위 코드의 경우 main 브랜치에 pull_request 요청이 발생하였을때 이다.
jobs:
build:
runs-on: ubuntu-latest
permissions:
write-all
#contents: read
services:
mysql:
image: mysql:8.0
ports:
- 3306:3306
env:
MYSQL_DATABASE: testdb
MYSQL_ROOT_PASSWORD: testdb
options: >-
--health-cmd="mysqladmin ping --silent"
--health-interval=10s
--health-timeout=5s
--health-retries=3
jobs: workflow 안에서 각각의 job이다. 위 코드의 경우 "build"라는 이름이 붙은 job인 것이다. job들 간에는 병렬적으로 task가 실행된다.(의존성을 추가할 수도 있다)
runs-on: 해당 job이 우분투 환경에서 실행된다.
permissions: job의 권한을 정의한다.
services: 사용할 컨테이너를 정의한다. CI의 경우 build에 db와 의존성을 보장하기 위해 mysql 컨테이너를 추가하였다.
mysql: 컨테이너 이름이다.
image: 사용되는 컨테이너 이미지 정보이다
ports: 컨테이너 포트 설정한다. 위 코드의 경우 3306:3306 이지만 예를들어 8080:3306이라면 컨테이너 외부 에서 8080 포트에 연결되어 있고 컨테이너 내부에는 3306 포트를 사용한다.
env: 환경변수로 mysql 설정 정보를 추가한다.
options: 옵션으로 health check를 추가하였다. mysql이 제대로 실행되었는지 확인하기 위함이다. 사실 health check를 추가하는 가장 큰 이유는 mysql가 온전히 실행되기 전에 spring boot가 실행되는 상황을 예방하기 위함이다.
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
# Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies.
# See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Setup Gradle
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
- name: Build with Gradle Wrapper
env:
SPRING_DATASOURCE_URL: jdbc:mysql://127.0.0.1:3306/testdb
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: testdb
run: ./gradlew build --stacktrace
# Test 후 Report 생성
- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
junit_files: '**/build/test-results/test/TEST-*.xml'
steps: step은 job안의 각각의 task를 구분짓는 용도이다.
actions/checkout: 우리가 사용중인 레포 정보를 가져오기 위한 설정이다.
name, run: 각각의 task이름과 실행 내용이다.
chmod +x gradlew: gradlew을 실행하기 위한 권한을 부여한다.
setup gradle: gradle를 설치한다.
./gradlew build --stacktrace: build를 진행한다 이때 env를 통해 설정 정보를 넣는다.
pushlish test results: build 결과를 공지한다.
정리하면 아래 사진과 같이 진행된다.
트러블 슈팅
직접 해보면 workflow가 실행되기 전까지 올바르게 동작하는지 알 수 없어서 디버깅 시간이 오래걸렸다.
나와 같이 디버깅에 너무 큰 시간을 사용하는 사람이 없길 바라는 마음에서 애러가 나온 경우를 정리해봤다.
- github action 문법이 틀린 경우 아에 실행되지 않음
- write 권한을 주지 않은 경우
- spring boot yml이 잘못 되었는경우 (여담으로 동일한 jdbc url를 사용해도 환경변수로 사용한 경우와 application.yml에 명시한 경우가 다르게 동작하였다. 되도록이면 환경변수에 명세하자. 환경 변수에서 설정한 값이 우선순위 이다.)
'인프라 > 도커' 카테고리의 다른 글
CI/CD 구축 (github action+Spring boot + mysql + docker-compose) (2) (10) | 2024.07.15 |
---|---|
도커 데스크탑, 젠킨스 설치 (1) | 2024.01.05 |