다양한 형태의 소프트웨어들(OS, 응용프로그램, WAS, DB, 오픈소스, 3rd party 프레임워크, 라이브러리 등)은 공통점을 가지고 있습니다. 소프트웨어의 버전(Version) 입니다. 그리고 대부분 Release Note 라는 문서 파일이 같이 포함되어 어떤 버그가 수정되었는지, 어떤 기능이 추가되었는지, 또는 어떤 개선이 이루어져있는지 등의 정보를 소프트웨어를 사용하는 클라이언트에게 제공하고 있습니다.

진화하는 소프트웨어, 하지만 항상 1.0.0-SNAPSHOT

지난 수년간 소프트웨어를 만들어오면서 버저닝(Versioning)을 해본 경험은 많지 않았습니다. 어찌보면 지금까지 필요성을 못 느꼇던 부분도 있고, 어떻게 하는지 몰라서 혹은 해본적이 없어서 일 것입니다.

대부분 프로젝트 생성시 POM(우리가 소프트웨어 빌드 도구로 대부분 Maven을 많이 사용하기 때문에 Maven 기준으로 글을 작성하였습니다.) 파일에 0.0.1-SNAPSHOT 혹은 1.0.0-SNAPSHOT 으로 시작하게 되고, 시간이 흐르면서 소프트웨어는 변화 하지만 버전은 영원히 동일하게 유지되는 경우가 많았습니다.

계속  1.0.0-SNAPSHOT 버전을 유지하면서 ‘오류 수정하고 배포 하였으니 의존관계를 업데이트 받고 다시 해봐!!’ 라고 다른 팀에게 말로 전하기도 하고, 버전체계가 있기는 하지만 수동으로 버전을 관리하거나 배포할 때만 '이건 버전이 몇이다!!' 라고 전하는 경우도 있었습니다. 심지어는 있던 버전관리 체계가 귀찮은 작업으로 취급되어 없어지는 현상도 목격 했습니다.

소프트웨어 버전의 필요성

우리가 만드는 소프트웨어를 버전관리 하지 않는다고 문제가 있는 것은 아닙니다. 소프트웨어가 단일 모듈이거나 규모가 작아서 관리가 어렵지 않고,  개발 초기단계처럼 빈번한 변화가 발생하는 등의 경우는 오히려 소프트웨어 버저닝이 오버헤드가 될 수 있습니다.

버전은 소프트웨어에 유일한 식별 번호를 부여하여 관리와 커뮤니케이션을 용이하게 하기 위한 목적이 강합니다.

패키징되어 고객에게 전달되는 제품, 차세대와 같은 대규모의 프로젝트, 여러 팀이 개발한 소프트웨어 간의 복잡한 의존관계가 발생하는 경우 버저닝은 다음과 같은 상황에서 유용한 커뮤니케이션의 용도로 활용되고, 관리를 용이하게 합니다.

  • 어떤 버전에서 발생하는 버그(bug) 였는지, 어떤 버전에서 픽스(fix) 되었는지
  • 어떤 버전에서 기능이 추가/삭제 되었는지, 무엇이 변경되고 개선이 되었는지
  • 소프트웨어를 사용하는 클라이언트는 어떤 버전을 사용하고 있는지

소프트웨어 릴리스(Release)

제가 진행했던 프로젝트에서 소프트웨어 릴리스는 다음과 같은 절차를 거쳐 수행하게 됩니다.

  1. 릴리스 되는 모듈의 전체 소스코드 SVN checkout/update
  2. 릴리스 되는 모든 모듈의 단위테스트 수행하여 점검
  3. 모듈의 모든 POM 파일의 SNAPSHOT 버전을 RELEASE 버전으로 변경후 SVN commit(1.0.0-SNAPSHOT -> 1.0.0-RELEASE)
  4. 릴리스 버전을 SVN Tagging 하여 해당 버전의 소스코드를 유지
  5. 릴리즈 버전 빌드(JAR, WAR)
  6. 모듈의 모든 pom.xml 파일의 버전을 다음 SNAPSHOT 버전으로 변경후 SVN commit(1.0.0-RELEASE -> 1.0.1-SNAPSHOT)
  7. 통합 저장소(Nexus)에 배포(Deploy)
  8. 릴리스 공지(EMAIL)

