ALM/Build Automation (빌드 자동화)

maven으로 환경별도 다르게 패키징 하기 & RPM 패키징 #2/2

Terry Cho 2013. 4. 15. 23:05

Plug in 을 통한 maven 빌드 확장


앞글에서 http://bcho.tistory.com/739 maven을 이용한 가장 기본적인 빌드 시나리오에 대해서 살펴보았다.

maven plug in이라는 기능을 통해서, 여러 기능 들을 추가로 빌드 프로세스내에 추가할 수 있는데, 여기서는 빌드에서 확장하여, 배포 환경 별로 패키징 하는 시나리오를 추가해보기로 한다.

 

다음과 같은 시나리오를 생각해보자, 빌드에 의해서 생성된 웹 애플리케이션은 내 local PC에서도 돌아가야 하며, 다른 개발자와 협업하는 서버의 개발환경에서도 돌아야 하고, 개발 주기마다 주기적으로 QA환경에서 테스트를 받은 후, staging 환경을 거쳐서 최종적으로 production 환경에 배포 되어야 한다고 가정하자.

 

Java Version 지정하기

먼저 대상 환경에 맞는 컴파일 run time시에 소스 코드에 대한 java 버전과, target compiler java 버전을 지정할 있다. 아주 기본적인 내용인것 같지만, 실제 빌드 과정에서 java 버전을 명시적으로 지정하지 않아서 run time등에서 문제가 생기는 경우가 의외로 많다. 예를 들어 runtime jvm 버전이 1.5인데, 최신 버전으로만 컴파일을 하는 것을 정책으로 잡아놓고 1.7로만 컴파일이 되게 하면, 빌드 스크립트에 의해서 컴파일된 바이너리는 run time에서 작동하지 않는다.

 

             <!--  compiler plug in -->

             <plugin>

                <artifactId>maven-compiler-plugin</artifactId>

                       <version>3.0</version>

                <configuration>

                    <source>1.5</source>

                    <target>1.5</target>

                </configuration>

              </plugin>

 

개발환경 별로 컴파일 하기

이를 지원하는 배포 프로세스는 뒤에서 다시 설명하기로 하고, 여기서는 이러한 다중 환경을 지원하기 위해서 같은 소스 코드로 어떻게 다르게 packaging을 할 것인가에 대해서 고민해보자, 각 환경이 다르면, dbms를 접근하기 위한 db url, id,password도 다를 것이며, 기타 디렉토리 구조나, 다른 서버의 ip등이 모두 다를 것이다.

즉 배포 target에 따라서 다른 빌드 프로세스를 타야 한다는 것이다.

 


이를 maven에서는 profile이라는 것으로 지원할 수 있다.

지금 소개하는 Sample 시나리오는 이러한 설정 정보를 WEB-INF/config/config.properties에 정의했다고 하고, 빌드 target에 따라 각각 다른 config.properties 파일을 패키징 하는 시나리오이다.

각각 다른 환경의 config 파일을 저장하기 위해서 ${basedir} 아래에 다음과 같은 이름으로 디렉토리를 만든다.

 

${basedir}/resource-local     : PC 용 설정 정보

${basedir}/resource-dev               : 공용 개발 서버용 설정 정보

${basedir}/resource-qa        : QA 환경용 설정 정보

${basedir}/resource-stage     : Staging 환경용 설정 정보

그리고 각 디렉토리 아래 WEB-INF/config/config.property를 각 환경에 맞게 정의한다.
다음 예제는 dev 환경용 설정 파일이다.

mybatis.jdbc.driverclass=com.mysql.jdbc.Driver

mybatis.jdbc.url=jdbc:mysql://localhost:3306/development

mybatis.jdbc.username=developer

mybatis.jdbc.password=developer

 

s3.url=developer_s3

이렇게 설정한 디렉토리는 다음과 같은 구조를 가지게 된다.

 


 

다음으로, maven pom.xml에서 환경에 맞게 위에 지정한 파일들을 포함해서 패키징 하게 해야 한다. 이를 maven에서는 profile이라고 하고, 다음과 같이 정의한다. 각 빌드 환경마다 여기서는 <environment> 라는 환경 변수를 지정하게 하였다.

<!--  profile definition -->

    <profiles>

        <profile>

               <id>local</id>

               <properties>

                       <environment>local</environment>

               </properties>

        </profile>

        <profile>

               <id>dev</id>

               <properties>

                       <environment>dev</environment>

               </properties>

        </profile>

        <profile>

               <id>qa</id>

               <properties>

                       <environment>qa</environment>

               </properties>

        </profile>

        <profile>

               <id>stage</id>

               <properties>

                       <environment>stage</environment>

               </properties>

        </profile>

  </profiles>

 

그리고 빌드시 ${basedir}/resource-{environment} 디렉토리를  webapp/ 아래에 복사하도록 하고자 한다. 이를 위해서는 war를 패키징 하는 war 플러그인의 속성세 web-resource (WEB-INF 디렉토리)를 빌드 타겟에 맞게 선택이 되도록 다음과 같이 지정한다.

