블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

Apt.ly를 이용한 데비안 리포지토리 생성


조대협 (http://bcho.tistory.com)




앞의 글에서 Jenkins + Maven 조합을 통해서 애플리케이션 설치 파일을 데비안 패키지로 패키징하는 방법에 대해서 알아보았다. 이제 이 패키지를 서버에 설치하는 방법을 살펴본다.

패키지를 설치하는 방법은 간단하게 데비안 패키지 파일을 설치하고자 하는 서버에 복사해놓은 다음에, sudo apt-get install을 이용해서 설치하는 방법도 있지만, 설치하고자 하는 서버마다 복사하기가 번거롭기 때문에 조금 더 쉬운 접근을 위해서 데비안 패키지 서버를 올리는 방법이 있다. 우리가 JDK나  node.js 등 다양한 유닉스 패키지를 apt-get 을 이용하여 설치가 가능한것은 미리 데비안 패키지 리파지토리 서버가 지정되어 있고, 그 서버내에 패키지들이 등록되어 있기 때문인데, 애플리케이션 패키지를 같은 방법으로 설치할 수 있게 하려면 애플리케이션 데비안 패키지 파일을 등록할 리포지토리 서버를 설정하면 된다.


지금까지 구현해온 파이프라인은 아래 그림과 같다

  1.  gitHub 로 부터 Jenkins가 자바 코드를 자바 코드를 당겨온다

  2. 이 코드를 Maven을 이용하여 빌드한다

  3. Maven은 코드 빌드가 끝나고 이를 데비안 패키지로 패키징 한다.

  4. Jenkins는 데비안 패키징 파일을 로컬 리포지토리인 apt.ly에 저장한다.

  5. Spinnaker에서 설치할때 데비안 패키지를 apt.ly에서 당겨서 설치한다.


앞의 글에서 까지 1,2,3과정까지 진행을 하였고, 이 글에서는 4번 과정을 구현할 예정이다.

다양한 오픈소스가 있지만, 플랫폼 종속성이 없고 손쉽게 설치가 가능한 apt.ly (www.aptly.info) 를 기준으로 설명을 하고자 한다.


apt.ly 설치

여기서 설명하는 설치는 데비안 리눅스 9을 기준으로 하여 설명한다.

설치는 앞의 글에서 설치한 Jenkins 서버에 그대로 설치하도록 한다.

설치 방법은 간단하다. www.aptly.info 사이트에서 설치 메뉴얼을 체크하여, 현재 사용하는 리눅스 버전에 맞는 바이너리를 wget을 이용해서 다운 로드 받은 후에, chmod +x 로 실행 권한만 주면 된다.


$ wget https://dl.bintray.com/smira/aptly/0.9.5/debian-squeeze-x64/aptly

$ chmod +x aptly


명령어가 설치 되었으면 리파지토리를 생성해야 한다.

리포지토리 생성 과 확인

리포지 토리 생성은 aptly repo crete {리포지토리 명} 을 입력하면 된다.  아래 명령은 “terry-repo”라는 이름의 리포지토리를 생성한것이다.

%./aptly repo create terry-repo


아래 명령은 terry-repo 라는 리포지토리에 대한 정보를 조회 하는 명령이다.

%./aptly repo show -with-packages terry-repo


아래는 실제 실행결과 인데, 테스트를 위해서 helloterry_1.0_all 이라는 패키지를 등록해놨기 때문에 하나의 패키지가 등록되서 보이는 것을 확인할 수 있다.



apt.ly 에 패키지 등록하기

리포지토리가 생성되었으면, maven 에서 빌드한 패키지를 apt.ly 리포지토리에 등록해보자

등록하는 방법은 aptly repo add -force-replace {리포지토리명} {데비안 패키지 파일명} 식으로 사용하면 된다.

아래는 terry-repo에 helloworld.deb 파일을 등록하는 명령이다.

%./aptly repo add -force-replace terry-repo helloworld.deb

apt.ly 리포지토리 퍼블리슁하기

패키지를 등록했으면 외부에서 억세스사 가능하도록 리포지토리 퍼블리쉬를 해야 하는데, 퍼블리쉬는 어떤 버전의 OS와 CPU 타입에 설치할 수 있는지등의 메타 정보를 함께 등록한다.

명령어 사용법은 aptly publish repo -distribution=”{OS 버전 정보}" -architecture=”{CPU 타입}” -skip-signing=true {리포지토리명}

식으로 사용한다.

원래 데비안 패키지를 외부로 배포를 할때는 패키지의 변경(원하지 않은)을 막기 위해서 패키지에 사이닝을 하는데, 여기서는 -skip-signing 을 이용하여 사이닝 단계를 건너뛰도록 하였다. 이 리파지토리는 외부에서 억세스하는 용도가 아니라 내부에서 CI/CD 파이프라인 단계에서만 사용되기 때문에 사이닝을 생략하였다.


아래 명령은 데비안 stretch 버전에 amd64 (intel CPU)에 terry-repo 이름으 리포지토리를 퍼블리슁한것이다.

%./aptly publish repo -distribution=stretch -architectures="amd64" -skip-signing=true terry-repo


apt.ly 서버 기동

퍼블리슁이 되었다고 당장 리포지토리를 접근 가능한것이 아니다. apt-get을 이용한 인스톨은 HTTP 프로토콜을 이용해서 접근하기 때문에 apt.ly 파일 저장소를 접근 가능하게 하는 웹서버를 올려야 한다.

간단한 방법으로는 aptly serve 명령어를 이용해서 웹서버를 올리는 방법이 있다.

아래 명령어 처럼 aptly serve -listen={IP:포트}를 적으면 된다.


% ./aptly serve -listen=:9090 > aptly.log &


이 보다는 제대로 서비스를 하기위해서는 웹서버에 올리는게 좋은데,

(참고 : https://www.spinnaker.io/guides/tutorials/codelabs/hello-deployment/)

% sudo apt-get install nginx

를 통해서 nginx 를 설치한 후에, /etc/nginx/sites-enabled/default 파일을 다음과 같이 편집한다.


server {
       listen 9999 default_server;
       listen [::]:9999 default_server ipv6only=on;
       root /var/lib/jenkins/.aptly/public;
       index index.html index.htm;
       server_name localhost;
       location / {
               try_files $uri $uri/ =404;
       }
}


이때 root에 aptly의 public 디렉토리를 명시해줘야 하는데, aptly를 설치한 디렉토리의 .aptly/public 이 되는게 일반적이다. 여기서는 /var/lib/jenkins 디렉토리 아래에 리포지토리를 만들었기 때문에 /var/lib/jenkins/.aptly/public 디렉토리를 홈 디렉토리로 설정하였다.


nginx 를 기동하면 http 9999번 포트로 데비안 패키지 서비스를 시작한다.

apt.ly 를 통한 패키지 설치

데비안 패키지 서버를 설치하고 패키지를 등록했으면 실제로 패키지를 다른 서버에서 인스톨 해보자

다른 서버에서 이 패키지 서버에 대한 정보를 알고 있어야 하는데 (서버 주소) 이 정보는 /etc/apt/sources.list 라는 파일에 아래와 같은 형태로 등록 되어 있다.


deb http://deb.debian.org/debian/ stretch main

deb-src http://deb.debian.org/debian/ stretch main

deb http://security.debian.org/ stretch/updates main

deb-src http://security.debian.org/ stretch/updates main

deb http://deb.debian.org/debian/ stretch-updates main

deb-src http://deb.debian.org/debian/ stretch-updates main


이 파일에 앞서 설정한 데비안 리포지토리 서버 (apt.ly) 서버의 주소와 정보를 입력해주면 된다.

만약 http://myserver-ip:9999 포트로 서버를 올렸다면 아래와 같은 정보를 /etc/apt/sources.list 에 추가해주면 된다.


deb http://myserver-ip:9999 stretch main


설정이 끝났으면

%sudo apt-get update

명령을 실행하면 아래와 같이 새로운 리포지토리에서 정보를 읽어오는 것을 확인할 수 있다.


모든 준비가 끝났다.

인스톤을 해보자. 인스톨은 sudo apt-get install을 이용하면 된다.

앞서 등록한 패키지 명이 helloterry 였기 때문에 간단하게 아래와 같이 sudo apt-get install helloterry 명령어를 실행하면 된다.



이외에도 유사한 툴로 pulp (https://docs.pulpproject.org/user-guide/introduction.html#what-pulp-can-do)

클라우드 서비스로는 cloudsmith.io (https://cloudsmith.io/)등이 있다. 

작은 규모의 팀이라면 관리 문제도 있으니 클라우드 서비스를 쓰는 것도 좋은 방안이 되지 않을까 한다.



Maven으로 데비안 패키지를 만들어보자


(http://bcho.tistory.com)

조대협

애플리케이션 배포

CI/CD 빌드 배포 프로세스에서, 컴파일된 애플리케이션을 배포하는 방법은 여러가지가 있다. 빌드된 바이너리를 Ansible과 같은 Configuration management 도구를 이용해서 배포하는 방법이 일반적이지만, 작업이 복잡한 경우에는 많은 스크립트 작업이 필요한 경우가 있다.

보통 애플리케이션 배포는 단순하게 바이너리만을 복사하는 것이 아니라, 이에 필요한 의존성이 있는 패키지 (예를 들어 JDK나 기타 의존되는 라이브러리)를 배포해야 하는 경우도 있고, 경우에 따라서는 의존되는 파일이나 복잡한 디렉토리 구조를 생성해야 하는 경우가 있다. 이를 Ansible과 같은 Configuration management 툴을 사용하게 되면 스크립트가 복잡해질 수 있는데, Debian 패키지 (apt-get install 로 설치하는)로 패키징을 하면, 의존성이 있는 패키지나, 복잡한 디렉토리 구조 설정, 그리고 여러 파일 설치를 한번에 끝낼 수 있다.

데비안 패키지 파일 생성

디렉토리 구조

데비안 패키지 생성은 어렵지 않다. 먼저 데비안 패키지 파일에 패키징할 파일을 저장한 “작업 디렉토리"를 하나 만든다. 그리고 그 아래 “홈 디렉토리”에 설치될 경로와 파일을 저장한다.

예를 들어 “홈 디렉토리”가 “/home/terrycho”면 이 패키지를 설치하는 시스템에 /home/terrycho라는 디렉토리가 생성이되고 “작업 디렉토리"아래에 /home/terrycho/my.jar 라는 파일이 있으면 대상 시스템에도 같은 경로에 파일이 설치된다.

파일 구조

패키지에 대한 정보를 설정하기 위해서는 “작업 디렉토리” 아래에 “/DEBIAN” 디렉토리 안에 각종 설정 파일을 넣어둘 수 있는데, control 이라는 파일은 필수로 필요한 파일이다. 이 파일에는 데비안 패키지의 필수 정보인 패키지명, 정보들이 들어간다.  아래는 샘플 내용이다.


Package: ${build.finalName}

Version: ${project.version}

Section: misc

Priority: low

Architecture: all

Depends: oracle-java8-installer | openjdk-8-jre

Description: spinnaker spring test

Maintainer: {my email}


각 항목을 살펴보자

  • Package : 가장 중요한 항목으로 패키지 명을 정의한다. apt-get install 시, 이 패키지명으로 지정해서 인스톨을 한다.

  • Version : 패키지 버전이다. 설치된 패키지를 업그레이드할때 이 버전을 비교하기 때문에 매우 중요한 필드 이다. 버전이 같으면 내용이 다르더라도 업데이트가 되지 않으니 주의가 필요하다.

  • Section : 패키지의 분류인데, 크게 중요하지는 않다.

  • Architecture : 설치 가능한 CPU 플랫폼 종류를 정의한다.

  • Depends : 이 패키지를 실행하기 위해서 필요한 다른 패키지명을 리스팅 한다. 예를 들어 자바 애플리케이션의 경우 JDK를 설치하도록 할 수 있다. 위의 예제는 oracle-java8이나, openjdk-8 런타임을 설치하도록 정의되어 있다.

  • Description : 패키지에 대한 설명을 적는다.

  • Maintainer : 패키지를 관리하는 개발자 이메일을 적는다.


control 파일 이외에도 추가 설정 파일을 통해서 인스톨전 후의 추가 작업을 preinstall이나, postinstall 스크립트를 지정할 수 있다.

패키지를 만들어보자

대략적인 개념을 이해 했으면 실제로 패키지를 만들어보자

아래와 같이 hellodebian 디렉토리에 hello.txt와 control 파일을 생성하였다.


/home/terrycho/hellodebian/home/hello.txt

/home/terrycho/hellodebian/DEBIAN/control


hello.txt 는 간단한 텍스트 내용이 들어있는 파일이고, control 파일의 내용은 다음과 같다.


Package: hellodebian

Version: 1.0

Section: misc

Priority: low

Architecture: all

Depends: oracle-java8-installer | openjdk-8-jre

Description: spinnaker spring test

Maintainer: {my email}


이 디렉토리를 패키지로 묶으려면 “dpkg-deb --build {작업 디렉토리명}” 명령어를 실행하면 된다.



위와 같이 명령을 실행하면 hellodebian.deb 파일이 생성된다.

설치 확인은

% sudo apt-get install ./hellodebian.deb

명령을 실행하면 설치가되는 것을 확인할 수 있고, 의존성에 정의한 Jre가 같이 설치되는것을 확인할 수 있다.




Maven을 이용한 데비안 패키지 파일 생성

그러면 실제 애플리케이션 빌딩 과정에서 이렇게 디렉토리를 구조를 정의하고 dpkg 명령어를 사용해서 패키징을 해야 하는가? 다행이도 언어마다 빌드 스크립트에 데비안 패키지로 패키징을 해줄 수 있는 플러그인이 있다.

여기서는 자바 빌드를 위한 maven에서 데비안 패키지를 묶어주는 jdeb 플러그인에 대해서 알아보자. (https://github.com/tcurdt/jdeb)

아래는 jdeb을 사용하는 pom.xml이다.


   <build>

       <plugins>

           <plugin>

               <groupId>org.springframework.boot</groupId>

               <artifactId>spring-boot-maven-plugin</artifactId>

           </plugin>

           <plugin>

               <artifactId>jdeb</artifactId>

               <groupId>org.vafer</groupId>

               <version>1.5</version>

               <executions>

                   <execution>

                       <phase>package</phase>

                       <goals>

                           <goal>jdeb</goal>

                       </goals>

                       <configuration>

                           <verbose>true</verbose>

                           <snapshotExpand>true</snapshotExpand>

                           <!-- expand "SNAPSHOT" to what is in the "USER" env variable -->

                           <snapshotEnv>USER</snapshotEnv>

                           <verbose>true</verbose>

                           <controlDir>${basedir}/src/deb/control</controlDir>

                           <dataSet>

                    <data>

                       <src>${project.build.directory}/${build.finalName}.jar</src>

                       <type>file</type>

                       <mapper>

                           <type>perm</type>

                           <prefix>/var/${build.finalName}</prefix>

                           <filemode>755</filemode>

                       </mapper>

                   </data>


                           </dataSet>

                       </configuration>

                   </execution>

               </executions>

           </plugin>

       </plugins>

   </build>



<goal>에 jdeb을 설정하고, <configuration>에 상세 설정 정보를 넣는다.

데비안 패키지는 앞에서 설명 했듯이, control 파일이 필요한데, <controlDir>에 control 파일이 저장되어 있는 디렉토리 위치를 지정한다.

다음으로, <dataSet>에 데비안 패키지에 대한 설정 정보를 지정하는데, 디렉토리 정보등을 정의할 수 있다. <type>file</type>은 파일에 대한 정보를 넣는데, <src>에는 소스 파일을 정의하고 <prefix>에 파일이 저장될 위치를 지정한다. <filemode> 에 Unix file permission을 지정한다.

위의 스크립트는 ${prject.build.directory}/${build.finalName}.jar 파일을 /var/${build.finalName}으로 복사한다.


생성된 jar 파일명은 ${build.finalName}으로 생성되는데, 이 이름은

${artifactId}_{$version}_all 이라는 이름으로 된다.

이 예제에서는 artifactId가 hello-springboot 이고, version은 1.0이기 때문에 최종 생성된 이름은

hello-springboot_1.0_all 로 된다.


Jenkins와 gitHub 연동


조대협 (http://bcho.tistory.com)


가장 널리 사용하는 Jenkins와, 소스 코드 리포지토리 서비스인 GitHub를 연동하는 방법에 대해서 알아본다. 시나리오는 gitHub에 코드를 푸쉬하면 Jenkins가 이를 인지해서 자동으로 코드를 내려 받아서 빌드 스크립트를 실행하는 순서로 한다.


GitHub에서 Credential 생성


gitHub 자신의 계정으로 로그인 한 후 우측 상단의 자신의 사진이 있는 아이콘을 누르면 메뉴가 나오는데, 여기서 Setting > Developer settings 메뉴로 들어간 후에 아래와 같이 Personal access tokens 메뉴로 들어간다.

다음 우측 상단의 Generate new token 메뉴를 선택한다.



다음 토큰으로, 접근할 수 있는 범위를 설정한다. 접근 범위는 “repo”와 “admin:repo_hook” 을 선택한다.




선택이 끝나고 토큰을 생성하면 문자열로 된 토큰이 생성된다.


Jenkins에서 GitHub 연결 설정

앞에서 생성된 토큰을 Jenkin의 GitHub 연결 부분에 설정하도록 하겠다.

Jenkins 초기화면에서 Jenkins > Manage Jenkins > Configure System 메뉴로 들어가면 GitHub 계정을 설정하는 부분이 있다.



Name은 이 GitHub 연결 설정을 구별할 이름으로 정의하고 API URL은 default로 https://api.github.com 으로 설정되어 있는데 default 값을 사용한다.

다음 접속 credential을 설정해야 하는데, credentials 부분에서 Add 버튼을 눌러서 Credential 설정 메뉴를 실행한다.




위와 같은 메뉴가 나오면 Kind는 “Secret text”를 선택하고 Secret 에 앞에 gitHub에서 생성한 키를 입력한다. ID에는 본인 gitHub ID를 입력한다.  Credential 입력이 끝나면,  아래 그림과 같이 Credentials 메뉴 아래에 Test Connection 버튼이 있는데, 이 버튼을 눌러서 제대로 github와 연결이 되는지를 테스트 한다.




Jenkins 프로젝트 생성 및 설정

Jenkins와 gitHub 연결 설정이 끝났으면, Jenkins에서 프로젝트를 생성한다.

Git 연결 설정

프로젝트 설정에서 아래와 같이 Git 메뉴로 이동한다.



여기서 Repository URL을 입력한다. Repository URL은 본인 gitHub Repository에서 우측 상단의 녹색 “Clone or download” 버튼을 누르면 HTTPS 로 된 URL이 나온다. 이 URL을 입력하면 된다.



다음 이 repository에 연결할 연결 정보를 입력해야 하는데, Jenkins에서 credentials 메뉴로 들어간다.

이 메뉴에서 Kind를 “Username with password” 를 선택하고 Username에는 본인의 github id, Password에는 github 비밀번호를 입력한다.



빌드 트리거 설정

다음 어떤 조건에서 Jenkins 빌드를 실행할지를 설정하는데, GitHub에 코드가 푸쉬되면 빌드를 트리거링 하도록 설정을 할것이다. 아래 그림과 같이 Build Triggers 메뉴에서 GitHub hook trigger for GitScm Polling을 선택한다.




이렇게 설정하면 GitHub에서 코드 푸쉬가 될때 webHook 메세지를 Jenkins에 보내주는데, 이 WebHook 메세지를 받을 때마다 빌드를 하게 된다.


GitHub에서 WebHook 설정

Jenkins 가 GitHub 에서 보내는 WebHook에 의해서 Triggering이 되도록 설정했으면, 이제 GitHub에서 코드가 푸쉬 될때 마다 WebHook을 Jenkins에 보내도록 설정해야 한다.




GitHub Repository로 들어가면 우측 상단에 Settings라는 메뉴가 있다.

이 메뉴에 들어가서 좌즉에 Integration & Service 라는 메뉴를 선택한다.


Services 메뉴에서 “Add service” 버튼을 클릭한 후에 “Jenkins (GitHub plugin)” 을 선택한다.



다음 플러그인 설정에 Jenkins hook url에 Jenkins가 WebHook을 받을 HTTP 경로를 입력한다.

일반적으로 http://{Jenkins server의 URL}/github-webhook 이 된다.




이제 모든 설정이 끝났다.

제대로 작동하는 것을 확인하기 위해서 코드를 commit 한 후에 Push를 해보면 빌드가 자동으로 진행이 된다.

Jenkins의 해당 project에서 좌측의 “GitHub Hook Log”를 보면 WebHook을 잘 받았는지 확인이 가능하다. 아래는 실제로 WebHook이 발생한 내용을 확인한 화면이다.




Spinnaker #3

Hello Spinnaker

조대협 (http://bcho.tistory.com)


Spinnaker에 대한 개념 이해 및 설치가 끝났으면, 이제 간단한 애플리케이션을 배포해보자.

여기서 사용하는 애플리케이션은 node.js로 8080 포트에 “This is Default” 라는 메세지를 출력하는 간단한 애플리케이션이다. VM이 기동되면 자동으로 이 node.js 서버가 기동되도록 설정을 해놓은 VM이미지를 만들어놓았다. 만약에 같은 테스트를 하고자 한다면 간단한 애프리케이션을 만들어도 좋고, nginx나 apache 웹서버를 설치해놓은 이미지를 사용해도 좋다.

Create Application

먼저 node.js 클러스터를 배포할 애플리케이션을 정의한다. 아래 처럼 메뉴에서 애플리케이션을 선택한 후에, 우측 상단의 Action 메뉴에서 Create Appliaction 메뉴를 선택한다.



다음 애플리케이션 정보에 애플리케이션명을 “hellospinnaker”로 입력하고, 관리자 이메일을 입력한다.





Load Balancer 생성

애플리케이션이 생성되었으면, 애플리케이션에서 사용할 로드밸런서를 사용한다. 구글 클라우드에는 여러 타입의 로드 밸런서가 있지만, 설정이 쉬운 Network 로드 밸런서를 사용하겠다.

Network Load Balancer는 TCP/UDP를 지원하는 Pass through (IP가 바뀌지 않는다.) 방식의 L4 로드 밸런서로, 구글의 망가속 기능을 사용하지 않는 리전 단위의 로드 밸런서이다.



로드 밸런서 타입을 선택했으면 상세 정보를 입력한다.

  • region을 선택한다. 여기서는 일본 리전인 asia-northeast1을 선택하였다.

  • 다음 로드밸런서의 포트를 선택해야 하는데, Listener 부분에서 TCP 프로토콜을 선택하고, 입력 포트를 8080으로 선택한다.

  • 그리고 마지막으로 중요한것은 Health Check 부분을 명시해야 하는데, Health check는 HTTP를 사용하게 된다. HTTP/GET request를 이용하여 Health check를 할 서버의 HTTP URL과 Port를 지정해야 한다. node.js 서버가 8080 포트를 통해 서비스 하기 때문에 Health Check도 8080 포트에 “/” 디렉토리로 지정한다.





Server 생성

로드 밸런서 설정이 끝났으면 여기에 붙일 서버 그룹을 정의해야 한다. 서버그룹 정의는 Clusters 메뉴에서 가능한데, 먼저 Clusters 메뉴로 들어간후, 우측 상단의 Create Server Group 버튼을 클릭하여, 서버 그룹 생성 화면을 불러온다.





서버 그룹에 정보에서는 아래 그림과 같이 region을 선택하고, VM을 생성할때 사용할 Image를 선택한다. 이 예제에서는 앞서 설명한것 처럼 node.js 애플리케이션을 “simple-node-server-default-image”라는 이미지로 준비해놓았다.

다음 Load Balancers 메뉴에서 로드 밸런서를 선택한다. 로드 밸런서는 앞 단계에서 만든 “hellospinnaker” 를 선택한다.





다음으로는 인스턴스 타입을 선택한다. 인스턴스 타입은 먼저 Zone 을 선택해야 선택할 수 있다. Zone은 두개의 존 이상에 걸치도록 설정하기 위해서 “Distribute instance multiple zones” 체크 박스를 클릭하면 선택한 리전에서 두개 이상의 존에 걸쳐서 인스턴스가 생성된다.

그리고 인스턴스 타입을 선택한다. 아래에서는 n1-standard-2 인스턴스를 선택하였다.

마지막으로 Number of instances에 기동시킬 인스턴스 수를 지정한다. 여기서는 4개의 인스턴스를 기동하도록 하였다.




서버 기동 확인

모든 설정이 끝났으면, 인스턴스가 기동되는 것을 확인할 수 있다. 아래 그림과 같이 인스턴스가 정상적으로 올라오면 초록색으로 표시가 된다. 만약 문제가 있어서 인스턴스가 올라오지 않으면 붉은 색으로 표시된다. (대부분 실패 하는 경우는 HeartBeat 설정이 제대로 되어 있지 않는 경우가 많다.)




실제로 구글 클라우드 콘솔의  Compute Engine탭을 확인해 보면 아래와 같이 VM들이 생성 된것을 확인할 수 있다. VM이름은 hellospinnaker-vxxx 라는 이름으로 생성이 되는것을 확인할 수 있다.



테스트

그러면 제대로 작동을 하는지 확인해보자. 로드밸런서의 IP를 확인해야 하는데,  생성된 로드밸런서를 클릭하면 로드밸런서의 IP가 아래 그림과 같이 우측에 나타난다.



이 IP로, HTTP 8080 포트로 접속을 해보면 아래 그림과 같이 접속이 되는 것을 확인할 수 있다.



지금까지 Spinnaker에 대한 제일 간단한 사용방법을 알아보았다.

실제 운영 환경에서는 이런식으로 사용하는 경우는 드물고, github등의 코드 Repository에서 코드가 변경되면 이를 Jenkins 등을 이용하여 빌드하고, 패키징 한 후에, VM등에 배포하는 파이프라인을 거치게 된다.

다음 글에서는 이러한 파이프라인을 하나 만들어 보도록 하겠다.




CI/CD 레퍼런스 아키텍쳐


조대협 (http://bcho.tistory.com)


Continuous Deployment를  구현하기 위해서는 여러가지 프레임웍을 조합할 수 있다. 배포를 위한 Chef,Puppet과 같은 Configuration management tools, 그리고 네트워크, VM등을 코드로 설정하기 위한 Terraform 과 같은 Infrastructure as a code, VM 이미지를 만들기 위한 Packer 등 다양한 솔루션 조합이 가능한데, 이 글에서는 이러한 솔루션을 조합하여 어떻게 Continuous Deployment 파이프라인을 구현할 수 있는지에 대해서 설명하고, 구체적인 솔루션 제안을 통하여 레퍼런스 아키텍쳐를 제안하고자 한다.

1. Terraform + Ansible 기반의 Continuous Delivery

가장 기본적인 조합으로는 Terraform 을 이용해서 코드로 정의된 설정을 이용하여 인프라를 설정한 후에,

VM에, Ansible을 이용하여 애플리케이션 서버등의 소프트웨어를 설치한 후,  애플리케이션 코드를 배포하는 방식이다.

아래 그림은 Terraform으로 먼저 VM 인스턴스 그룹을 만든 후에, Load Balancer에 연결하고, CloudSQL (DB)인스턴스를 배포하는 구조이다.




이후에, 각 VM에 대한 설치는 Ansible을 이용하는 구조이다 Ansible은 Jenkins와 같은 CD 툴에 의해서 코드 변경등이 있으면 호출되서 자동화 될 수 있다.


이러한 구조는 전통적인 Continuous Delivery 기반의 애플리케이션 배포 자동화 구조이다.


2. Packer를 추가한 Foundation Image 사용방식

앞의 구조에서 VM은 애플리케이션 서버를 코드 배포 단계에서 배포할 수 도 있지만 애플리케이션 코드 이외에는 변경이 없기 때문에, Terraform으로 인프라를 배포할때, Packer와 Ansible을 이용하여, 애플리케이션이 설치되어 있는 이미지를 만들어놓고, 이를 이용해서 배포할 수 있다. (이미지를 만드는 과정을 베이킹 = 굽는다. 라고 한다.)

아래 그림을 보면, Terraform에서, Packer를 호출하고, Packer가 VM 이미지를 만드는데, 이 과정에서 Ansible을 이용하여, 애플리케이션 서버를 설치하도록 설정하는 구조를 가지고 있다.



위의 구조에서는 node.js server 애플리케이션 서버를 사용했지만, 실제 인프라를 구축할때는 redis나 웹서버등 다양한 애플리케이션의 설치가 필요하기 때문에, 이 구조를 사용하면 전체 인프라 구축을 코드로 정의하여 자동화를 할 수 있다.

3. Spinnaker를 이용한 Continuous Deployment 구조

코드만 배포하고 업데이트 할 경우, 서버의 패치 적용등의 자동화가 어렵기 때문에, 매번 배포시 마다, VM 설정에서 부터 OS 설치와 패치 그리고 애플리케이션 설치와 코드 배포까지 일원화하여 VM 단위로 배포할 수 있는데, 이를 Continuous Deployment 라고 한다.


솔루션 구성은 2번의 구조와 유사하나, Terraform으로는 VM과 로드밸런서를 제외한 다른 인프라를 설정하고 Spinnaker를 이용하여, 로드밸런서와 VM을 이용한 배포를 실행한다.


Spinnaker로 배포할 수 있는 범위는 방화벽, 로드밸런서, VM 과 같이 워크로드를 받는 부분인데, Spinnaker는 Packer와 Ansible과 협업하여, VM에 모든 스택을 설치하고, 이를 VM 단위로 배포할 수 있도록 해준다. 복잡한 네트워크 설정이나, CloudSQL과 같은 클라우드 전용 서비스는 Spinnaker로 설정이 불가능하기 때문에, 먼저 Terraform으로 기본 인프라를 설정하고, VM관련된 부분만을 Spinnaker를 사용한다.

이렇게 VM전체를 배포하는 전략을 피닉스 서버 아키텍쳐라고 한다. 피닉스 서버 패턴은 http://bcho.tistory.com/1224?category=502863 글을 참고하기 바란다.


Spinnaker를 이용한 배포 전략

Spinnker를 이용하면, VM 기반의 배포뿐 아니라, 다양한 배포 전략을 수행할 있다.



그림 https://sdtimes.com/cloud/google-open-source-platform-spinnaker-1-0/


Blue/Green deployment

블루 그린 배포 전략은 새버전의 서버그룹을 모두 배포 완료한 후에, 로드밸런서에서 트래픽을 구버전에서 새버전으로 일시에 바꾸는 방식이다.

Rolling deployment

롤링 배포는, 새버전의 서버를 만들어가면서 트래픽을 구버전 서버에서 새버전으로 점차적으로 옮겨가는 방식이다. 예를 들어 구서버가 10대가 있을때, 새 서버 1대가 배포되면, 구서버 9대와 새서버 1대로 부하를 옮기고, 새서버 2대가 배포되면 구서버:새서버에 8:2 비율로 부하를 주면서 7:3,6:4,5:5,.... 이런식으로 부하를 옮겨가며 전체 부하를 새 서버로 옮기는 방식이다.


블루 그린 배포 전략은 서버 대수의 2배수의 서버가 필요한 반면, 롤링 배포 방식은 같은 서버의 수 (위의 예의 경우 10대만 있으면 됨)를 가지고 배포를 할 수 있기 때문에 서버 자원이 한정되어 있는 경우에 유리하게 사용할 수 있다.

Canary deployment

카날리 배포를 설명하기 전에 카날리 테스트에 대한 용어를 이해할 필요가 있다.

카날리 테스트는 옛날에 광부들이 광산에서 유독가스가 나오는 것을 알아내기 위해서 가스에 민감한 카나리아를 광산안에서 키웠다고 한다. 카나리아가 죽으면 유독가스가 나온것으로 판단하고 조치를 취했다고 하는데, 이 개념을 개발에서 사용하는것이 카날리 테스트 방식이다.

예를 들어 사용자가 1000명이 접속해 있을때, 일부 사용자에게만 새 버전을 사용하도록 하고, 문제가 없으면 전체 사용자가 새 버전을 사용하도록 하는 방식인데, 안드로이드 앱 배포의 경우에도 10%의 사용자에게만 새 버전을 배포해보고 문제가 없으면 100%에 배포하는 것과 같은 시나리오로 사용된다.


이 개념을 배포에 적용한것이 카날리 배포 방식인데, 일부 서버에만 새 버전을 배포하여 운영한 후에, 문제가 없는 것이 확인되면 전체 서버에 새 버전을 배포하는 방식이다.

Docker를 이용한 배포 효율화

이러한 VM 기반의 Continuous deployment 구조는 피닉스 서버 패턴을 기반으로 하여, 모든 업데이트 추적이 가능하다는 장점을 가지고 있지만, 매번 VM을 베이킹해야 하기 때문에 시간이 많이 걸리고, VM 이미지는 사이즈가 커서 스토리지를 많이 사용한다는 단점이 있다.

이러한 배포 구조와 잘 맞는 것이 Docker (Docker 개념 http://bcho.tistory.com/805 ) 인데, Docker는 컨테이너 기반으로 경량화가 되어 있기 때문에, 이미지 베이킹 시간이 상대적으로 짧고, 이미지 사이즈가 작아서 저장이 용이하며, 이미지를 저장하기 위한 리파지토리와 같은 개념이 잘되어 있다.


Spinnaker의 경우 이런 Docker 기반의 피닉스 서버 패턴 기반의 배포를 지원하는데, 특히 Kubernetes 클러스터를 매우 잘 지원하기 때문에, 오히려 VM 기반의 배포 보다는 Docker + Kubernetes 배포 구조를 선택하는 것이 좋다.


이 경우 인프라 배포에 있어서는 애플리케이션을 서비스하는 VM워크로드는 도커를 사용하되, Redis, RDBMS와 같은 미들웨어 솔루션은 재 배포가 거의 발생하지 않기 때문에, VM에 배포하여 사용하는 것이 성능적으로 더 유리하기 때문에, 도커와 VM 을 하이브리드 구조로 배포하는 방식을 권장한다.


클라우드 전용 배포 솔루션  VS 오픈소스 (Terraform)

앞에서 설명한 아키텍쳐에서 사용한 솔루션은 모두 오픈 소스 기반이다. 클라우드 벤더의 경우에는 구글은 Deployment Manager와, 아마존은 CloudFormation을 이용하여, 코드 기반의 배포 (Terraform과 동일)를 지원하는데, 그렇다면, 클라우드에서 제공하는 전용 솔루션을 쓰는 것이 좋은가? 아니면 오픈소스나 벤더에 종속적이지 않은 솔루션을 사용하는 것이 좋은가

오픈소스의 배포툴의 경우에는 요즘 트랜드가 다른 영역으로 확장을 해가는 추세가 있기 때문에, 코드 기반의 인프라 배포 이외에도 애플리케이션 코드 배포등 점점 더 넓은 영역을 커버할 수 있는 장점이 있고, 오픈 소스 생태계내에서 다른 제품들와 연동이 쉬운점이 있다. 그리고 특정 클라우드 벤더나 인프라에 종속성이 없기 때문에 조금 더 유연하게 사용이 가능하지만, 클라우드 벤더에서 제공되는 새로운 서비스나 기능 변화를 지원하는 것에는 상대적으로 클라우드 벤더에서 제공하는 도구보다 느리다. 예를 들어 구글 클라우드에서 새로운 서비스가 나왔을때, 테라폼에서 이 기능을 지원하는데 까지는 시간이 걸린다는 것이다.


양쪽다 좋은 선택지가 될 수 있기 때문에, 현재 환경에 맞는 솔루션을 선택하는 것을 권장한다.



Hudson을 이용한 빌드와 테스트의 자동화


 

2007-04-04
BEA Systems Korea
Sr consultant Byungwook Cho (bcho@bea.com)

Continuous Integration(점진적 통합,이하 CI)이란, 개발자가 각각 개발한 소스코드를 모아서 한꺼번에 빌드하는 통합 빌드의 과정을 특정 시점이 아니라 매일이나 매주와 같이 아주 잦은 주기로 수행함으로써 통합에서 발생하는 오류와 시간을 줄이기 위한 기법이다.
Extreme Programming Community (XP)에서 애자일 방법론의 일부로 Kent Beck에 의해서 고안된 방법으로 다음과 같은 특징을 가지고 있다.

1. CI의 특징
(1) 소스코드 일관성 유지
CI툴을 설정하기 위해서는 기본적으로 소스 관리 시스템이 필요하다.
대표적인 소스 관리 시스템은 Subversion,CVS,Perforce등이 있다.
CI툴은 이 소스 관리 시스템으로부터 프로젝트 소스의 메인 브랜치(trunk 라고도 한다.) 코드를 Check out 받아서 빌드를 수행한다.

(2) 자동 빌드
소스 코드에 대한 빌드는 CI툴에 의해서 자동적으로 이루어 져야 한다.
빌드가 이루어지는 시점을 정하는 방법이 두가지가 있는데 다음과 같다.

1) 커밋에 따른 자동 빌드
다른 방법으로는 소스코드가 소스 관리 시스템에 커밋이 되었을 때 마다 CI툴이 이를 감지 하고 자동으로 빌드를 수행하도록 설정할 수 있다.
이렇게 설정할 경우 소스 코드의 변경이 있을 때 마다 빌드 작업을 수행하기 때문에 소스 관리 시스템에 저장된 소스 코드에 대한 무결성을 보장하기는 매우 좋지만, 빌드 시간이 길 경우 빌드가 적체 되는 현상이 발생할 수 있다.
(일반적으로 대규모 애플리케이션의 FULL 빌드는 길게는 2~3시간 까지 소요될 수 있다.) 그래서 이 방법은 빌드 시간이 오래 걸리는 경우나 커밋이 자주 발생하는 경우에는 적절하지 않다.

2) 시간 간격에 의한 빌드
일정 시간 간격을 정해서 빌드를 하는 방법이다. 매일 5시에 빌드를 한다. 또는 매주 금요일 저녁 5시에 빌드를 한다는 것과 같이 주기를 정할 수 있다. 빌드 스케쥴이 미리 정해져있기 때문에 개발자들이 커밋에 대한 스케쥴을 관리할 수 있고 빌드 시간이 오래걸리는 대규모 빌드에도 적정하다.
 빌드 시간을 정할 때 중요한 점은 가급적이면 퇴근 시간 1~2시간 전으로 개발자들이 퇴근하기 전 시간으로 여유를 두는 것이 좋다.
이후 빌드가 깨진 경우는 컴파일이 실패하였거나 테스트가 통과하지 못하였을 경우인데 이때 소스 관리 시스템에 저장된 코드는 문제가 있는 코드이다. (빌드가 깨졌기 때문에) 이 코드들을 다른 개발자가 체크아웃 받아서 개발을 했을 때 잘못된 코드로 인해서 잘못된 개발 방향으로 갈 수 가 있기 때문에 빌드가 깨졌을 때는 가급적 빨리 문제를 수정하여 빌드를 정상화 시키고 소스 관리 시스템에 저장되 코드의 무결성을 회복하거나 빌드가 성공한 전버전으로 BACK(Revert) 해서 무결성이 보장된 코드내에서 작업하도록 한다. Revert를 위해서는 소스 관리 시스템에 빌드때마다 Tagging을 해서 무결성이 보장된 버전에 대한 History를 관리해야 한다.

Silent period에 대해서
CI툴에서는 소스 관리 시스템으로부터 소스를 체크아웃 또는 업데이트 받을 때 Silent Period라는 옵션을 제공한다.
개발자가 소스를 커밋하고 있을 때 커밋이 완료되지 않은 상태에서 CI툴이 소스를 체크아웃하게 되면 불완전한 코드가 내려와서 빌드가 망가질 수 있다. 이를 방지하는 옵션이 Silent Period인데, 커밋이 있은후 일정 시간동안 소스 관리 시스템에 변화가 없을 때 CI툴이 체크아웃을 받아서 불완전한 코드를 내려 받을 수 있는 가능성을 최소화 하는 것이다.

이렇게 자동 빌드를 하면서 얻을 수 있는 이점은, 주기적인 빌드를 통해서 소스코드의 무결성 관리와 빅뱅방식의 통합에서 올 수 있는 리스크를 개발과정 전반으로 분산할 수 있다.

(3) 자동 테스팅
빌드 과정에서 테스트를 포함할 수 있는데, 주기적인 빌드 과정에 테스트를 포함해서 자동 빌드를 통한 Syntax에 대한 검증과 더불어 테스팅을 통한 기능과 비기능적(성능등)에 대한 요건을 매번 검증함으로써 코드의 품질에 대한 무결성을 함께 유지한다.

(4) 일일 체크아웃과 빌드
개발자가 출근후 소스 관리 시스템에서 최신 코드를 내려받고, 출근전에 현재 코드를 소스 관리 시스템에 저장함으로써 소스 코드에 대한 무결성을 유지한다.

예를 들어 개발자 A와 개발자 B가 같이 개발을 할 때, 개발자 A가 작성한 모듈을 개발자 B가 참고해서 사용한다고 하자, 이런 경우 개발자 A가 임의로 컴포넌트에 대한 작동 방식이나 인터페이스를 변경했을 때 일일 체크아웃과 빌드를 하면 개발자 A의 모듈을 사용하는 개발자 B의 모듈의 컴파일 오류나 또는 테스트 오류가 발생할 것이고 코드 변경으로 인한 임팩트를 빠르게 발견하여 수정할 수 있다.
그러나 통합 빌드의 과정이 일일이 아니거나 일일 체크아웃 빌드를 하지 않고 일주일이나 한달 단위로 할 경우 일주일동안 개발자 B는 잘못된 코드를 양산할것이고, 그 만큼의 시간 낭비가 발생한다.

일일 체크아웃과 빌드는 이를 방지해주는 역할을 한다.

2.CI 프로세스

CI에 대한 프로세스를 정리해보면 다음과 같다.
 

사용자 삽입 이미지


<그림. Continous Integration Process >


(1) 개발자
1) 개발자는 아침에 출근해서 소스 관리 시스템으로부터 최신 코드를 Checkout 또는 update받는다.
2) 코드를 가지고 개발을 수행하고 테스트를 작성한다.
3) 로컬에서 빌드 및 테스트를 진행한다.
4) 테스트과정에서 커버러지분석과 Code Inspection을 수행한다. (Optional)
 커버리지 분석
커버러지 분석은 테스트의 대상중에 테스트에 해당하는 부분중에 어느 부분이 테스트가 수행이 되었는지를 체크하는 과정이다. 개발 과정에서의 테스트 커버러지 분석은 일반적으로 코드 커버러지로 분석한다.
코드 커버러지란 테스트가 전체 소스 코드중 어느부분을 수행했는지를 검토하는 것이다.
코드 커버러지를 측정할 때 가장 중요한 것은 목표 커버러지율을 결정하는 것이다. 코드 100%를 테스트하는 것이 좋겠지만, Exception,If 문에 대해서 100% 테스트가 불가능하다. 또한 Setter와 Getter만 있는 ValueObject의 경우 테스트를 작성하는 것도 쉽고 테스트 자체가 의미가 없나 Coverate rate는 많이 올릴 수 있다. 만약 커버러지율을 강제적으로 높이고자 하면 개발팀에서 VO등 테스트가 필요하지 않고 테스트가 쉬운곳에만 테스트를 집중할 수 있기 때문에 컴포넌트의 우선순위를 정해서 중요한 컴포넌트에 대해서 커버러지를 관리하는 것이 필요하다.
커버러지율은 잘 만든 테스트라도 50~70% 내외이고, 고 가용성 시스템도 80%를 넘기 힘들기 때문에, 컴포넌트의 중요도별로 목표 커버러지율을 융통성 있게 결정하는 것이 필요하다.
대표적인 오픈소스 도구로는 EMMA와 Cobertura등이 있고, 상용 도구로는 Atlassian社의 Clover등이 있다.
 Code Inspection
Code Inspection이란, 완성된 코드에 대한 검토를 통해서 코드상에 존재하고 있는 잠재적인 문제를 발견하는 과정이다. 흔히 “정적 분석” 이라는 이름으로도 불리는데, 이 과정에서 Deadlock에 대한 검출 Lock contention과 같은 병목 구간에 대한 검출 Memory Leak이나 Connection Leak과 같은 자원 누수에 대한 검출과 코딩 스타일 (변수명이나 메서드명 규칙등)에 대한 가이드를 수행한다.
보통 이런 도구들은 룰 셋을 추가하여 Inspection을 각 팀의 스타일에 맞춰서 Customizing할 수 있으며 대표적인 오픈 소스 도구로는 PMD, FindBugs등이 있다.

5) 완료된 코드를 소스 관리 시스템에 저장한다.
완료된 코드와 테스트를 소스 관리 시스템에 커밋한다.

(2) CI Tools

1) 체크아웃
CI Tools는 정해진 시간이나 소스가 커밋이 되었을 때 등 정책에 따라서 빌드를 시작한다. 먼저 소스 코드를 체크아웃 받는다.
2) 컴파일
체크아웃 받은 코드에 내장되어 있는 빌드 스크립트를 기동하여 컴파일을 수행한다.
3) 배포
컴파일이 완료된 코드를 테스트 서버에 배포한다.
4) 테스트 수행
체크아웃 받은 코드내에 있는 테스트 코드들을 수행하고 리포팅을 한다.
5) 커버러지 분석
테스트 과정중에 코드 커버러지를 수행한다.
커버러지의 기본 원리는 커버러지 분석 대상이 되는 코드내에 커버러지 분석 코드를 삽입하여 테스트가 완료된 후에 그 결과를 수집하여 분석을 하는데 분석 코드를 삽입하는 과정을 Code Instrument라고 한다. Instrumented된 코드는 커버러지 분석 기능으로 인해서 성능 저하를 유발할 수 있기 때문에 만약에 테스트 과정에 성능이나 응답시간에 관련된 테스트가 있을때는 커버러지 분석을 위해서 테스트를 마친후에 Instrument를 다시하여 3),4) 과정을 다시 거쳐서 커버러지 분석을 해야 테스트 과정에서 성능에 대한 요소를 올바르게 추출할 수 있다.
6) Code Inspection
다음으로 Code Inspection을 수행하고 리포트를 생성한다.
7) 소스 태깅
1)~6) 과정이 정상적으로 수행되었을 때, 현재 소스 관리 시스템에 저장된 버전을 안정적인 버전으로 판단하고 소스 관리 시스템에 현재 버전에 대한 이미지를 저장하기 위해서 Tagging을 수행하여 현재 버전을 저장해놓는다.
8) Reverse (Optional)
만약에 빌드나 테스트가 실패하였을때는 이전에 성공한 빌드 버전으로 소스를 롤백하고, 실패의 원인을 파악한후에 다시 커밋한다.
이것은 소스 관리 시스템에 저장된 소스는 문제가 없는 소스를 항상 유지하여 개발자들이 문제가 없는 소스로 작업을 할 수 있게 보장해주며, 릴리즈가 필요한 시기에 언제든지 릴리즈가 가능하도록 지원해준다.
9) 결과 분석
빌드와 테스트가 완료된 후에 테스트 결과서를 통해서 문제가 있는 테스트를 개발자가 수정하도록 하고, Code Inspection결과를 PM이 검토하여 담당 개발자가 수정하도록 한다.
다음으로 Coverage 분석 결과를 통해서 테스트가 부족한 부분은 PM이 담당 개발자에게 지시항 테스트를 보강하도록 한다.