최대한 빨리 오류수정 및 기능 추가하고 배포해야 하는데 릴리스 절차가 생겨나면서 위의 번거로운 작업들을 하기란 쉽지 않았습니다.

릴리스를 간편하게

제가 참여했던 차세대 프로젝트는 업계 1위의 서비스를 제공하고, 그에 맞게 규모 또한 상당했습니다. 각 팀에서 개발하고 있는 단위 모듈 또한 전체 합하면 수십 개가 넘었습니다.(JAR, WAR 갯수로 헤아려 보면 수백개는 될 것입니다.) 그리고 서로간의 복잡한 의존관계를 가지고 있었습니다.

앞서 작성한 이유에 의해 분명 릴리스는 반드시 필요했습니다. 하지만 위의 절차대로 진행하도록 모든 팀에게 요구하기에는 쉽지 않은 일이며, 게다가 환경에 익숙하지 않은 엔지니어들에게는 변경된 소프트웨어를 상용화 하기란 여간 어려운 것이 아니었습니다.

그래서 각 팀에서 릴리스를 최대한 편하게 할 수 있는 방안을 마련하고자 하였습니다...

Maven Release Plugin + Jenkins

프로젝트에 구성된 환경은 다음과 같습니다.

프로젝트에 구성된 릴리스 환경

Maven Release Plugin

Maven Release Plugin은 Maven의 추가 플러그인으로 우리가 필요했던 위의 1~7번 릴리스 절차를 쉽게 처리할 수 있도록 지원합니다.(프로젝트에서는 maven-release-plugin-2.2.2 버전을 사용했습니다.)

릴리즈 되는 모듈의 POM에는 SCM 정보와 Maven Release Plugin이 선언되어 있어야 합니다.

릴리스 대상 모듈의 pom.xml의 Maven Release Plugin 선언

릴리스 대상 모듈의 pom.xml의 SCM 정보

Maven Release 과정은 크게 두 단계(prepare, perform)로 구분됩니다.

prepare : 릴리스 준비단계

  1. 소스코드 오류 체크
  2. 의존관계를 가지고 있는 하위 모듈에 SNAPSHOT이 포함되어 있는지 체크(릴리스되는 모듈은 의존관계에 있는 하위 모듈의 SNAPSHOT 버전이 없어야 합니다.)
  3. 릴리스되는 모듈들의 POM에 존재하는 x-SNAPSHOT 버전을 릴리스 버전으로 변경
  4. POM의 SCM 정보(TAG경로) 변경
  5. 릴리스되는 모듈들의 전체 단위테스트 수행
  6. POM의 모든 변경된 정보를 commit
  7. SCM Tagging 수행
  8. POM의 정보를 다음 개발버전 y-SNAPSHOT으로 변경
  9. POM의 변경정보 commit

release prepare 예시(릴리스버전, 다음개발버전, TAG명 등을 터미널에서 입력받습니다.)

perform : 실제 릴리스 수행

  1. prepare 단계에서 TAG된 위치로부터 소스코드 체크아웃
  2. 릴리스 수행(빌드 및 통합저장소에 릴리스 버전 Deploy)

release perform 예시

자세한 옵션 및 설정 방법은 http://maven.apache.org/maven-release/maven-release-plugin/index.html 참조

Jenkins

Maven Release Plugin 만으로도 릴리스를 수행할 수 있습니다. 하지만 터미널에서 작업해야 하기 때문에 익숙하지 않은 엔지니어에게는 명령문과 절차들을 기억해야 하기 때문에 작업의 번거로움이 있습니다.

그래서 편리하게 Maven Release를 수행할 수 있도록 UI를 제공하기 위해 Jenkins를 도입 하였고, Maven Release Plugin의 기능을 사용할 수 있도록 Jenkins에서 제공하는 플러그인을 추가로 설치하였습니다.

