김선종 개발자의 초보 설계자의 CI/CD 적용 분투기

『지속적 통합배포 구축은 처음이라』는 ‘[Beyond the book] 『자바 프로젝트 필수 유틸리티』 편’ 참여자의 글을 모아 한 권의 책으로 엮은 무료 전자책입니다.

[Beyond the book]은 책, 그다음 이야기를 전하는 독자참여 프로젝트입니다. 책을 읽고 현업에 적용한 이야기, 책에 소개된 내용 이외의 더 나은 대안은 없는지 등 다양한 주제의 독자 여러분의 기고를 기다리고 있습니다.  



김선종
아티프렌즈(artifriends.com)의 개발자로, 컴퓨터 작업이 즐거워 개발 업계에 발을 들여놓았다. 2009년부터 자바 개발자로 활동하며 다양한 분야의 개발 경험을 쌓았다. 현재는 Go 언어로 블록체인 엔진을 개발하고 있다. 언제나 새로운 배움을 갈구하고 즐기는 괴짜 개발자다.



자바 프로젝트 필수 유틸리티 책을 읽고 지속적 통합/배포CI/CD를 적용한 프로젝트는 개발 매니저PM역할을 맡아 관리하는 부동산 자산평가 서비스 셀리몬(http://sellymon.com)입니다. 책에서 사용된 것과 같은 도구를 사용하지는 않았지만 나름대로 고민하면서 적용한 경험을 공유하려고 합니다.


모든 서비스의 처음이 그렇듯이 셀리몬이라는 서비스는 회사 창업 초기부터 만들어온 서비스입니다. 백엔드 개발자 2명, 프론트엔드 개발자 1명, 디자이너 2명이란 적은 인원이 서비스를 빠르게 만들다 보니, 개발 생산성이나 시스템 구성 측면에서 일부 깊이 고려하지 못한 채로 개발하게 되었습니다.

지금은 백엔드 개발자와 프론트엔드 개발자가 충원되어 시스템의 개발에 대한 부분은 어느 정도 구색이 맞춰진 상태입니다. 국내에만 있는 이상한 업무 역할인 기획자의 역할은 디자인팀 내부에서 기본을 담당하고, 전체 마무리는 관련 서비스의 모든 관련자가 협의하여 처리하는 구조로 일하고 있습니다. 디자인팀을 포함한다면 8명 정도 개발팀만 놓고 보면 5명이 개발하고 있습니다.


기존 개발 환경

그럼 기존의 개발 환경 구성부터 설명하겠습니다. [그림 1]은 우리 회사의 기존 서비스 개발 방식입니다. 이외에 기획이나 디자인 등의 다른 부분이 있으나 내용과 맞지 않아 제외하였습니다.


그림 1 기존 개발환경



그림 1 관해 설명하면 ①번 로컬 환경(IDE, Local Server)에서 개발자가 맡은 기능을 개발합니다. 기능을 개발하면서 단위 테스트를 거치고 빌드한 후에 로컬 서버를 통해 서비스를 구동하여 테스트를 진행합니다.

이때 진행하는 테스트는 개발자의 PC에서 진행하는 테스트입니다. 로컬 서버를 실행하고 서비스 기능을 사용하면서 기능의 동작 여부를 확인합니다. 만약 테스트 도중 버그가 발견되면 다시 개발 단계로 돌아가 기능을 수정하거나 다시 개발하는 일련의 과정들을 반복합니다.

다시 그림으로 돌아가 ①번 로컬 환경에서 이루어지는 빌드, 테스트와 회사 Git 저장소에 코드를 병합Merge하는 것은 개발자 각자가 똑같이 작업하고 있습니다. ②번 서버 환경에서는 메인 배포자가 클라우드 서버에 접속해 수동으로 현재 배포된 소스 코드를 백업하고 배포하는 일련의 과정을 진행합니다.

다시 말해 빌드와 단위 테스트는 어느 정도 CI/CD와 상관없이 진행되지만, 배포와 지속적인 통합에 대한 내용은 CI/CD가 없다면 쉽지 않은 얘기가 됩니다. 


기존 개발 환경의 한계와 CI/CD 도입의 필요성

더불어 서버에서 진행되는 이러한 과정이 사람이 직접 수행하다 보면 휴먼 에러Human Error로 인해 어쩔 수 없이 문제가 생기기도 합니다.

③번의 경우처럼 로컬 환경에서 테스트하는 도중에 버그가 발견되어 다시 개발하는 것은 문제가 되지 않습니다. 실제로 서비스하기 전이기 때문입니다. 하지만 ②번의 실 서비스 운영 환경, 특히 테스트용 운영 서버가 없는 상황에서 문제가 발생하면 서비스의 매출에 큰 손해가 발생합니다. 그때는 밤낮을 가리지 않는 비상상황이 되며, 문제를 무조건 해결해야 합니다. 그것도 최대한 빨리 해결해야 하죠.

특히나 사람에 의한 문제인 경우는 원인이 다양합니다. 이전에 사용하던 소스 코드가 배포됐다거나, 서버에서 급하게 수정한 버그가 수정되지 않은 채 신규 기능이 추가되어 배포되는 등 알기가 힘든 원인인 경우가 많습니다. 때론 아주 작은 실수로 인해 문제가 발생하기도 합니다.

이로 인해 서비스가 중단되거나 오류가 발생하는 일은 일상이 될 수 있습니다. 자연스레 고객은 서비스를 이용하지 않게 되고, 이는 매출 하락으로 이어져 심각한 경우 회사가 망하게 되지요( ..)

때문에 ①번 환경에서 아무리 완벽하게 테스트를 한다고 해도 ④번의 경우를 완벽하게 없애기란 쉽지 않기 때문에 사람의 영향이 최대한 적은 CI/CD 환경을 구축하는 것이 매우 중요합니다.

지금 회사의 경우 서비스의 프론트엔드 부분을 신규 입사자도 쉽게 개발할 수 있도록 새롭게 구성해야 했습니다. 사내에서 사용 중인 서비스 중 Git과 Travis CI를 이용하면 개발자들이 좀 더 쉽게 개발을 할 수 있을 것입니다. 이런 연유로 프론트엔드 부분을 설계하면서 CI/CD 환경도 함께 구성하기로 했습니다.


지속적인 통합 도구 Travis CI

최근에는 CI/CD 도구가 다양하게 출시되면서 통합개발환경을 구성하는 데 선택의 폭이 넓어졌습니다. 국내에서 가장 많이 알려진 도구는 오픈소스로 제작된 젠킨스Jenkins입니다. 『자바 프로젝트 필수 유틸리티』(한빛미디어, 2018) 책에서도 소개하고 있습니다. 무료로 사용할 수 있다는 점과 플러그인Plug-in으로 여러 환경에서 사용할 수 있다는 점 때문에 많은 기업이 사용하고 있습니다. 그 외에도 CircleCI, Travis CI, Bitries, Visual Studio App Center, TeamCity, GoCD, Bamboo, GitLab CI, Codeship, Codefresh, Nevercode 등 많은 제품이 있으니 가격 정책과 환경에 맞게 구성하여 사용하시면 됩니다.

저희는 현재 Travis CI를 이미 사용하고 있었기 때문에 추가 이용에 대한 비용 없이 적용할 수 있었습니다.

만약 Travis CI를 사용하고 Git을 사용해 소스 코드를 관리하고 있다면 Travis CI에 가입하고 Git의 계정과 연동하면 바로 사용할 수 있습니다. Travis CI에 Git 계정으로 로그인하면 자동으로 연동 화면이 나타나고, 연동 후에는 Git의 Profile 화면의 Applications에 [그림 2] 같은 Travis CI의 설정 항목이 추가됩니다.


그림 2 GitHub Profile Applications 메뉴


[Configure] 버튼을 클릭해 설정 화면을 엽니다. 그림 3 화면처럼 Git의 Repository를 추가하는 화면이 나타납니다.


그림 3 GitHub의 Travis CI Repository 접근 권한 설정 화면



[All repositories]를 선택하여 전체 저장소를 전부 포함하거나, [Only select repositories] 항목을 선택하여 특정 저장소만을 선택할 수 있습니다. 그림에는 보이지 않지만 스크롤을 더 내리면 [Uninstall Travis CI] 버튼이 있는데 해당 버튼은 당연히 GitHub와 연동한 Travis CI를 제거하는 것입니다. 따라서 Travis CI를 쓰지 않기로 했을 때만 클릭하기 바랍니다.

그럼 이제 연동도 끝났으니 Travis CI가 알아서 해줄 것 같습니다. 내가 원하는 저장소 또는 전체 저장소를 선택하여 저장하고 Travis CI에 접속해보면 아무것도 실행되지 않습니다. 이유는 Travis CI가 동작하는 데 필요한 기본적인 설정 파일이 저장소 내에 없기 때문입니다.

GitHub 와 연동한 Travis CI가 자동으로 실행되기 위해서는 저장소의 루트에 Travis CI에서 실행될 명령어와 환경 정보가 입력된 설정 파일(.travis.yml)이 필요합니다.

저는 프론트엔드 환경에서 Travis CI를 사용한 통합 개발환경을 구성하기로 했기 때문에 Node를 사용하는 환경설정으로 파일을 구성했습니다. 거기에 AWS로 배포하므로 배포를 위한 AWS 정보를 추가로 설정 파일에 적었습니다.


그림 4 .travis.yml 파일 내용


[그림 4]의 각 항목의 의미는 다음과 같습니다.

  • language : 빌드나 테스트 대상 언어 정보
  • node_js : 대상 언어의 버전
  • install : 환경 파일이나 기타 의존성dependency 파일의 설치 명령어
  • script : 테스트, 빌드 명령어
  • deploy : 코드를 업로드할 서버 대상 정보


이 항목 외에도 CI/CD에 도움이 될만한 항목은 많습니다. 더 자세한 정보는 Travis CI Document에서 확인할 수 있습니다.

아래 [그림 5]는 Travis CI를 사용하여 새롭게 구성한 통합 개발환경의 워크플로우입니다.


그림 5 Git과 Travis CI를 사용한 워크플로우



그림 5를 살펴보면 기존 개발환경과 Git을 사용하는 것은 같고 추가로 Travis CI를 사용해 빌드하고 배포하고 있습니다. Git에서 소스 코드가 변경되면 Travis CI가 자동으로 감지하여 빌드와 테스트 그리고 배포까지 하도록 최대한 자동화했습니다. 로컬에서 개발하고 테스트하는 환경은 개발자 각자가 구성하는 것이기 때문에 새롭게 구성하는 부분에서는 제외하고, 서버나 CI/CD 도구로서 동작하는 공통적인 부분의 내용만 넣었습니다.

워크플로우를 따라가 보면 [그림1]의 기존 구성에서 ①번 로컬 환경에 대한 부분은 같습니다. 다만 구성을 변경하면서 각 개발자의 유닛 테스트와 로컬 서버 환경에서의 통합 테스트가 더 중요해지게 됩니다. 특히 개발자가 미리 테스트 케이스를 생각해 만들어 두면, CI/CD 도구에서 자동으로 빌드하고 테스트를 하는 과정에서 오류 사항을 찾아 개발자나 배포자에게 바로 알려줄 수 있기 때문입니다.

그렇기 때문에 Jenkins 나 Travis CI 같은 CI/CD 도구를 제대로 사용하기 위해서는 충분한 테스트 케이스가 코드 내에 포함되어야 합니다. 지금 당장은 개발 도중이니 테스트용 운영 서버 없이 구성하였지만, 나중에 제대로 서비스되기 시작하면 테스트와 서비스용 운영 서버를 나눠 최대한 버그가 생길 확률을 낮춰야 합니다. 

[그림 6]을 보면 GitHub에 코드를 병합Merge한 후 자동으로 Travis CI 도구에서 빌드하고 만들어진 유닛 테스트를 실행하는 모습입니다.


그림 6 Travis CI 결과 화면


마치며

아직 프로젝트를 진행 중이어서 완벽한 결과물을 뽑아내지는 못했습니다. 첫술에 배부를 수 없듯이 지금 당장 제대로 동작하지 않는다고 하여 시작도 하지 않는 것은 회사든 직원이든 발전하지 못하는 걸림돌이된다고 생각합니다. 불완전하지만 우리는 이렇게 시작을 했고, 앞으로도 제대로 활용해 적용하는 일만 남았습니다.

회사의 기본적인 문화가 TDDTest Driven Development를 지향하는 만큼 아직은 회사 동료가 익숙하지 않은 TDD를 하는 것만도 쉽지 않지만, CI/CD를 제대로 구성하기 위해서는 어떻게든 넘어야 하는 산입니다. CI/CD가 제대로 구성되기 위해서는 잘 구성된 테스트 케이스가 필수 불가결인 만큼 차근차근 제대로 만들어가야 하는 책임감과 무게도 함께 느끼고 있습니다.


여기서 소개한 내용은 아직 완벽하지는 않습니다. API 서버에 적용, 로그 처리, 서비스 중단 없는 배포 적용, 백업의 구성, 배포되는 소스 코드의 버전 관리, 테스트가 부족한 부분 보완 등 서비스 무결성을 위해 해야 하는 작업은 아주 많습니다.

하지만 지금 구성만으로도 개발자는 단순히 로컬 환경에서 개발이 끝난 소스 코드를 회사 저장소에 풀 리퀘스트Pull Request를 하는 것으로 일이 끝나게 됩니다. 이전에는 배포하려면 서버에 접속해서 GitHub에서 소스 코드를 받아서 실행되고 있는 서비스를 중단하고 새로운 소스 코드로 서비스를 다시 시작하는 일련의 작업을 하지 않아도 되는 거죠. 그만큼 신경 써야 하는 부분은 줄었고 개발의 생산성 향상이란 이점을 챙길 수 있었습니다.

제가 고생한 만큼 회사 동료 개발자가 편하게 일할 수 있다면 그만큼 저도 보람을 느낄 수 있을 테지요. 많은 회사에서 CI/CD를 도입하고 활용해 개발에만 집중할 수 있는 환경이 여러 회사에 전파되길 바라며 글을 마칩니다.

 


자바 프로젝트 필수 유틸리티

쇼다 츠야노 , 전민수