3.Hudson 설치

(1) Hudson의 설치 및 기동


1) https://hudson.dev.java.net/ 에서 hudson을 다운로드 받는다.
2) 다운로드 받은 Hudson.war를 Apache Tomcat에 deploy해서 구동 하거나 도는 java –jar hudson.war로 hudon으르 기동한다. 디폴트로 설치된 hudson은 8080포트를 통해서 접근이 가능하다. (Tomcat을 통해서 설치 하지 않은 경우)

WAS에 인스톨 정보
http://hudson.gotdns.com/wiki/display/HUDSON/Containers

(2) Hudson과 소스 관리 시스템 연동
좌측 메뉴에서 “New Job”을 선택하여 새로운 작업을 등록한다.
Job name을 선택하고 “Build a free-style software project”를 선택한다. 아직까지 다른 빌드 선택은 안정화 되어있지 않기 때문에 이 메뉴를 중심으로 설명한다.
 

사용자 삽입 이미지


<그림 1. 새로운 프로젝트의 생성>

(3) 소스 관리 시스템과 연동
Job이 생성되고 나면 초기화면에서 Job을 선택할 수 있다 Job을 선택하면 좌측에 Configure라는 메뉴가 생기는데, 그 안으로 들어가면 Job에 대한 설정을 할 수 있다.