* 설치버전(Jenkins ver 1.480, Jenkins Maven Release Plug-in Plug-in ver 0.9.1)

Jenkins에 설치된 Maven Release Plugin을 위한 Plugin

위와 같이 Maven Release Plugin을 위한 Plugin이 설치된 Jenkins는 다음과 같이 Maven Release를 위한 기능이 Jenkins UI 상에서 제공됩니다.

Jenkins에서 Maven Relase 기능 제공

Jenkins Job 설정에 보면 Maven Release를 터미널에서 수행 시 입력했던 정보를 받는 항목이 다음과 같이 추가되어 있습니다.

Jenkins에서 Maven Release prepare, perform 설정

실제로 릴리스를 수행할 때에는 Jenkins에 플러그인으로 새로 추가된 기능인 Perform Maven Release를 선택하여 릴리스 버전, 다음 개발버전, SCM 계정, SCM TAG명 등을 입력 받고 수행하게 됩니다.

Perform Maven Release 수행

위와 같이 설정이 되었으면 앞으로는 릴리스 수행 시 Perform Maven Release를 실행하여 간단한 정보만 입력 후 수행하게 됩니다. 그러면 우리가 필요했던 릴리스 절차들을 부담 없이 수행할 수 있습니다.

또한 Jenkins의 기본 기능인 Job 이력을 확인함으로써 릴리스를 언제, 누가, 어떤 버전으로 수행했는지 다음과 같이 확인할 수 있습니다.

Jenkins의 Maven Release Job 이력

[참고#1]릴리즈 모듈

우리가 작성한 소프트웨어는 대부분 여러 개의 프로젝트로 존재하며 서로간의 의존관계를 가지고, 각각의 빌드된 결과물이 생성되게 됩니다.

릴리즈를 위해서는 어떤 프로젝트들이 묶여 하나의 버전체계를 가질 것인지를 선택하는 것이 중요 합니다.

아래 그림은 플랫폼의 basecamp 모듈로 여러 개의 프로젝트들(Sub Modules)이 하나의 버전체계를 가지고 있습니다.

모듈 구조와 최상위 pom.xml
하나의 버전체계를 가지는 Sub Modules

[참고#2]버전 체계

아래와 같이 일반적인 버전 규칙을 제안하였습니다.

버전체계

정리

차세대 프로젝트 플랫폼의 역할을 수행하며 여러 팀에서 개발, 운영 되는 시스템 전반적으로 튼튼하게 유지할 수 있는 방향을 찾기 위해 고민이 많았습니다. 이글의 내용도 그의 일부분 입니다.

버전체계, 릴리스와 관련해서도 고객들, 각 업무 개발 팀들과 여러차례 회의를 거치면서 "릴리스를 시도해보자, 아니다 그냥 SNAPSHOT으로 유지하고 다른 방법으로 관리하자!" 등등 의견이 분분 했습니다.

결론적으로 모든 팀에서 소스코드 상용화 시 릴리스 프로세스를 가지도록 결정하였고, 1년여 기간 동안 지켜본 결과 개발자들이 릴리스 과정에 부담은 거의 없었습니다. Jenkins UI 상에서 몇가지 간단한 정보만 입력 후 실행만 시키면 되기 때문입니다.

자주 접하는 도구인 Maven 과 Jenkins를 "플러그인들을 추가해서 이런 용도로도 사용할 수 있구나~" 정도 기억하고 릴리스가 필요할 때 적용해 보거나 더 나은 방법을 찾기 위해 다른 방법과 비교해보면 좋을 것 같습니다.

namoosori
안녕하세요. 나무소리 입니다. 나무소리는 넥스트리(주)의 교육 브랜드 입니다.넥스트리가 지난 20년 동안 쌓아온 개발 및 교육 경험들을 나무소리를 통해 많은 분들과 공유 하려고 합니다.앞으로 저희 나무소리를 통해 보다 나은 교육을 경험 하실 수 있도록 구성원 모두 최선을 다하겠습니다.