SPOT 개발에 본격적으로 들어가면서 제일 먼저 진행했던 업무는 CI/CD 파이프라인 구축이었다.
지난 3월, 그릿지 테스트를 진행 하면서 챌린지 채점을 위해 서비스 배포가 필요했다. 당시에는 따로 CI/CD 파이프라인을 구축하지 않았다. 당시 배포 과정은 다음과 같다.
로컬에서 Gradle로 빌드 → Dockerfile로 이미지 생성 → 원격 Docker Hub에 이미지 Push → SSH로 배포된 서버 접속 → 원격 Docker Hub에 이미지 Pull → Docker Container 실행
개인 프로젝트였고, 프론트와의 협업이 필요한 부분이 아니기 때문에 수정 사항이 많지 않을것이라 판단했고, CI/CD 파이프라인 구축에 대해 그렇게 깊게 고민하지 않았다. 시간도 촉박했고, 과도한 작업이라고 생각 했다.
하지만, 계속해서 수정 사항들이 발생했다. API 개발을 마무리한 뒤, 지속적으로 코너 케이스를 찾기 위해 테스트를 진행하여 파악된 부분은 빠르게 수정했다. 이를 배포된 서버에 반영하기 위해서는 위와 같은 번거로운 배포 과정을 무수히 반복해야 했다. 이 반복되는 작업은 피로감도 컸고, 배포 성공률 또한 현저히 떨어졌다.
예를 들어 환경을 Prod로 올려야하는데 Dev로 올려서 DB 연결이 의도한대로 되지 않는다거나, 로컬에서 Gradle로 새롭게 Build한 파일로 Docker Image를 생성해야하는데, 예전 Jar 파일로 컨테이너화 해놓고 왜 변경 사항이 반영 안된건지 하면서 많은 시행착오를 겪었다.
이번 SPOT에서는 위의 경험을 배경으로 하여 CI/CD 파이프라인을 구축하여 체계적이고 안정적으로 코드를 관리하자고 다짐 했다.
또한, 개발해야 할 기능이 많기 때문에, 코드 관리를 철저히 하지 않으면 프로젝트 규모가 커질수록 유지보수가 어려워질 것이라고 판단했다. 그래서 본격적인 개발에 앞서 CI/CD 파이프라인을 도입해 처음부터 체계적으로 코드를 관리하고자 했다.
SPOT은 Github Action을 CI/CD 툴로 사용 했다. 선택한 이유는 다음과 같다.
- 초기 세팅이 간단하다.
- Github 이벤트들에 대해서 간편하게 실행할 수 있다.
- 코드 재사용이 용이하다.
프로젝트 초기 세팅에 그렇게 많은 시간을 투자할 수 없었다. 다양한 CI/CD 툴에 대해서 알아보고 고민 했지만, YAML 파일 하나로 빠르고 간편하게 환경 구축을 할 수 있다는 점이 매력적이었다.
또한, 과거 프로젝트를 진행 하면서 작성해놓은 YAML 파일이 있었기 때문에 해당 코드를 일정 부분 재사용 가능하다는 점도 장점이었다.
Github 이벤트들에 대해 Workflow가 실행 되기때문에 Github를 통해 협업을 진행하는 우리에겐 더욱 좋은 선택지였다.
CI/CD 프로세스는 다음과 같이 진행됐다.
- 각자 develop에서 브랜치를 분기해 작업을 진행 →
- 작업 완료 후 develop 브랜치로 Pull Request를 작성 →
- Github Action에서 빌드 테스트 →
- 빌드 테스트 통과 시 팀원들의 코드 리뷰 후 merge
CD는 main 브랜치를 향한 PR이 merge되면 실행된다.
- develop에서 main으로 PR 작성 →
- merge 후 workflow 작동 →
- Gradle로 Build →
- Dockerfile로 이미지 생성 →
- 내 원격 Docker Hub에 이미지 Push →
- SSH로 배포된 서버 접속 →
- 내 원격 Docker Hub에 이미지 Pull →
- Docker Container 실행
CI/CD 파이프라인에 Docker를 사용한 이유는 다음과 같다.
SPOT 팀의 개발 환경은 다양하다. Windows, MacOS 등 다양한 운영체제를 사용하고 있다. 또한, 배포될 서버는 Ubuntu이다. 이러한 다양한 플랫폼에서 우리가 작성한 코드를 안정적이고 일관되게 실행하려면 Docker로 코드를 컨테이너화하는 것이 필수적이었다.
Docker를 사용하면 각자의 개발 환경이나 운영체제에 구애받지 않고 동일한 환경에서 애플리케이션을 실행할 수 있다.
이를 통해 자주 겪는 문제점 중 하나인 "로컬에서는 작동하지만 서버에서는 작동하지 않는다"는 문제를 방지할 수 있었다. 배포된 서버에서도 개발 환경과 동일한 환경을 보장할 수 있어 배포의 안정성이 크게 향상되었다.
뿐만 아니라, DB나 APM(애플리케이션 성능 관리) 도구를 Docker 컨테이너로 묶어 하나의 네트워크로 관리할 수 있다. 이를 통해 여러 애플리케이션을 서로 격리된 상태로 운영할 수 있었으며, 애플리케이션 간의 충돌을 방지하고 유지보수를 더 쉽게 할 수 있었다.
결과적으로는 만족스러웠다.
총 실행했던 배포 Workflow 40개 중, 37개가 성공적으로 실행 되어 약 92.5%의 성공률을 기록 했다. 실패한 3개의 경우도 APM 도입 과정 중
환경변수 미설정으로 인해 발생했던 오류였다.
CI Workflow도 약 140번 실행 됐고, 총 22번 실패하여 84%의 성공률을 보였다.
CI Workflow 도입으로 인해 코드의 안정성 또한 보장 받을 수 있었다. CI 과정이 없었다면, 문제가 있는 코드가 바로 Repo에 merge 되어 예상치 못한 에러가 배포된 서버에서 발생했을 것이다. 이러한 문제를 테스트 코드를 통해 발견했고, 빠르게 해결할 수 있었다.
데모 데이 직전에는 예상치 못한 이슈나, 누락된 API들을 서둘러 서버에 반영해야 했다.
CI/CD 파이프라인이 구축되어 있지 않았다면, 과거 겪었던 번거로운 과정을 반복했어야 했다. 하지만, main 브랜치에 변경된 코드를 반영 함으로써 배포된 서버에 간단하고 안정적으로 반영할 수 있었다.