먼저 소스 관리 시스템으로부터 코드를 내려받도록 설정해야 한다.
“Source Code Management”에서 사용하는 소스 관리 시스템을 선택한다.
이 예제에서는 Subversion을 선택한다.
Subversion을 선택한후 Repository URL에 SVN접근 주소를 입력한다.
svn://source.example.com/trunk 그 아래에 “Local module directory”에 SVN 레파지토리의 하위 디렉토리를 선택한다. “/myproject” 식으로
이렇게 하면 svn://source.example.com/trunk/myproject 에서 소스 코드를 매번 내려받게 된다. Repository URL과 Location을 지정하면 Hudson이 자동으로 SVN에 접속을 시도해본다. 만약에 id와 passwd가 필요한 경우에는 아래 그림과 같이 “enter credential”이라는 링크가 Repository URL 아래 나타나서 id와 passwd를 입력할 수 있게 한다.
 

사용자 삽입 이미지


<그림 2. SVN 접속 정보 입력>
여기에 소스 관리 시스템 연결에 관련해서 몇가지 옵션을 추가할 수 있다.

 Use Update
소스 관리 시스템에서 소스를 내려받을 때 디폴트가 모든 소스를 매번 다운로드 받는것인데 이런 경우에는 소스양이 많을 경우 다운로드에 많은 시간이 소요되서 전체 빌드 시간이 늘어날 수 있다. 이때 “Use Update”라는 옵션을 사용하면 처음에만 소스 코드를 전체 다운로드 받고, 두번째 부터는 변경된 소스 코드만 다운로드 받기 때문에 소스 코드를 다운 받는 시간을 많이 줄일 수 있다. (svn update와 같은 명령)

