본문 바로가기

Programming

CI/CD - 위대한 자동화의 힘

프로젝트 링크

 

TimJLee/Lets-boot

Side project_ 스프링부트로 게시판 만들고 무중단 배포까지. Contribute to TimJLee/Lets-boot development by creating an account on GitHub.

github.com

들어가기에 앞서

 

  이번에 사이드 프로젝트로 스프링 부트와 AWS 를 이용하여 간단한 게시판을 구현해 보았다. 서버개발캠프에서 다른 팀이 사용한 CI/CD 툴 중 travis CI, CodeDeploy를 보고 처음에 '저건 뭐지? 나도 한번 써보고 싶다.' 라는 생각이 들었고, 캠프가 끝나자마자 이에 대해 공부하기 시작했다. 처음에는 왜 사용하는지 잘 이해가 가지 않았다. 빌드를 자동화 한다는 건 무엇이고, 배포를 자동화한다는 건 또 무엇이란 말인가? 또 새로 공부해야 할 게 산더미처럼 불어났다고 생각이 되는 순간 머리가 아파왔다. 그러던 중 이동욱님이 쓰신 '스프링 부트와 AWS 로 구현하는 나만의 웹서비스' 라는 책을 알게 되었고, 내가 기존에 배우고자 했던 Spring Boot 와 AWS 관련 개념들이 다 담겨져 있었기에 고민없이 바로 주문을 하게 되었다. 그 후 3주(?) 가 지난, 책을 1회독하고 코드를 다 구현하여 클라우드에 배포까지 완료한 상태인 지금 회고를 시작해보고자 한다.

사실 개발일지를 보신 분은 알겠지만, 2회독을 하는것이 목표였다.. 책을 여러번 보는 건 참 인내심이 필요한 일이라 회고를 계기로 2회독을 하는것으로..ㅎ
 

과정지향적인 개발자가 되자

돌아보며 이번 방학동안 진행한 서버개발캠프에서 팀원들과 프로젝트를 진행하는 과정 속에서 나의 아집을 버리고 팀원들을 믿고 꾸준히 소통하는 것이 효율적인 팀빌딩임을 깨닫게 되었다. ��

creakycogwheel.tistory.com

사실 난 위에서 언급했듯이, 컴파일과 빌드의 차이를 알지 못했다.(빌드가 컴파일과 같은 개념이라고 생각했다... 부끄럽다) 그래서 코드를 번역하고 실행가능한 파일이 되기까지의 과정에서 중요한 개념인 컴파일, 링크, 빌드에 대해서 먼저 알아보자. 

 

1. 컴파일(Compile)

 

  컴파일이란 개발자가 작성한 소스코드를 바이너리 코드로 변환하는 과정을 말한다. (오브젝트 파일이 생성됨) 

즉, 컴퓨터가 이해할 수 있는 기계어로 변환하는 작업이다. 이러한 작업을 해주는 프로그램을 가리켜 컴파일러(Compiler)라 한다.

자바의 경우, 자바가상머신(JVM)에서 실행가능한 바이트코드 형태의 클래스파일이 생성이 된다.

 

2. 링크(link)

 

  프로젝트를 진행하다 보면 소스파일이 여러개가 생성되고 A라는 소스파일에서 B라는 소스파일에 존재하는 함수(또는 메서드)를 호출하는 경우가 있다.

이때 A와 B 소스파일 각각을 컴파일만 하면 A가 B에 존재하는 함수를 찾지 못하기 때문에 호출이 불가능하다. 

그래서 A와 B를 연결해주는 작업이 필요하며, 이 작업을 링크라고 한다.

다시말해, 여러개로 분리된 소스파일들을 컴파일한 결과물들에서 최종 실행가능한 파일을 만들기 위해 필요한 부분을 찾아서 연결해주는 작업이다.