환경에 맞게 정의한다.
다음 예제는 dev 환경용 설정 파일이다.

             <!--  war plug in  -->

             <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                       <artifactId>maven-war-plugin</artifactId>

                       <version>2.3</version>

                       <configuration>

                               <warSourceDirectory>${basedir}/src/main/webapp</warSourceDirectory>

                              <webResources>

                                      <webResource>

                                                     <directory>${basedir}/src/main/resources-${environment}</directory>

                                      </webResource>

                              </webResources>

                       </configuration>

               </plugin>

 

여기 까지 진행한 후에, 각 환경에 맞게 packaging을 하기 위해서는 mvn에서 -P{environment} 이름을 적어주면 된다.

예를 들어 qa환경용으로 war 파일을 만들기 위해서는

 

% mvn -Pqa package

 

와 같이 명령을 실행하면 된다.

 

RPM으로 패키징 및 배포 하기

maven의 빌드 패키징의 문제가 java에 관련된 jar, ear 또는 war 파일만 딱 생성하고 패키징을 한다. 그러나 서버를 배포하기 위해서는 이런 jar형태의 파일 뿐만 아니라 애플리케이션 들이 참고하는 각종 설정 파일들을 함께 배포해야 할 필요가 있다. 운이 좋게 모든 파일들이 jar,ear,war등에 함께 패키징 되면 좋겠지만, 애플리케이션이 어느정도 규모가 되면 함께 패키징이 되지 않는 파일들이 발생한다.

이런 문제를 해결하기 좋은 방법으로는 linux에서 제공하는 rpm 패키징을 이용하는 방법이 있다.

maven에서는 이 rpm 패키징을 플러그인으로 제공한다.

(http://mojo.codehaus.org/rpm-maven-plugin/ )

사용법도 상당히 간단하기 때문에 추천한다. 플러그인은 linux 명령어인 rpmbuild 내부적으로 수행하기 때문에, 반드시 windows 아닌 linux machine에서만 사용이 가능하다.

 

rpm package 여러가지 기능을 수행할 있지만, 여기서 설명하는 것은 기본적으로 file copy 이다.

 

              <!--  rpm plug in -->

              <plugin>

                <groupId>org.codehaus.mojo</groupId>

                <artifactId>rpm-maven-plugin</artifactId>

                <version>2.0-beta-2</version>

                <configuration>

                        <copyright>2013 - Terry Cho</copyright>

                        <group>terry/example</group>

                        <mappings>

                        <mapping>

                               <directoryIncluded>false</directoryIncluded>

                                 <directory>${rpm.install.webapps}</directory>

                                <username>bwcho</username>

                                <groupname>bwcho</groupname>                            

                                 <sources>

                                         <source>

                                                 <location>${basedir}/target/${artifactId}.war</location>

                                         </source>

                                 </sources>

                        </mapping>

                        </mappings>

                    </configuration>

              </plugin>

 

설정을 제공하는 <configuration> 부분을 보자

rpm 패키지에 대한 관리를 위해서 rpm 그룹핑을 제공하는데, <group> rpm 패키지의 그룹을 정의한다. group 여러개의 컴포넌트를 함께 배포할때 매우 유용하게 사용될 있다. 예를 들어 비디오 인코딩 애플리케이션이 있고, 애플리케이션이 upload, download,encoding 컴포넌트 3개로 구성되어 있고, 각각 배포 되어야 한다면 그룹명을 videoencoding/upload, videoencoding/download, videoencoding/encoding 등으로 지정하여 구별할 있다.

다음으로 <mappings> 엘리먼트에서는 복사할 파일 리스트를 지정할 있다. 하위 엘리먼트로 <mapping>이라는 엘리먼트에서 개개별의 디렉토리나 파일을 지정하면 된다.

<sources><source> 엘리먼트에서 복사할 원본 파일 리스트를 지정하고,

<directory> 엘리먼트에서 복사될 타겟 디렉토리를 지정한다.

그리고 <username> <groupname> 파일이 복사될때 (생성되는 파일의) user id group (unix) 정의한다.

위의 예제는 war 파일을 ${rpm.install.webapps} 복사하는 rpm 파일을 생성하는 스크립트이다.

이렇게 생성된 스크립트는

 

% mvn package rpm:rpm  으로 수행될 있다.

앞서 설명한, profile 함께 사용하면, dev rpm 패키지 생성은

% man -Pdev package rpm:rpm

으로 하면된다.

 

이렇게 생성된 rpm 파일들은 대상 시스템으로 복사되서 rpm 수행하는 것만으로도, 모든 의존성을 가진 파일들을 함께 설치할 있다.

아울러 rpm 가지고 있는 고유한 기능으로, 특정 버전으로의 roll back등이 가능하다.

rpm 파일들을 대상 시스템으로 자동으로 복사 실행 하는 부분에 대해서는 뒤에서 다시 살펴 보도록 하자