Repository Browser
Repository Browser란 소스 관리 시스템에 저장된 소스의 내용 웹에서 브라우징할 수 있는 도구이다. 도구에 따라서 이전 버전과 변경된 부분에 대한 Diff비교 또는 처음 소스 코드가 생성되었을 때부터 매번 커밋되었을 때 변경 내용에 대한 Revision등에 대한 모든 히스토리를 출력해준다. 이런 기능은 빌드가 깨졌을 때, 바로 빌드 버전에 대한 소스 변경 내용을 추적하여 누가 어떤 코드를 변경하였는지를 추적하여 가능한한 빠른 시간내에 문제를 해결하게 해준다.
이 옵션을 체크해놓으면 빌드가 완료된후 Job의 Changes를 보면 소스 코드가 변경된 부분에 대해서 Repository Browser로 링크가 걸려서 소스를 웹에서 바로 확인하거나 전버전에서 바뀐 부분을 확인할 수 있다.
대표적인 Repository Browser로는 오픈소스 제품인 Sventon과 상용제품인 Fisheye등이 있다.

(4) 빌드 트리거링
다음 설정해야 하는 부분이 Build Triggers 설정이다.
이 설정은 언제 빌드가 돌아야 하는가를 설정하는 부분으로 3가지 옵션을 제공한다.