링크는 정적링크(static link)와 동적링크(dynamic link)가 있다.

  • 정적링크 - 컴파일된 소스파일을 연결하여 실행가능한 파일을 만드는 것
  • 동적링크 - 프로그램 실행 도중 프로그램 외부에 존재하는 코드를 찾아서 연결하는 작업
자바의 경우, JVM이 프로그램 실행 도중 필요한 클래스를 찾아서 클래스패스에 로드를 해주는데 이는 동적링크의 예이다.

 

3. 빌드(Build)

 

  소스코드 파일을 실행가능한 소프트웨어 결과물로 만드는 일련의 과정을 말한다. 

빌드의 단계 중 컴파일이 포함이 되어 있으며, 따라서 컴파일은 빌드의 부분집합이다.

이때, 빌드 과정을 도와주는 도구를 빌드 툴이라 한다.

Gradle 이냐 Maven 이냐.. 그것이 문제로다 - Spring Boot 를 시작하기 전 정말 많은 고민을 했지만, 별 의미가 없는 고민이었다

 

3-1. 빌드 툴(Build Tool)

 

  일반적으로 빌드 툴이 제공해주는 기능으로는 다음과 같은 기능들이 있다.

전처리(preprocessing), 컴파일(Compile), 패키징(packaging), 테스팅(testing), 배포(distribution)

빌드 툴로는 Ant, Maven, Gradle 등이 있다.

 

CI/CD 를 사용하는 이유

 

  현대의 웹 서비스를 개발할때에는 하나의 프로젝트에 여러명의 개발자가 붙어서 작업을 진행한다. 그러다 보니 각자가 개발한 코드를 합치는 일은 매우 큰 일이었다(물론 이번 개발캠프에서는 모놀리틱 방식이 아닌 마이크로서비스 아키텍쳐로 진행을 했기에 코드 충돌이 거의 없어서 이 점은 살짝 공감이 안간다. 내가 아직 병아리라 그럴 가능성이 높다). 그래서 매주 병합일(코드 Merge 만 하는 날)을 정하여 이날은 각자가 개발한 코드를 합치는 일만 진행했을 정도라고 한다(빌드 전문가가 따로 있을정도).

이런 수작업 때문에 생산성이 좋을 수가 없었고, 개발자들은 지속해서 코드가 통합되는 환경(CI)을 구축하게 된다. 개발자 각자가 원격 저장소(깃허브 등)로 푸시가 될 때마다 코드를 병합하고, 테스트 코드와 빌드를 수행하면서 자동으로 코드가 통합됨으로써 더는 수동으로 코드를 통합할 필요가 없어지면서 자연스레 개발자들 역시 개발에만 집중할 수 있게 된다.  CD 역시 마찬가지이다. 한두 대의 서버에 개발자가 수동으로 배포를 할 수 있지만, 수백 대의 서버에 배포를 해야 하거나 당장 급하게 배포를 해야 하는 상황에서 수동으로 배포하는 것은 매우 어려운 일이다(거의 불가능에 가깝다고 한다). 이 역시 자동화를 하게 되었고, 개발자들은 개발에만 집중할 수 있게 되었다고 한다. 

하지만... Travis CI 와 같은 CI 툴을 도입하여 프로젝트를 했다고 해서 과연 CI 를 했다고 할 수 있을까?

마틴 파울러는 이에 대해 진정한 CI 를 하려면 다음과 같은 4가지 규칙을 지켜야 한다고 말한다. 

  1. 모든 소스 코드가 살아 있고(현재 실행되고) 누구든 현재의 소스에 접근할 수 있는 단일 지점을 유지할 것. 
  2. 빌드 프로세스를 자동화해서 누구든 소스로부터 시스템을 빌드하는 단일 명령어를 사용할 수 있게 할 것.
  3. 테스팅을 자동화해서 단일 명령어로 언제든지 시스템에 대한 건전한 테스트 수트를 실행할 수 있게 할 것. 
  4. 누구나 현재 실행 파일을 얻으면 지금까지 가장 완전한 실행 파일을 얻었다는 확신을 하게 할 것.