1) Build after other projects are built
이 옵션에는 다른 Job(Project)의 이름을 인자로 넣는다.
이렇게 하면 지정된 프로젝트의 빌드가 정상적으로 끝나면 자동으로 이 프로젝트가 Invoke된다. 만약에 빌드만 하는 Job과 테스트만 하는 Job이 있고 테스트는 자주 사용하고 빌드후에 반드시 테스트를 해야할 때, 테스트 Job에서 이 옵션으로 선행작업을 빌드로 해놓으면 빌드를 수행할 때 마다 빌드가 성공하면 테스트를 수행하게 된다. 테스트만 수행하면 빌드와 상관없이 테스트만 수행된다.
이 옵션은 프로젝트 실행의 전후 관계(Chainning)을 하는데 매우 유용하게 사용할 수 있다.

2) Poll SCM
이 옵션을 사용하면 여기에 지정한 주기별로 소스 관리 시스템을 폴링(체크)하여 변경이 있을 경우에만 빌드를 수행한다.
 

사용자 삽입 이미지


<그림 Build Trigger 등록 >

시간 설정 방법은 unix의 crontab 명령과 같은 형식으로 아래와 같은 형식을 사용한다.
분 시간 날짜 월 요일

사용 예는 다음과 같다.
# 매일 12시에 실행
00 12 * * *
# 매주 일요일 1시에 실행
00 01 * * 7
# 매일 12시와 5시에 실행
00 05 * * *
00 12 * * *

3) Build periodically
마지막으로 Build periodically는 정해진 시간 주기별로 소스가 변경과 상관없이 무조건 주기적으로 빌드를 수행하며 Poll SCM과 마찬가지로 crontab과 같은 형식으로 스케쥴을 등록한다.

(5) Build
정해진 스케쥴 정책에 따라 빌드 프로세스가 기동되면 실제 빌드를 수행할 빌드 스크립트가 구동되어야 하는데, Hudson에서는 ANT,MAVEN,그리고 Unix/Windows shell을 수행할 수 있도록 되어 있다. 여기서는 ANT 기반으로 설명을 한다.
 

사용자 삽입 이미지


<그림. Invoke ANT 설정 >

Invoke ANT를 선택 하면 다음과 같은 옵션을 선택할 수 있다.

 ANT Version
Hudson 초기화면에서 “Manage Hudson”메뉴로 들어가면 “System configuration” 메뉴에서 여러 개의 ANT_HOME을 등록할 수 있다.
ANT 버전에 따라서 플러그인이 차이가 날 수 도 있고, 프로젝트에 따라서 사용해야 하는 ANT 버전이 틀릴 수 있기 때문에 여러 개의 ANT를 등록할 수 있게 해준다.
예를 들어 프로젝트가 JUnit 3.8대와 JUnit 4.X대로 각각 구현되어 있다면 ANT에 설치되어야 하는 JUnit 라이브러리 버전이 틀리기 때문에 두개의 ANT를 설정해야 할 수 있다. 이런 경우에 “System configuration”에서 ANT를 여러 개 등록해놓고, 이 ANT Version 메뉴에서 필요한 ANT 버전을 선택하면 된다.

 Target