여기서 특히 중요한것은 테스팅 자동화이다. 지속적으로 통합하기 위해서는 무엇보다 이 프로젝트가 완전한 상태임을 보장할 수 있어야 하기 때문이다. 이때, 테스트 코드가 구현이 잘 되어있어야만 한다(이래서 테스트코드 작성이 여러모로 중요한 것 같다)

 

그래 다 알겠고, 그래서 CI/CD 가 뭔데?

 

  24시간 365일 연중무휴로 운영되는 서비스에서 배포 환경 구축은 필수 과제 중 하나이다. 여러명의 개발자가 작성한 코드가 실시간으로 병합이되고, 테스트가 수행이 되는 환경에서 master 브랜치가 체크인(푸시)되면 배포가 자동으로 이루어지는 환경을 구축하지 않으면 실수할 여지가 많아진다. 단지 스프링 부트 프로젝트를 AWS EC2 에 배포하고 끝나면, 로컬에서 코드를 수정하고 깃허브에 푸시한 후에 putty로(windows 기준) EC2에 접속해서 github에 올라온걸 pull 하고, 테스트를 돌리고, 빌드를 돌리고... 해야 할 자잘한 작업들이 너무 많아지게 된다. 그래서 나도 이 책을 보면서, 빨리 자동 빌드와 자동 배포를 경험해 보고 싶다는 갈증이 심했다. 그런데, CI/CD 는 이 모든 귀찮은 작업을 자동화 시켜줌으로써 우리를 편하게 해준다. CI(Continuous Integration - 지속적 통합) 는 코드 버전 관리를 하는 VCS 시스템(Git, SVN 등)에 푸시가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정이다. 일반적으로 빌드만 자동화 시키지 않고, 배포까지 자동화를 시킨다. CI 툴은 대표적으로 다음과 같이 세가지가 있다.

  • Travisi CI(Github) - 내가 사랑하는 깃허브에서 제공하는 툴이다! 게다가 무료라니! 깃허브에 프로젝트가 올라가 있으면 세팅이 매우 쉬워진다. 나는 이 툴을 사용하여 CI 를 구현하였다.
  • Jenkins - 예전부터 정말 사용하고 싶었지만(아이콘이 멋있게 생김..ㅎ) 설치형이기 때문에 이를 위해 기존의 EC2 서버 외에 젠킨스를 위한 EC2 인스턴스가 하나 더 필요하다는 말을 듣고 이별하였다. 
  • CodeBuild(AWS) - AWS 라서 매력적이다. 하지만 빌드 시간만큼 요금이 부과되는 구조라서 공짜를 좋아하는 나로써는 사용하기 부담스러웠다. 

CD(Continuous Deployment - 지속적 배포)는 CI를 통해서 생성된 jar 파일을 전달 받아서 서버에 자동으로 배포해준다. CD 툴로는 대표적으로 CodeDeploy 가 있는데, 이것은 빌드와 배포 둘 다 해준다. 하지만, 빌드와 배포를 분리시키기 위해서 나는 Travis CI 로 빌드한 결과 jar 파일을 AWS S3 로 전달하고, 이후 CodeDeploy 로 jar 파일을 넘겨서 배포하는 식으로 빌드와 배포를 분리함으로써 배포만 해야하는 경우에 대비할 수 있게 아키텍쳐를 저자의 조언에 따라 구성하였다. 즉, 빌드와 배포가 분리되어 있으면 예전에 빌드되어 만들어진 Jar 를 재사용할 수 있기 때문에 확장성이 높아진다. 

 

 


참고자료

 

  •  CI, CD 관련 개념과 프로젝트 진행 참고 - 스프링 부트와 AWS로 혼자 구현하는 웹 서비스, 이동욱 
  • 컴파일, 빌드, 링크 개념 참고 - https://freezboi.tistory.com/39

 

 

 

'Programming' 카테고리의 다른 글

Markdown 문법 총정리  (0) 2020.04.28