ANT 스크립트의 Target을 설정한다.

 Build File
ANT 스크립트를 지정한다. 일반적으로 build.xml을 지정한다.

 Properties
ANT 스크립트에 전달해야 하는 Property를 지정한다.
예를 들어 스크립트내에 $workspace라는 변수를 지정하였을 경우 –Dworkspace=값 이런식으로 텍스트 상자에 정의하면 빌드 스크립트로 인자를 전달할 수 있다.

 Java Options
ANT 를 기동하는데 필요한 자바 옵션을 지정한다. ANT도 자바 프로그램이기 때문에 여러가지 JVM 옵션이 지정되는데 Heap,Perm size등을 여기서 –Xmx256m 식으로 지정하여 이 옵션으로 ANT 프로세스를 실행할 수 있다.

여기 까지 설정하면 주기적으로 빌드를 자동화 하는 설정이  완료 되었다.

(6) Hudson의 사용
초기화면에 들어가면 등록된 프로젝트 리스트들이 나온다.
 

사용자 삽입 이미지


초기화면에서는 현재 빌드 상태와 프로젝트별 빌드 성공 실패 여부가 나타난다. 빌드가 성공하면 맑은 태양이 실패율이 높으면 천둥 모양으로 아이콘이 변경이 된다.

초기화면에서 프로젝트를 클릭하면 아래와 같은 화면이 나오는데
 

사용자 삽입 이미지


< 그림, Hudson 프로젝트별 초기화면 >
Changes는 빌드 버전별로 소스 관리 시스템에서 지난 버전에 비해서 변경된 내용 누가 변경했는지 그리고 커밋시에 개발자가 추가한 Comment를 확인할 수 있다.Workspace는 이 프로젝트의 빌드 디렉토리를 보여준다. 브라우져를 통해서 빌드에 사용된 파일등을 확인할 수 있다.
그 아래 메뉴가 “Build Now”인데 이 메뉴는 스케쥴에 상관없이 지금 강제적으로 빌드를 하게 한다.
좌측 맨 아래 메뉴는 BuildHistory로 언제 빌드가 수행되었고 현재 빌드 상태와 빌드 성공 실패 여부를 나타낸다.

(7) Hudson과 Email 연동
Hudson 초기화면에서 Manage Hudson > System Configuration 메뉴에 들어가면 Email-Notification 설정부분이 있는데, 여기 SMTP 서버를 설정해주면 빌드가 실패하였을 때 등에 담당자들에게 메일로 통보를 할 수 있다. SMTP 설정을 한후 프로젝트의 configuration 메뉴에서 Post-build Actions에서 Email Notification에 Receipients에 이메일 주소를 적어놓으면 빌드가 실패했을때와 실패한 빌드가 복구 되었을 때 이메일이 발송된다.
 

사용자 삽입 이미지


<그림. Email Notification 설정 >


(8) JUnit 테스트 연동
CI에 대해서 설명할 때 Test에 대해서 설명했는데, Hudson에서는 JUnit Test Report를 출력해주는 기능을 지원한다.
프로젝트 configuration에서 Post-build actions의 “Publish JUnit test result report” 메뉴에서 JUnit 리포트 파일명을 지정해주면 아래와 같이 테스트가 끝나고 테스트 리포트가 생성되면 테스트 성공 실패 여부를 그래프로 나타내주고, 테스트의 Progress도 누적 그래프로 프로젝트 초기화면에서 출력해준다.

사용자 삽입 이미지


<그림. 프로젝트 초기화면에서 테스트 히스토리에 대한 그래프 > 

사용자 삽입 이미지


<그림. 프로젝트별 테스트 성공 실패 요약 >

이때 주의할점은 JUnit의 테스트 리포트의 파일 경로는 절대 경로가 아니라 프로젝트 Workspace에 대한 상대 경로이기 때문에 상대 경로로 지정해야 한다.

(9) Hudson과 Japex를 이용한 부하 테스트 연동
Japex는 단위 테스트에 대한 부하 테스트를 할 수 있는 단위 부하 테스트 자동화 프레임웍이다. Japex에 대한 사용 방법은 단위 테스트의 “단위 부하 테스트” 부분을 참고하기 바란다.
Japex 역시 JUnit과 마찬가지로 성능에 대한 결과 (테스트 소요 시간)를 그래프로 출력할 수 있다. JUnit과 설정 방법이 같으며 프로젝트 > configuration > Post-build Actions > Record Japex test report에 Japex 테스트 리포트 경로를 추가하면 된다.
 
설정이 제대로 됐으면 테스트 수행후에 왼쪽에 Japex Trends Report라는 메뉴가 생겨서 성능 테스트에 대한 결과를 누적 그래프로 출력해준다.

Japex 테스트 플러그인은 Hudson에 Default로 포함된 것이 아니기 때문에 http://hudson.dev.java.net에서 다운받아서 Hudson에 추가로 설치해줘야 한다.


(10) Hudson과 Cobertura를 이용한 Coverage분석
Coverage 분석에 대해서는 EMMA와 Cobertura, Clover에 대한 확장 플러그인을 제공하는데, 플러그인을 설치한후 JUnit과 Japex와 동일한 방법으로 리포트에 대한 위치를 등록해주면 아래와 같이 커버러지의 누적 그래프를 클래스별,라인별,브랜치별로 출력해준다.
 

사용자 삽입 이미지

(11) 그외의 기능들
본 문서에서는 Hudson에 대한 대략적인 기능을 살펴보았다.
Hudson은 이 이외에도 여러 개의 Hudson 인스턴스를 구성하여 클러스터된 빌드환경을 구축할 수 있다. 여기서 클러스터란 로드분산이나 장애 대응등의 의미가 아니라,
하나의 소스 코드를 가지고 Windows,AIX,HP 버전으로 각각 빌드가 필요할 때, 각 서버에 Hudson을 따로 설치하고 각각 관리하는 것이 아니라 설치는 각각 하더라도 하나의 콘솔화면에서 컨트롤을 하도록 설정이 가능하다.
또한 여러 확장 플러그인을 통해서 기능 확장이 가능하다.

(12) Hudson 사용시 주의할점
Hudson은 이미 JBoss 프로젝트나 기타 상용 프로젝트에서 사용될정도로 매우 널리 쓰이고 안정적인 버전이다. 그럼에도 불구하고 오픈 소스의 한계점과 잦은 업그레이드로 인해서 잠재적인 버그가 있고 특히 플러그인들의 버전이 Hudson의 버전 업그레이드를 쫓아가지 못해서 일부 플러그인들은 하위 버전에서만 작동하고 최신 버전에서 작동하지 않는 경우가 있기 때문에 자신이 사용하고자 하는 플러그인들에 맞는 Hudson 버전을 사용하는 것이 중요하다.
여기서 소개된 플러그인들은 Hudson 1.7 버전을 기준으로 사용 및 검증이 되었다.

4. 그외의 CI Tools
예전에는 CI 툴이 Cruise Control이나 Ant hill이 주류를 이루고 있었으나,
Hudson이 등장하면서 많은 프로젝트들이 쉽고 직관적인 인터페이스와 확장성으로 인해서 많이 사용되고 있다.
TeamCity의 경우 일반 버전은 무료로 제공되며 TeamCity Pro는 상용이다. 무료 버전도 상용 코드를 기반으로 하는 만큼 Hudson에 비해서 높은 안정성을 가지고 있으다.
AntHill Pro 역시 꾸준히 Java 진영의 CI도구로 사용되고 Atlassian의 Bamboo도 근래에 들어 많이 프로젝트에 사용되고 있다.

Hudson을 이용한 빌드와 테스트의 자동화.doc


'ALM > Build Automation (빌드 자동화)' 카테고리의 다른 글

이클립스 ALF  (0) 2008.08.12
괜찮은 ALM툴  (5) 2008.06.11
Hudson을 이용한 빌드 배포 테스트 자동화  (8) 2008.04.07
플러그인 개발 순서  (0) 2008.04.02
Code Inspection Tools  (0) 2008.02.29
빌드 자동화 업체  (0) 2008.02.12