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


Archive»


 
 

Vagrant를 이용한 개발환경 자동화

ALM/배포(Deployment) | 2013.10.15 17:53 | Posted by 조대협

참고 : http://ppiazi.tistory.com/m/post/view/id/230



1. vagrant 다운받아서 설치

2. virtual box 다운 받아서 설치

3. 우분트 precise32 버전을 설치 : vagrant box add "precise32" http://files.vagrantup.com/precise32.box 

4. vagrant init precise32

다음 vagrant up 으로 vm 실행 (virtual box에서 보면 실행된게 보인다.)

5. putty ssh에서 localhost:2222로 접속

6. default id/passwd는 vagrant/vagrant


다음에는 chef연동해보기.


본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

maven nexus 설치

ALM/Build Automation (빌드 자동화) | 2013.09.05 23:47 | Posted by 조대협

Nexus 설치 및 Maven 연동

조대협

Nexus maven에서 사용할 수 있는 가장 널리 사용되는 무료 repository 중의 하나이다. www.sonatype.com 에서 다운로드 받아서 설치할 수 있다.

Local nexus를 설치하게 되면, 외부로 부터 dependency를 끌어 오는 수고를 덜고, local nexus proxy (cache)로 사용함으로써 빠르게 라이브러리들을 끌어 올 수 도 있고, 반대로 개발팀내에서 사용하는 공통 라이브러리들을 local nexus에 배포해서 팀간에 공유할 수 있다.

또한 사용자 계정 지정을 통해서 repository에 대한 접근 정책을 정의할 수 도 있다.

Nexus repository의 용도와 목적에 따라서 몇 가지로 나눌 수 있는데, 대표적으로 다음과 같은 종류 들이 있다.

   Snapshots : 빌드등 수시로 릴리즈 되는 바이너리를 배포 하는 장소

   Releases : 정식 릴리즈를 통해서 배포되는 바이너리를 저장하는 저장소

   3rd party : 벤더등에서 배포하는 (Oracle,IBM) 바이너리를 저장해놓는 장소로 특정 솔루션등을 사용할때, 딸려 오는 라이브러리등을 여기에 놓고 사용한다

   Proxy Repository : 원격에 원본 repository가 있는 경우, Local에 캐쉬 용도로 사용한다.

   Virtual Repository : Repository Group은 몇 개의 repository를 하나의 repository로 묶어서 단일 접근 URL을 제공한다.

 

여기서는 가장 널리 사용하는 local repository로 설정 하는 시나리오와 함께, 외부 repository에 대한 proxy 시나리오로 사용하는 설정을 소개한다.

설치

http://www.sonatype.com 에서 nexus 무료 버전을 다운로드 받아서 설치한다. 초기 디폴트 로그인 계정과 비밀번호는 "admin/admin123"이다.


  

Public Repositories라는 repository 그룹에 local repository (Releases Snapshots, 3rd party) proxy repository를 포함시킨다.




 

다음으로 Proxy Repository Remote Repository의 내용들에 대한 라이브러리 목록(Index) Local Caching할 수 있도록 되어 있다. 이렇게 하면, nexus proxy repository에 실제 바이너리가 내려와 있지 않더라도 목록이 미리 내려와 있기 때문에, nexus search 기능을 통해서 검색이 가능하다.

"Maven Central Repository" "Central" repository 에 설정을 해보자 "Central repository"를 선택한 후, 메뉴에서 "Download Remote Indexes" 라는 Option "True"로 변경한다. 다음 SAVE 버튼으로 저장한 후, 상단 테이블 메뉴에서 "Central" repository를 선택한 후 오른쪽 버튼을 눌러서 팝업 메뉴에서 "update index"를 실행하면, 원격 maven repository에서 라이브러리 목록을 읽어서 업데이트가 된다.

 



 

업데이트가 끝나면 "Browse Index" 메뉴에서 라이브러리 목록이 새롭게 업데이트 되어 있는 것을 확인할 수 있다.

 



Maven에서 local nexus Proxy (Cache) repository로 설정하기

Nexus 설정이 끝났으면 다음으로 maven nexus rmirroring repository 설정해보자.

$MAVEN_HOME/.m2/setting.xml

파일에서 <mirrors> section에 아래 내용을 추가하자

 

<mirror>

      <id>nexus</id>

      <mirrorOf>*</mirrorOf>

      <name>Local nexus repository.</name>

      <url>http://localhost:8081/nexus/content/groups/public/</url>

    </mirror>

  </mirrors>

 

설정이 끝난후, maven 빌드를 수행하면 maven script가 원격지가 아닌 local에 있는 nexus repository를 통해서 라이브러리를 다운로드 하는 것을 확인할 수 있다.

 



또한 nexus console을 통해서 "Browse Storage" 메뉴를 통해서 "Central" repository storage 를 보면 빌드에 사용되었던 모든 라이브러리들이 local nexus에 다운로드 받아져 있음을 확인할 수 있다.

 


 



본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

  1. gt1000 2013.09.06 07:54  댓글주소  수정/삭제  댓글쓰기

    안녕하세요.
    늘 좋은 글 잘 읽고 있습니다.
    Nexus 관련 하나만 질문 드려도 되겠습니까?
    회사에서 Nexus 를 설치 하는데
    윈도우에서는 아무 문제가 없는데
    Linux 버전만 꼭 설치 후 ext.js 관련 Javascript
    오류가 나서 기능이 정상 동작 하지 않았습니다.
    모든 버전을 다 테스트 해 봤는데...
    1.x 대 버전부터 2.06 버전까지만
    문제가 없어서 할수 없어 최신 버전이 아닌
    2.06 버전을 현재 사용하고 있습니다.
    좋은 하루 되십시요.

nexus pro에 대한 고급 기능소개


조대협 (bwcho75@지메일)


nexus는 maven repository로 매우 유명한 솔루션이다. 오픈 소스 버전은 maven을 사용하는 경우에는 거의 필수적으로 사용이 된다고 해도 과언이 아니다.

nexus의 상용 버전인 nexus pro의 경우 CLM (Component Life-cycle Management) 개념을 도입하여, 접근제어나 컴포넌트에 대한 security 나 license risk등을 관리 통제할 수 있다.

이 글에서는 nexus pro에 대한 몇 가지 고급 기능에 대해서 살펴보고, 이를 통해서 컴포넌트(라이브러리)의 관리가 단순한 중앙 집중형 공유만이 아닌 일종의 life cycle 개념이 있다는 것을 이해하도록 해보자


 

Nexus의 상용 버전인 Pro 버전에는 단순한 공유나 maven repository cache 용도뿐만이 아니라 조금 더 복잡한 기능의 라이브러리 관리 기능을 제공한다. Nexus에서는 이러한 개념을 CLM (Component Life-cycle Management)이라고 하는데, 라이브러리에 대한 접근 제어나 정책 관리등이 이에 해당한다. 몇가지 대표적인 오픈소스 정책 관리 기능을 살펴보자.

근래에 소프트웨어 개발 패러다임은 오픈소스를 이용한 소프트웨어 개발이 많다. 많은 오픈 소스 라이브러리를 사용하게 되는데, 문제는 각 오픈소스 컴포넌트들의 라이센스 정책이 다르다는 것이다. GPL,Apache,MIT,BSD 등 여러가지 라이센스 정책이 있는데, 라이센스 정책에 따라서, 어떤 오픈 소스는 사용에는 제약이 없지만 배포시 소스코드를 변경해야 하거나, 유료로 비용을 지불해야 하는 경우도 있고, 2.0 버전에서는 멀쩡하게 아무 제약없이 사용할 수 있었던 컴포넌트들이 3.0 버전으로 업그레이드 되면서 제약이 생기는 경우가 있다. (오라클이 인수한 MySQL의 경우 제품에 번들해서 재 배포할 경우 일정의 비용을 지불해야 한다.)  이러한 이유 때문에, 오픈소스 컴포넌트에 대한 라이센스 체크는 점점 필수적인 요건이 되어가는데 문제는 하나의 서비스나 소프트웨어 제품을 개발하는데, 수백개 이상의 라이브러리가 사용된다는 것이고, 각 버전마다 일일이 라이센스를 체크한다는 것은 보통일이 아니다. Nexus는 이런 오픈소스 라이브러리 정책을 repository 차원에서 관리해준다.

오픈소스 라이센스 정책 관리

Nexus proxy repository를 선택하고, Analysis 라는 버튼을 누르면, 현재 repository에 저장되어 있는 오픈 소스에 대한 라이센스 정책을 분석하여 다음과 같이 보여준다. 이 라이센스 정책에 대한 DB nexus 판매사인 sonatype으로 부터 제공된다.



각 라이브러리가 어떤 라이센스 정책을 사용하는지, 그리고 각 라이센스 정책이 문제가 없는 지등을 찾아준다.

Security 체크

또한, 보안에 위험이 있는 라이브러리등을 찾아서 보안 위험도등을 표시해준다. 2013년 기준으로 struts2에 대해서 아주 큰 보안 위험이 발생된 일이 있었다. 이렇게 중앙의 repository에서 회사내에서 사용하는 라이브러리에 대한 보안 위험성을 감지해서 중앙에서 통제하게 되면, 개별 개발자에 대한 수고도 덜 수 있을 뿐더러, 보안 위험에 대해서 피해갈 수 있는 장점을 가질 수 있다.



이렇게 체크만 할뿐만 아니라, 이렇게 검출된 문제 있는 라이브러리들을 접근하지 못하게 막을 수 있다.

Procurement

nexus pro에는 “artifact procurement” 라는 기능이 있는데, 이 기능을 사용하면 proxy repository를 만들고, 여기에 속해 있는 라이브러리에 대해서 white list 또는 black list 방식으로 접근을 제어할 수 있다. 아래 그림은 asm-parent 라이브러리에 대해서 모두 접근을 제어 하는 설정을 적용한 예이다.



 

Staging

또 다른 재미 있는 기능중에 하나는 staging 개념을 지원한다는 것이다.

즉 개발자가 컴포넌트나 라이브러리를 개발하여 nexus에 배포하면 다른 개발자나 사용자들이 바로 그 라이브러리를 사용하게 하는 것이 아니라, 일종의 워크플로우를 통해서 릴리즈 절차가 끝나면 일발 개발자들이 사용할 수 있도록 프로세스를 조정할 수 있다.

이를 위해서 staging repository라는 개념을 제공하는데, 설명하자면 다음과 같다.



개발자가 컴포넌트를 개발하고, 개발이 끝나면 staging repository로 배포를 진행한다. 배포된 repository QA 그룹 엔지니어만 접근이 가능하다. QA 엔지니어는 컴포넌트를 받아서 테스트를 진행하고, 문제가 없으면, 해당 컴포넌트를 베타 테스트 단계로 넘긴다.

베타 테스트 단계에 있는 컴포넌트는 베타 테스트 사용자에게만 접근이 허용되며, 테스트가 끝나면 일반 repository로 이동되어 일반 개발자도 접근이 가능하게 해준다.

이 워크플로우에서 단계별로 넘어갈때, 각 단계 이동별로 정책을 정할 수 있다. 예를 들어 앞서 설명한 security level이 낮은 경우 reject을 하거나, open source 라이센스가 문제가 있는 경우에, reject을 하는 중의 policy를 정의할 수 있다

< 출처 : http://www.sonatype.com/take-a-tour/nexus-pro-tour-start >

본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

git 사용법과 소스 관리

ALM/SCM/VCS | 2013.07.28 01:00 | Posted by 조대협

 소스 코드 관리와 git

조대협 (bwcho75@지메일)

소프트웨어 개발에 있어서소스코드의 관리는 중요한 포인트 중의 하나이다다양한 버전과 변경 관리협업을 위해서는 소스코드를 저장 및 관리할 수 있는 시스템이 필요하고이를 VCS (Version Control System) 또는 SCM (Source Code Management) System이라고 한다소스코드 관리 시스템의 주요 기능은 다음과 같다.

협업을 위한 코드 공유 - 여러 사람들이 협업을 할 경우코드를 각 개발자와팀간에 공유할 수 있어야 하며

접근 제한사용자의 권한 등급에 따라 접근을 제한해야 한다.

다양한 버전(형상) 관리소프트웨어 개발 버전 또는 릴리즈 (브랜치마다다른 코드를 저장할 수 있어야 한다예를 들어 릴리즈된 버전이나 마이너 버전에 대한 코드 관리패치 코드 관리 등이 그 예가 될 수 있다. 또한 다양한 브렌치중 두개 이상의 브렌치를 하나의 코드로 합칠(merge)할 수 있어야 한다.

특정 시점 추적 태깅 설명

변경 추적 - 마지막으로각 코드에 대한 변경을 추적할 수 있어야 한다누가언제어떤 이유로 코드를 어떻게 변경을 했는지를 추적하여 문제 발생시 원인 분석을 할 수 있어야 한다.

1)   Branch

먼저 소스코드 관리에 대한 개념 이해를 위해서는 Branch의 개념 이해가 필요하다소프트웨어 개발을 할 때하나의 저장소에 소스코드를 저장해서 개발하고개발자간의 공유를 해서 협업을 진행한다.

 개발을 진행하다가 특정 목적에 의해서 별도의 작업에 의해예를 들어 영문으로 된 버전을 중국어나 한국어로 제공하기 위해서는 기존 개발 소스코드의 복사본을 만들어서,중국어 개발용으로 하나 사용하고한국어 개발용으로 하나 사용 한다이렇게 새롭게 만들어진 소스코드의 복사본 (중국어버전한국어 버전)을 브랜치라고 하고원래 소프트웨어를 개발하던 소스코드 저장소를 메인 브랜치(또는 trunk version, head version)이라고 한다.

이렇게 코드의 원본에서 용도와 목적에 따라서 새로운 복사본을 만들어 나가기 때문에,메인 코드에서 복사본을 나뭇가지 (Branch)라고 하고이 모양이 마치 나무와 같은 구조가 되기 때문에, Source Code Tree또는 Branch Tree라고 한다.

2)    Check Out / Commit & merge

소스코드 저장소를 만들었으면 해야 할 일이 코드를 저장하거나 내려 받는 일이다.

코드를 내려 받는 행위를 Check Out이라고 하고작성된 코드를 저장소에 업로드 하는 행위를 Commit이라고 한다.

VCS의 종류에 따라서 Check Out된 코드의 경우다른 사람이 편집을 할 수 없고read만 할 수 있도록 lock을 걸 수 도 있다. (VCS 종류에 따라 다르다). 이 경우 다른 사람이 내가 편집하고 있는 코드를 편집할 수 없기 때문에코드 작성에는 문제가 없지만 반대로 다른 개발자는 lock이 풀리기 까지 기다려야 하기 때문에협업에 문제가 발생할 수 있다그래서 lock을 걸지 않고 코드를 동시에 2인 이상이 코드를 다운받아 편집할 수 있는 방법을 제공하는데이 경우 코드를 Commit을 할 경우한 파일을 다운 받아서 각자 편집을 하고 저장을 시도할 경우코드상 Conflict(충돌)이 발생한다.

 즉 개발자 A,B가 소스 코드 버전 1 Check Out 받았다고 하자개발자 A가 소스코드 2번 라인에 "printf('hello world')" 라는 코드를 추가하고 Commit을 해서 코드 버전이 2가 되었다고 했을 때, B도 역시 2번 라인에 "printf('hello developer')" 라는 코드를 추가하고 Commit을 하려고 하면, A B가 편집한 내용이 충돌이 생긴다둘다 1번 버전의 코드를 가지고 수정을 하였으나공교롭게 개발자 A,B 가 같은 파일을 수정하였기 때문에 VCS 입장에서는 B 개발자가 수정한 내용을 반영하게 되면A개발자가 반영한 내용이 없어져 버리기 때문에 문제가 될 수 있다.

이런 경우 VCS에서 B Commit하려는 코드가 현재 버전인 2 버전에 의해서 편집 된것이 아니라는 것 을 알려주고개발자 B에게 선택을 하도록 하는데, 2 버전 코드와 다른 내용을 병합 (merge)하게 하거나, 3버전의 코드를 Overwrite하여 2버전의 코드 변경 내용을 무시할 수 있도록 한다.

대부분의 경우에는 당연히 다른 개발자의 변경 내용을 무시할 수 없기 때문에, merge를 선택하게 되고, merge는 개발자B 2번 버전과의 로직의 차이를 일일이 확인하면서 수동으로 merge를 하도록 한다.

3)   Update

Update의 개념은 개발자가 소스 코드를 Check Out 받아 놨을 때현재 작업 버전이 오래되거나또는 다른 개발자가 Commit을 먼저 해서, VCS의 소스코드 버전이 올라갔을 때, VCS Local의 코드를 동기화 시키기 위해서 사용한다.

위에서 설명한 Commit시 발생하는 Conflict(충돌시나리오와 마찬가지로내가 변경한 코드와 다른 개발자에 의해서 변경된 코드가 Conflict이 발생할 수 있으며앞에서 설명한 방법과 같은 방법으로 수동으로 코드의 변경 부분차이 나는 부분)을 병합하도록 한다.

4)   Tagging

다음으로 Tagging이라는 개념을 알아보자, Tagging 이란코드를 개발 중에특정 시점의 이미지에 표시를 해놓는 것을 의미한다예를 들어매일 소스코드에 대한Tagging을 달아놓으면개발 중에 문제가 생겼을 경우에특정 날짜의 소스 코드로 다시 돌아갈 수 가 있다.

Tagging은 주로, Build 시마다 하는 경우가 많은데 (이를 빌드 태그라고 함). 통상 적으로 빌드시 에러가 날 경우에 다른 개발자들이 빌드 에러로 인하여 개발을 못하는 경우가 생길 수 있기 때문에이런 경우에는 이전 Build시 태그해놓은 버전으로 소스코드를 돌려서 다시 개발을 수행하고문제가 해결 되면새로운 코드를 다시Commit 하는 방식으로 개발을 진행한다.

5)    Release Branch

다음으로 Branch Release Branch에 대한 설명이다.

패키지 소프트웨어 개발 프로세스를 생각해보자예를 들어서버 제품을 개발하여,출시를 했다고 하자현재 개발 중인 메인 Branch 에서 해당 시점에 릴리즈를 했다.릴리즈한 서버의 버전은 6.1이다메인 branch 로는 계속해서 신제품 개발을 이어나가고 7.0 개발을 진행 중이었다.

이때, 6.1을 사용하던 고객에게서 버그 수정 요청이 온경우 어떻게 해야 할까?

6.1 코드에 일부 코드만 수정하여 패치를 발급하면 되지만메인 branch의 경우 이미 7.0 버전 개발을 위해서 코드 개발이 많이 진행되었기 때문에 6.1 에 대한 코드는 바뀌어서 찾을 수 가 없고 7.0 버전 역시 개발이 완료되지 않아서 수정이 불가능하다.

이런 시나리오를 방지하기 위해서 패키지 형태의 소프트웨어 개발은 각 릴리즈 마다release branch를 발급하는 것이 좋다.

우리가 사용하는 Windows , Windows XP,7등으로 release를 하지만 Service Pack이나 필수 패치등을 발급하는 것은 각 release  branch를 발급한 뒤에, branch 별로 패치나 service pack것과 같은 원리이다.

이런 release branch는 웹서비스 (face book )의 경우하나의 코드가 하나의 서비스에만 배포가 되기 때문에별도의 release branch를 유지하는 것 보다는release tagging을 한 후에이슈가 있을 경우 이슈를 fix한 최신 버전을 다음release 때 배포 하는 방식등을 주로 사용하기 때문에, release branch의 효용성이 패키지 소프트웨어에 비해서 떨어진다.

6)   QA branch

다음으로 사용할 수 있는 branch중 하나는 QA branch 이다. production 으로 (상품화 하기 위해개발팀에서 source code freezing 하고 QA 팀에 해당 제품을 넘겨서 테스트를 의뢰할 경우, QA팀에서 계속해서 버그 수정 요청을 해오게 된다이 때버그를 main branch에서 계속해서 수정을 하게 되면, main 개발에 많은 수정이 가해지기 때문에 개발이 어려워질 수 있다. (merge도 많이 발생하고번거로움그리고, main branch에서는 개발이 계속 진행되기 때문에, feature 변경이나 기타 수정이 있을 경우 QA에 의해서 reporting된 버그가 제대로 재현이 되지 않는 경우가 있을 수 있다그래서 QA에 넘기기 전에 QA branch를 따고버그에 대한 fix를 이QA branch에서 수행 및 반영 한다.

QA가 모두 완료되고 나면 QA branch에 있는 변경 내용을 다시 main branchmerge하여, bug 수정 내용을 반영하도록 한다.

7)    소스 코드 브랜치 관리 전략

앞서 살펴본 바와 같이 사실 branch main code (branch)의 복사본이다용도에 따라서 얼마든지 만들 수 있고필요에 따라 merge를 할 수 도 있다그러나 패키지냐웹서비스냐와 같은 소프트트웨어의 종류와팀의 크기와 구조 , 릴리즈 정책등에 따라서 어떠한 branch를 언제 사용할지가 다르기 때문에개발하는 소프트웨어의 형상에 따라서 알맞은 branch 전략을 결정해야 한다.

또한 VCS 제품에 따라, 몇몇 제품의 경우에는 이미 자사 제품 특성에 맞는 브렌치 구조에 대한 레퍼런스를 제공하거나, 또는 성격에 따라 맞는 레퍼런스 브렌치 모델이 많이 공개되어 있다.

또 다른 방법으로는 오픈소스에서 사용하고 있는 소스 코드의 tree 구조를 레퍼런스 해보는 것도 좋은 방법이다.

다음은 몇 가지 유용한 브렌치 구조에 대해서 소개하도록 한다.

오픈소스 소스 코드 브렌치 관리 전략

다음은 요즘 많이 사용하는 VCS 솔루션의 하나인 git를 이용한 branch 전략이다.


[1]

이 브렌치 구조는 이미 git flow라는 이름으로, git를 사용하는 사람들에게는 널리 알려져 있는 브렌치 모델이다. 이 구조는 오픈소스와 같이 대규모의 분산된 개발 조직이 서비스나 오픈소스 제품을 만드는 구조에 매우 적합니다.

http://nvie.com/posts/a-successful-git-branching-model/

그리고, 이 구조대로, git의 저장소를 정의하고, 쉽게 사용할 수 있도록 git flow라는 오픈소스 도구를 제공한다. https://github.com/nvie/gitflow

개념을 살펴 보면, main branch에서는 개발을 진행하지 않고별도의 develop branch를 만들어서 여기서 개발을 진행한다기능 (feature) 별로 feature branch를 별도로 만들어서 개발을 진행하고 feature 개발이 완료되면, develop branch merge를 한다.

master develop branch의 관계는 재미있는 개념이 있는데, 바로 code review이다. 개발자가 코드 수정을 하였을 경우, Jenkins 등의 빌드 시스템에 통합되서 빌드되고, 테스트되어야 동작 여부를 확인할 수 있기 때문에, 어딘가 코드를 공유할 수 있는 장소가 필요하다. 즉 개발이 완료된 부분은 먼저 develop branch에 저장되서 컴파일 및 테스트를 끝내고, code review를 위해서 다른 개발자와 reivew를 하고 승인이 되면 그 때 master branch로 반영이 되는 것이다.

release 시기가 되면별도로 release branch를 만든 후에, release에 필요한 각종configuration file 정리기타 메뉴얼이나 문서등을 합쳐서 release하고, release가 된 버전은 main branch에 반영한 후 tagging을 한다.

오픈소스 프로젝트에 보면소스 코드가 날짜나 버전 별로 open 이 되어 있는 형태를 본 기억이 있을 것이다이렇게 main branch는 외부 개발자 공개를 위해서 유지하고특별한 release가 있을때에만 반영하여항상 main branch에는 문제 없는 버전이 존재하도록 한다.

또한 혹시 main branch를 통해서 공개된 버전이 문제가 있을 경우에는 별도로 Hot fix (버그 수정용) branch를 만들어서 버그를 수정하고테스트를 끝낸 후에버그 수정 내용을 main branch에 반영하고 또한 함께, develop branch에도 반영한다.

 일반적인 소프트웨어 브렌치 관리 전략

다음은 git 이전에 많이 유행하였던, Subversion (이하 svn) 사용시 많이 사용하는 브렌치 구조이다. SVN에서는 크게 아래와 같이 세가지 브렌치를 메인으로 하여 코드를 저장하는 구조를 사용한다.



trunk 또는 head 라고도 하는데, 이 브렌치는 현재 개발이 진행중인 코드를 저장한다.

개발을 진행중에, 빌드나 또는 특정 날짜를 기준으로 tag를 따놓는데, 향후 빌드 실패나, 특정 날짜의 개발 내용으로 돌아가기 위해서 사용하며 이는 tags라는 브렌치 아래 들어간다. tag 명은 위의 그림에서와 같이 날짜를 사용할수 도 있으며, 또는 빌드 시스템의 빌드 #를 사용하기도 한다.

마지막으로 release 브렌치이다. Branches는 릴리즈시마다, 그 때의 소스코드 형상을 저장해놓는 구조이다.

이 브렌치 전략은 단일팀에서, 서비스나 제품을 릴리즈 주기를 통해서 릴리즈 하는 구조에 적절하며, 버그 수정이나 기능 개선은 다음 버전(release)에 포함 시키는 형태일 경우 적절하다. (별도의 패치를 위한 브렌치를 관리하는 전략이 없기 때문에)

8)   분산 형상 관리 시스템 Git

그러면 근래들어 많이 사용되고 있는 VCS 시스템인 Git에 대해서 알아보도록 하자.

Git는 기본적으로 분산 소스코드 관리 시스템이다. 모든 개발자가 중앙 저장소에 붙어서 작업을 하는 것이 아니라. 소스 코드가 여러개의 서버에 다른 복제본으로 존재할 수 있다. 먼저 이 분산 저장소의 개념부터 이해 해보도록 하자

중앙 집중형 저장소 (Centralized Version Control System)

중앙 집중형 저장소는, 코드가 저장 서버 단 한군데만 저장된다. 개발자가, 코드를 받아서 수정하고 저장하면, 그 내용이 바로 중앙 저장소에 반영된다 (당연 하지만). 즉 서버에는 항상 마스터 버전(최신 버전)의 소스코드가 저장되어 있다.

  그리고, 서버가 다운 되거나, 네트워크에 접속할 수 없다면 당연히 코드를 commit하거나 최신 코드를 내려받을 수 없다.



분산형 저장소 (Distributed Version Control System)

분산 저장소는 말 그대로, 소스코드가 하나의 중앙 서버가 아니라, 여러개의 서버나 여러개의 개발자 PC에 저장될 수 있으며, 각각이 소스 코드 저장소 (source repository)가 된다. 각 저장소에 저장되는 소스 코드는 같은 버전의 코드가 아니라 제각기 다른 브렌치 코드가 저장된다. 즉 서버 A에는 branch A,B,C 버전이, 서버 B에는 branch A,C,D버전과 같이 다른 브렌치 버전을 저장할 수 있다. 즉 각 저장소에 브렌치 버전이 모두 틀리고, 소스 코드를 access해서 가지고 오는 장소도 모두 다르기 때문에, 시스템 자체에서는 마스터 버전 (최신 버전이 항상 어느 곳에 저장되어 있는가)의 개념이 없다. 예를 들어 설명하자. 아래 그림과 같이 Developer Terry Server A에서 코드를 내려 받아서, 데이타 베이스 관련 모듈을 개발하고 있고, Michelle Server B에서 UI 관련 모듈을 개발하고 있다. 각자는 개발을 진행하면서, 수시로 각자 Server A Server B Commit을 하고 있다고 가정하자. Server A는 전체 시스템에서 데이타 베이스 모듈 부분은 가장 최시일테고, Server B에는 UI 모듈의 가장 최신 버전의 코드가 들어가 있을 것이다.

대신 각 모듈의 개발이 끝나면, Server A Server B의 코드를 merge하여, 개발 내용을 병합(합칠 수)할 수 있다.

즉 전체 시스템의 최신 소스 코드가 명시적으로 어느 한곳에 저장되어 있지 않는 구조이다.



이러한 형태로, 코드의 여러 버전을 여러 저장소에 분산해서 저장할 수 있기 때문에, 몇가지 장점이 올 수 가 있는데, 팀 단위나 기능 단위로 저장소를 분리해서 개발하거나 릴리즈 버전 단위로 저장소를 분리해서 개발할 수 있는 등 소스코드 버전관리에 많은 유연성을 가지고 있다.

또한 중앙 저장소의 개념이 없기 때문에, 특정 VCS 시스템이 장애가 나더라도, 내가 사용하고 있는 VCS만 문제가 없다면 개발을 계속할 수 있고, 앞에서 언급한바와 같이 개발자의 Local PC VCS를 설치하여 네트워크 연결이 없는 상태에도 개발을 지속할 수 있다.

그리고 소스코드가 중앙 서버만이 아니라 여러 서버와 PC에 분산 되서 저장되기 때문에 서버 장애로 저장소가 손상된다고 해도, 다른 서버나 다른 PC에서 소스코드와 History들을 모두 저장하고 있기 때문에, 중앙 서버 방식에 비해서 복구가 쉽다.

Git

DVCS Mercurial, Bazzar등 여러가지 제품이 있으나, 근래에는 git 가 가장 많이 사용되고 있다. Linux Kernel 프로젝트나, 안드로이드, Gnome, Ruby on Rails등이 Git를 사용하는 대표적인 프로젝트이다.

Git는 기존의 VCS에 비해서 설치가 쉽고, 속도가 매우 빠르다. 그리고, branch merge가 매우 빠르고 사용이 쉽다. 특히 merge의 경우 누가? 언제? 무엇을 어떤 부분을 merge했는지 까지 상세하게 추적이 가능하기 때문에, 오픈 소스와 같이 대규모 개발자가 동시에 개발을 진행하는 환경에서는 매우 유용하다. 오픈소스 개발자들이 network가 연결되어 있지 않은 상황에서도 언제 어디서나 개발을 할 수 있다. 그리고, 자기만의 개발 branch로 개발을 하다가 main branch merge도 쉽다. 아마 이런 장점이 git major VCS로 만든게 아닌가 싶다.

 

그러면 간단하게, git의 간략한 기본 사용법을 알아보자.



1)     Repository 생성 (init clone) - git에서 init 명령은 local에 새롭게 저장소를 만드는 명령이다. 이를 통해서 새롭게 git 저장소를 만들 수 있다.
만약에 원격에 있는 서버의 저장소를 복제해서 로컬에 만들려면
git clone
사용자명@서버주소:"저장소 경로"
명령어를 사용하면 된다.

2)     파일 추가
다음으로 파일을 추가해보자. 위의 예제에서 echo 명령을 사용하여, init.html, index.html 파일을 생성하였다. 그리고 git에 이 파일이 git commit이 될 예정이라고 mark를 해놓는다. 위의 예제에서는 index.html 파일만 먼저 commit을 하도록 한다.
git
에서는 add의 개념을 이해하려면 먼저 staging area라는 개념을 이해해야 한다.



작업 디렉토리 (working dir)에서 작업을 한것은 내 local pc에만 반영된 내용이다. 이 내용을 저장소로 올리기 전에, git staging(git에서는 index라는 이름으로 사용한다.) 이라는 개념을 제공한다. 소스 코드를 저장소에 최종 반영하기 전에 두 단계를 거치는 two-phase commit을 사용한다.

staging이라는 개념은 작업 디렉토리에서 작업한 내용을 반영하기 전에, 최종으로 확인하는 중간 단계 정도로 생각하면 된다. 작업 디렉토리에서 작업한 내용 중 commit할 내용을 미리 "add" 명령어를 통해서 stage에 반영한 후에, stage에 있는 내용을 commit전에, 저장소내의 코드와 비교(diff)하면서, commit을 할 수 있다.

작업 영역과 (working directory) stage영역간의 비교는
"git diff"
명령어를 통해서 가능하고  stage master 버전에 저장된 코드의 변경 사항은"git diff --cached"  (또는 git diff --staged) 명령을 이용해서 비교가 가능하다.

작업 디렉토리에서 바뀐 내용을 몽땅 한꺼번에 commit하는 것이 아니라, feature별이나 특정 그룹 (기능이나 FIX별 또는 모듈별)staging에 이동 시킨후, 하나하나 검증하면서 그룹별로 commit이 가능하다.

3)     저장소에 반영 (commit)
add
를 통해서, 변경본 반영 리스트를 작성하고, diff등을 통해서 확인이 끝나면, 이를 저장소에 반영해야 한다. 반영은 commit 명령어를 사용하며, commit에 대한 comment (변경 내용)을 같이 넣는다.
git commit -m "
변경 내용 description"

4)     변경 내용을 원격 저장소에 반영 (push)
앞 단계 까지 끝났으면, 소스코드의 변경 내용은 내 local pc에 있는 git 로컬 저장소에 반영되었다. git는 앞서도 설명했지만 분산저장소이기 때문에, commit을 한다고 해서, 서버에 코드가 저장되지 않는다. 기본적으로 commit은 로컬 저장소에 반영이 되지만, 서버의 원격 저장소에 코드를 반영하려면 별도의 반영 작업이 필요하다. 반영은 push 명령어를 사용한다. 다음과 같이 push 명령을 사용하여, 원격 서버에 반영한다.



git push origin "브렌치명"
) git push origin master (master branch push하는 명령)
※단 이 경우는 처음에 저장소를 만들때, git clone을 통해서 원격 저장소로 부터 코드를 읽어와서 로컬 저장소를 만들었을 경우이다.

만약에 원격 저장소로 부터 clone을 해서 만든 경우가 아닐때, 원격 저장소로 code를 밀어 놓고자 한다면, 원격 저장소를 정의해줘야 한다. 원격 저장소를 정의 하는 방법은
git remote add "
원격저장소명" "원격저장소주소"
) git remote add zipkin https://github.com/twitter/zipkin.git
zipkin
이라는 이름으로 https://github.com/twitter/zipkin.git URL에 있는 원격 저장소를 등록하였다. 여기에 push를 하려면, git push zipkin master (zipkin 원격 저장소 master branch push)

분산 저장 VCS 답게, 원격 저장소는 하나가 아닌 여러 개를 git remote add 명령을 통해서 추가 할 수 있고, 등록되어 있는 원격 저장소는 git remote -v 명령을 통해서 조회해볼 수 있다.

5)     브렌치 관리
소스코드 브렌치에 대한 개념은 앞에서 설명하였기 때문에 별도로 설명하지 않고, 명령어 사용법만 설명한다. 현재 코드에서 브렌치를 생성하려면

git branch "브렌치명" 을 사용한다..
) git branch bugFix
bugFix
라는 이름으로, 현재 코드에서 branch 만들기

그리고 현재 작업중인 브렌치를 이동하려면
git checkout "
브렌치명" 을 사용한다.
) git checkout master
master
브렌치로 이동

6)   merge

merge는 다른 브렌치의 내용을 현재 작업 중인 브렌치로 합쳐 오는 작업이다.
예를 들어 내가 master 브렌치에서 작업을 하고 있을때, 예전에 버그 수정을 위해 만들었던 bugFix라는 브렌치의 내용을 현재 브렌치에 반영하고 싶을 경우, master 브렌치에서 "git merge bugFix" 라는 명령을 사용하면 bugFix 브렌치의 변경 내용을 master 브렌치에 반영하게 된다.

이 때, 서로 변경 내용이 다르거나, 같은 코드 라인을 수정하였을 경우 충돌 (conflict)이 발생하는데, 충돌이 발생한 경우, 직접 충돌 부분을 수정한 후, git add를 통해서 수정한 파일을 넣고, git commit을 통해서 최종 반영한다.

7)   원격 저장소의 변경 내용을 읽어오기 (pull & fetch)

반대로, 원격 저장소에서 다른 사람들이 작업했던 내용을 내 로컬저장소로 가지고 오려면 pull fetch 라는 두 가지 방법이 있다.

먼저 fetch ("git fetch")의 경우, 원격 저장소의 업데이트 된 내용을 별도의 브렌치로 읽어 온다. 실제 내가 로컬에서 작업중인 로컬 저장소에는 반영되지 않는다. 반영을 하려면 원격 저장소에서 읽어온 내용을 merge를 통해서 내 작업 영역에 반영해야 한다 이해를 돕기 위해서 아래 그림을 보자.



원격 저장소의 v1 버전에서 clone을 받아서 로컬 저장소에서 개발을 시작하였다. 로컬에서 여러번의 commit을 통해서, v4 버전까지 개발을 진행하였다.

그 상태에서, 원격 저장소의 변경 내용을 업데이트 하기 위해서 fetch를 하면, 원래 clone을 하였던 원격 저장소의 브렌치 (master)의 최신 코드를 로컬로 복사해서 origin/master라는 이름의 브렌치에 업데이트를 한다. 내 작업 영역은 여전히 v4이고, 원격 저장소의 변경 내용은 반영되지 않았다.

이를 반영하려면 "git merge origin/master"를 해주면 merge를 통해서 내 작업 영역에 반영된다. (v5 버전상태)

pull ("git pull")은 한마디로, fetch + merge. pull 명령어 하나로 자동으로 fetch merge를 한꺼번에 해주는 명령어 이다. 아래 그림을 보자, 처음에 원격 저장소에서 v1 버전을 clone으로 내려 받아서 개발을 하다가, v4 버전에서 원격 저장소의 코드를 pull 해주면, 원격 저장소의 clone을 한 원본 저장소와, 로컬의 저장소의 현재 브렌치를 merge하여 새로운 버전으로 만들어 준다.



8)   태깅

git에서 태깅은 매우 간편하다.

git tag -a "태그명" -m "태그 설명"

) git tag -a "build1109" -m "July.15 빌드 태그".

태깅한 버전으로 이동하려면, 브렌치 이동과 마찬가지로 checkout을 사용하면 된다.

git checkout "태그명"

만약 그 태그 버전으로 부터 무엇인가를 작업하려면, 해당 태그로 이동한 후에, git branch를 이용하여, 그 버전에서 부터 branch를 따서 작업을 하거나 clone등을 해서 작업을 하는 것이 좋다. 그리고, 태그를 다른 사람과 공유하려면, 브렌치나 코드와 마찬가지로, 태그를 서버로 push해줘야 한다.

git push origin "태그명"

9)   Rebase

git rebase git만의 고유 기능이다. merge와 유사한 기능이지만, 코드 변경 History를 조금더 깔끔하게 정리해주는 기능이라고 생각하면 된다.

다음과 같은 브렌치가 있다고 하자. V3에서 브렌치를 생성하여 V4를 만들어내었고, master에서는 commit을 진행하여 V5로 진행되었다고 하자. 이 상태에서 V4의 변경 내용을 V5로 합치고자 한다.



일반적인 경우에는 merge를 한다. 아래와 같이 merge를 하는 경우에는 V6 버전이 새로 생기고, V4 branch와 내용과 history가 모두 유지 된다.



반면 rebase 명령을 수행할 경우, merge와 마찬가지로, 코드를 master branch로 합치지만, 기존의 V4 branch는 없어지고, V4에 작업된 내용 (변경 History)는 마치 master branch의 변경 history인 것 처럼 하나로 합쳐진다.



유용한 git 관련 도구들

git의 경우, 요즘 널리 사용되는 만큼 지원되는 도구들도 많다. 여기서 몇몇 유용한 git 지원 도구들에 대해서 살펴보도록 하자.

1)   git-gui & gitk

이 두가지 툴을 gui 툴로, git를 설치하면 기본적으로 설치 된다. git-gui git에서 commit을 하는 것을 도와주고, gitk git 저장소를 gui 기반으로 browsing할 수 있게 해준다.  

2)   gerrit

gerrit는 오픈소스 코드리뷰 도구로 (https://code.google.com/p/gerrit/) 에서 다운로드 바을 수 있으며, git를 사용시, 웹 기반으로 코드 리뷰를 가능하도록 해준다.

master branch dev branch를 갖는 상태에서, dev branch에서 개발을 한 후, dev branch push를 하면, jenkins등과 같은 자동 빌드 도구에서 컴파일 및 테스트를 수행한 후에, gerrit을 통해서 코드 리뷰 요청을 생성하고, 코드 리뷰어가 리뷰를 끝내면, 코드를 master push하는 시나리오를 만들 수 있다. UI는 좀 떨어지긴 하지만, 저렴한 비용으로 코드리뷰 도구를 사용할 수 있다.



3)   gitLab

git lab 역시 오픈 소스이다. 코드 리뷰뿐만 아니라, git 저장소에 대한 browsing, 프로젝트 관리, 이슈 관리등 다양한 기능을 제공한다.



지금까지 git에 대해서 가장 기본적인 기능만을 소개하였다. 이외에도 상당히 많은 기능이 있기 때문에, git의 경우에는 꼭 별도의 서적을 참고해 보기를 권장한다.
Pragmatic Version Control Using Git, 저자 Travis Swicegood , ISBN-10: 1934356158
※ 참고할만한 글

Ÿ   git에 대해서 간략하게 설명해놓은 문서http://rogerdudler.github.io/git-guide/index.ko.html

Ÿ   git에 대해서 설치 없이 간단하게 배울 수 있는 온라인 튜토리얼
http://pcottle.github.io/learnGitBranching/

사실 git를 사용해보면,그 속도도 빠르고 branch 생성이나 merge도 쉬워서 참 유연한 툴이구나 생각하게 된다. 반대로 생각해보면 유연하다는 것은 사용할 수 있는 용도가 많다는 것이고, 잘 모르면 어떤 방향으로 사용해야 할 지 정하기가 매우 애매하다는 이야기가 된다. svn과 같은 경우는 일반적으로 사용하는 branch 전략이 정해져 있어서 learning curve도 낮아서 쉽게 사용할 수 있지만, svn과 같은 centralized VCS에 익숙해져 있는 사람은 git를 접하면 개념을 잡는데 한참 시간이 소요되다가, 결국은 centralized VCS와 같은 형태로 사용하는 경우가 종종 있다.

 git가 되었건, svn이 되었건 간에, 툴의 사용법 보다는 소스코드의 버전 관리의 본질을 제대로 이해하고, 팀과 프로젝트 성격과 회사내의 릴리즈 정책에 맞는 VCS를 선택하고 그에 맞는 브렌치 전략을 제대로 수립하고 적용해 나가는 것이 더욱 더 중요하다.  특히 조직의 규모가 커지면 커질 수 록, 그리고 릴리즈하는 버전의 다양성이 많을 수 록, 효과적인 브렌치 구조의 정의는 개발 환경의 효율성에 아주 지대한 영향을 미치게 된다.

또한 이 글을 쓰는 내내 머릿속에 멤도는 생각은 수년전만 해도 개발자가 사실 이러한 VCS branch 전략에 대해서 크게 신경 쓸 필요가 없었다. 일반적인 팀 단위 프로젝트에 들어가서 Check out, update, commit, merge 정도만 잘하면 되었으니까는, 그러나 앞서서 git에서 살펴보았듯이. 이미 소스 코드 관리 전략은 오픈소스등의 영향을 많이 받아서 분산형이 대세다. 분산을 하다보니, 상대적으로 다른 개발자나 개발팀의 간섭을 덜 받으면서 별도의 브렌치에서 작업을 해서 코드 작업을 할 수 있다는 장점도 있지만, 그만큼 개발자가 이제는 코드 관리에 대한 깊숙한 이해를 가져야 한다는 것이다

'ALM > SCM/VCS' 카테고리의 다른 글

github 연동 방식 메모  (0) 2014.01.12
git 사용법과 소스 관리  (6) 2013.07.28
Git branch reference  (0) 2013.06.25
git 기본 command  (0) 2013.06.24
VCS 브렌치 관리 전략  (0) 2013.05.27
git 노트  (0) 2013.05.27
본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

  1. 악당잰 2013.10.31 11:25  댓글주소  수정/삭제  댓글쓰기

    좋은글 감사합니다. 요즘 Git가 많이 쓰임에도 불구하고 실제 프로젝트에서 사용할 기회가 없었거든요. 빨리 활용해 보고 싶네요.

  2. 수여리 2013.11.26 14:10  댓글주소  수정/삭제  댓글쓰기

    감사합니다.
    자세한건 책을 봐야겠지만 이 글 덕분에 git에 대한 기본적인 이해가 되었습니다.

  3. Frank Kim 2014.03.28 11:04  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 고맙습니다.
    git 을 이용해 볼려고 하는데, 한 수 배우고 갑니다.
    by http://linuxtip.net

  4. 유민선 2015.01.02 10:14 신고  댓글주소  수정/삭제  댓글쓰기

    잘보고 갑니다.ㅎㅎ글 내용 참조 할게요 ㅎㅎ

  5. 이승민 2015.08.05 02:37  댓글주소  수정/삭제  댓글쓰기

    잘요약되있어서 이해가 잘되네요~!

  6. tfde467h 2018.02.19 15:50 신고  댓글주소  수정/삭제  댓글쓰기

    좋은 글 감사합니다.

Git branch reference

ALM/SCM/VCS | 2013.06.25 00:19 | Posted by 조대협


참고 : http://nvie.com/posts/a-successful-git-branching-model/

이 모델은 서비스 개발에 적절한 모델. (여러 버전을 동시에 릴리즈해서 유지 보수하는 솔루션 모델에는 맞지 않음)


master

master는 외부 공개용으로, 항상 깔끔한 형상을 유지하며, 주요 milestone마다 tagging이 되어 있음. 기존의 release branch를 tagging으로 대체함

release 

여기서 release branch는 release 후에 없애 버리는 개념을 갖는데, release시 필요한 작업 공간으로 사용되며, minor fix 나 configuration 수정등을 위한 협업 장소로 사용됨.

Fix된 내용들은 모두 release시 develop와 master로 merge됨.

develop

develop는 주요 개발 branch로, 여기서 개발이 된 후, 주요 milestone마다 master를 통해서 외부 공개됨.

feature

feature는 각 기능 구현을 위한 branch로 기능 구현이 끝나면, develop branch로 merge

hotfix

hotfix는 주요 release 이외에, 긴급 수정이 필요할 때, master에서 따서 사용하며, fix 내용은 바로 master와 develop에 merge된다.



'ALM > SCM/VCS' 카테고리의 다른 글

github 연동 방식 메모  (0) 2014.01.12
git 사용법과 소스 관리  (6) 2013.07.28
Git branch reference  (0) 2013.06.25
git 기본 command  (0) 2013.06.24
VCS 브렌치 관리 전략  (0) 2013.05.27
git 노트  (0) 2013.05.27
본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

git 기본 command

ALM/SCM/VCS | 2013.06.24 23:23 | Posted by 조대협


1. git 기본 사용법

$ echo "test materials" > index.html

$


repository 생성

$ git init

Initialized empty Git repository in c:/dev/git/.git/

$ echo "This is test materials" > init.html

$ echo "This is test materials" > index.html

$ git add index.html

warning: LF will be replaced by CRLF in index.html.

The file will have its original line endings in your working directory.

$ git status

# On branch master

#

# Initial commit

#

# Changes to be committed:

#   (use "git rm --cached <file>..." to unstage)

#

#       new file:   index.html

#

# Untracked files:

#   (use "git add <file>..." to include in what will be committed)

#

#       init.html

$ git commit -m "Initial contents" --author="Terry <bwcho75@gmail.com>"

[master (root-commit) eb86eb0] Initial contents

 Author: Terry <bwcho75@gmail.com>

warning: LF will be replaced by CRLF in index.html.

The file will have its original line endings in your working directory.

 1 file changed, 1 insertion(+)

 create mode 100644 index.html

 

수정 하기

$ echo "append" >> index.html

$ git add index.html

$ git commit -m "append"


commit history 확인

$git log master



2.태깅

$git tag -a 0.2 -m "v0.2 tagging"


태그 버전들 확인하기

$git tag


각 태그 버전으로 이동하기

$git reset --hard <태그명>


3. 브렌치


생성

$git branch "브렌치이름"

브렌치 목록 보기

$git branch 

- 현재 사용중인 branch는 *표로 보임


브렌치 전환하기

$git checkout "브렌치이름"

메인 master로 전환하기

$git checkout "master"


merge 하기 (현재 브렌치에, 브렌치명의 파일들을 합치기)

$git merge "브렌치명"


tag와 branch의 차이

- tag는 그 순간의 스냅샷을 보관하기 위함

- branch는 그 순간부터 붙여서 계속 해서 개발해나가기 위함





'ALM > SCM/VCS' 카테고리의 다른 글

github 연동 방식 메모  (0) 2014.01.12
git 사용법과 소스 관리  (6) 2013.07.28
Git branch reference  (0) 2013.06.25
git 기본 command  (0) 2013.06.24
VCS 브렌치 관리 전략  (0) 2013.05.27
git 노트  (0) 2013.05.27
본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

개발 환경(dev,stage,qa,production)

ALM/배포(Deployment) | 2013.06.11 00:13 | Posted by 조대협

서버 개발을 가정하고, 먼저, 개발 및 운영에 사용할 서버를 어떻게 배치 해야할지를 살펴보자

일반적인 서버 개발환겨은 아래와 같이 local,dev,integration,qa,staging 그리고 production 환경을로 나뉘어 진다. 각자의 개발 과정에 따라, 각자의 역할과 목적이 다르고, 그에 따라서 시스템의 크기도 다르다.



꼭 모든 환경을 갖출 필요가 없으며, 프로젝트 환경에 따라서 각 환경을 합치거나 생략해도 된다.

그러면 각 환경에 대해서 살펴 보도록 하자.

환경

설명

local

로컬 개발 환경

먼저 개발을 하려면, 각자 개발자 PC에 개발 및 테스트 환경이 셋업 되어 있어야 한다. 각 개발자마다, 설치된 서버 환경을 local 환경이라고 한다. (. PC MySQL등의 DB Tomcat등의 제품을 설치하고, Eclipse와 같은 개발툴과, 컴파일러 등이 설치되어 있는 환경)

local 환경을 구축할시에 가장 주의해야 할점은 모든 개발자가 같은 개발 환경을 사용해야 한다는 것이다. 실제로 많이 일어나는 문제인데, 다른 version JVM를 사용하거나, 다른 버전의 Tomcat을 사용하거나 Lang (문자 local 설정)을 서로 다르게 해서, 정작 코드를 합칠때, local에서 잘 작동했던 코드가 작동하지 않는 경우가 많다.

개발 환경을 표준화 하는 방법은 여러 방법이 있지만, 전체 개발 환경 (JDK, Eclipse, 라이브러리) zip 파일 형태로 묶어서 사용하는 방법이 가장 일반적이다. 또는 뒤에서도 설명하겠지만, maven을 사용할 경우, 개발에 사용되는 JDK,라이브러리 버전등을 지정할 수 있기 때문에 개발환경 차이에서 오는 문제점 상당 부분을 해소할 수 있다.

dev
서버 개발 환경

개발 환경은 각 개별 개발자들이, 만든 코드를 합쳐서 서버 환경에서 테스트해볼 수 있는 환경이다. 소스코드를 형상관리 시스템에 commit하면, 코드는 이 dev 환경에 자동으로 배포되고, 이 환경에서 테스트가 된다.

기능 개발을 위주로 하기 때문에, 서버의 환경은 production 보다 훨씬 작다. 예를 들어 production이 클러스터링 환경으로 수개의 서버로 구성된다면, 개발 환경은 한 두 개의 서버로 기능 구현이 가능한 정도로 구축하는 것이 일반적이다.

Integration

통합 개발 환경

통합 개발 환경은, 여러개의 컴포넌트를 동시 개발하는 프로젝트가 있고, 각 컴포넌트가 다른컴포넌트에 대해서 dependecy를 가지고 있을때, 컴포넌트를 통합 및 테스트 하는 환경으로 사용한다.

예를 들어 단말과 서버를 같이 개발하는 환경의 경우 이 integration 환경에서 통합을 한다.

dev 환경과 마찬가지고, 최소한의 set으로 구성하되, dev 환경에서 release가 되면 주기적으로 deploy 한다.

qa

테스팅 환경

테스트 환경은 QA 엔지니어에 의해서 사용되는 환경으로, short release 주기에 따라서, 개발환경에서 QA 환경으로 배포 되고, 여기서 기능 및 비기능 (Load Test)등을 QA 엔지니어가 수행한다.

비 기능 테스트를 수행할 시에는, production과 거의 유사한 환경을 만들어 놓고, 테스트를 수행한다. (경우에 따라서는 비기능 테스트는 release전에, production 환경에서 직접 수행하는 경우도 있다. 이런 경우는 release cycle이 매우 긴 경우 주로 사용하는데, 기업의 내부 IT 시스템 만들어서 몇 년씩 사용 하는 경우와 같은 때 이런 방식을 이용한다

staging
스테이징 환경

운영 환경과 거의 동일한 환경을 만들어 놓고, 운영환경으로 이전하기 전에, 여러 가지 비 기능적인 부분 (Security, 성능, 장애등)을 검증하는 환경이다.

production
운영 환경

실제 서비스를 위한 운영 환경

 

대부분 개발환경은 별도로 운영하는 것이 일반적이고, 상황에 따라서 integration, qa, stating 환경은 요구 사항에 따라서 합치거나 별도 운영한다. 환경이 많아지면 조금 더 다양한 형태의 검증과 각 stakeholder (테스터, 개발자, 사용자 등)별로 테스트가 쉽지만 반대로, 각 환경을 유지 하는데, 필요한 서버들과, 운영 인력이 많이 소요되는 단점이 있다.

그래서 요즘과 같이 가상화 환경을 사용하는 경우에는  이미지를 만들어놨다가, 실제 테스트나 사용을 할 경우에만 가상 서버에 환경을 deploy해서 사용하고, 사용이 끝나면 다시 이미지를 스토리지에 저장해 놓는 전략을 많이 사용한다.

본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

  1. 최정한 2019.03.14 01:31  댓글주소  수정/삭제  댓글쓰기

    잘 보고 갑니다.

VCS 브렌치 관리 전략

ALM/SCM/VCS | 2013.05.27 02:06 | Posted by 조대협

http://nvie.com/posts/a-successful-git-branching-model/


복잡하긴 하지만, 대략 흐름은 맞는듯.


'ALM > SCM/VCS' 카테고리의 다른 글

github 연동 방식 메모  (0) 2014.01.12
git 사용법과 소스 관리  (6) 2013.07.28
Git branch reference  (0) 2013.06.25
git 기본 command  (0) 2013.06.24
VCS 브렌치 관리 전략  (0) 2013.05.27
git 노트  (0) 2013.05.27
본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

git 노트

ALM/SCM/VCS | 2013.05.27 00:52 | Posted by 조대협
Initializing a Repository in an Existing Directory

If you’re starting to track an existing project in Git, you need to go to the project’s directory and type

$ git init

This creates a new subdirectory named .git that contains all of your necessary repository files — a Git repository skeleton. At this point, nothing in your project is tracked yet. (See Chapter 9 for more information about exactly what files are contained in the .git directory you just created.)

If you want to start version-controlling existing files (as opposed to an empty directory), you should probably begin tracking those files and do an initial commit. You can accomplish that with a few git addcommands that specify the files you want to track, followed by a commit:

$ git add *.c
$ git add README
$ git commit -m 'initial project version'

We’ll go over what these commands do in just a minute. At this point, you have a Git repository with tracked files and an initial commit.




git clone은 무엇일까??

Working directory
Index(Staging)
Head 의 개념은 무엇일까?

--------------

VCS (Version Control System) or SCM

중앙 집중형 (CVS,Subversion) - 서버가 문제가 생기면 협업이 불가능함
분산형 (Git,Mecurial, Bazzar) - 각 클라이언트가 각각 저장소를 가지고 있으며, 서버가 문제가 생겨도 지속 적인 작업이 가능하고, 서버가 날라가도, 복구가 가능하다. 또한 중앙 집중식 이외에도, Commit에 대한 다양한 Workflow 구현이 가능하다.

특징
git는 delta를 저장하는 것이 아니라, 순간 snapshot을 저장한다.
파일을 파일명이 아니라 SHA-1 해쉬 값으로 저장함. (git 만을 통해서만 접근 가능)

파일의 상태
modified - 수정되었으나, stage나 commit되지 않은 상태 (working directory 안에 존재)
stage - 수정하였으며 곧 commit할 상태라고 표시 (staging area라는 별도 영역에 존재함)
add라는 명령어가 다른 모든 버전 관리 시스템에서는 없던 파일을 추가하는 기능이지만, git에서는 stage에 파일을 추가(add)하는 명령이다 보니, 조금 헷갈릴 수 있다.


- 코드리뷰 등에 유용하게 사용될 수 있음.
- 실제 메인에는 저장되지 않았지만, 변경 내용은 저장이 되서, 다른 사람들이 볼 수 있는 상태가 됨. 
commited - 서버에 저장된 상태 (git 디렉토리에 존재)


도구
git flow - 개발에 사용되는 몇개의 브랜치만 관리할 수 있게 해줌
master branch: 최종 릴리즈된 소스 코드만 관리
 develop : 개발중인 코드
 feature : develop branch로 부터 특정한 새로운 기능을 개발할때만 사용, 완료후 develop로 merge
 release
 hotfix branch : hot fix용 etc


gerrit - git 기반의 코드 리뷰 도구.
(이전 버전과 코드 라인비교, 라인단위 코멘트, 코드 승인 프로세스를 지원함)


git 파일들을 ${repository}/.git안에 저장되어 있으며, 각 파일들은 SHA-1 으로 파일명이 encrypt되어 있어 있어서, 그냥은 볼 수 없음


'ALM > SCM/VCS' 카테고리의 다른 글

github 연동 방식 메모  (0) 2014.01.12
git 사용법과 소스 관리  (6) 2013.07.28
Git branch reference  (0) 2013.06.25
git 기본 command  (0) 2013.06.24
VCS 브렌치 관리 전략  (0) 2013.05.27
git 노트  (0) 2013.05.27
본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

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 파일들을 대상 시스템으로 자동으로 복사 실행 하는 부분에 대해서는 뒤에서 다시 살펴 보도록 하자

본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

  1. jake 2018.06.27 13:39  댓글주소  수정/삭제  댓글쓰기

    안녕하세요 혹시 ${environment} 값을 java 땅에서 사용할수있나요?

Maven을 이용한 Jersey + Spring + MyBatis 기반의 REST 애플리케이션 개발


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

빌드 스크립트 설정

개발 환경에서 가장 중요한 빌드에서 부터 알아보자, 우리가 정의하는 빌드는 다음과 같다.

"빌드란, 실행 환경에 맞춰서 소스 코드를 실행 가능한 형태의 바이너리로 변경 및 패키징 하는  일련의 과정을 정의한다."

단순하게 소스코드를 바이너리로 바꾸는 컴파일이 될 수 도 있고, 실행에 필요한 각종 리소스 (이미지, 각종 설정 파일등)을 실행 환경(서버 주소등)에 맞춰서 같이 패키징 하는 과정을 이야기 한다.

이 빌드 여러개의 연속된 작업을 포함하기 때문에, 보통 스크립트를 기반으로 수행이 되는데, C/C++의 경우에는 make 기반의 빌드 스크립트가, 자바의 경우에는 ant maven이 널리 사용된다.

 

ant vs maven

자바 기반에서 현재 가장 인기 있는 빌드 스크립트 툴은 ant maven이다. 요즘은 상당 부분이 maven으로 넘어갔다. 그렇다면 이 각각 빌드 스크립트 툴의 장점은 무엇일까?

 

유연성과 관리

ant의 경우에는 자유도가 상당히 높다. 파일을 복사하거나, 쉘 명령을 실행할 수 도 있다. 스크립트내에서 빌드, 패키징 은 물론이고 배포,테스트, 미들웨어에 대한 기동이나 정지까지 모든 것이 가능하다. 자유도가 높다는 이야기는 반대로 이야기 하면 표준화가 어렵다는 이야기가 된다.

잘 관리 하지 않으면 프로젝트 마다 또는 팀마다 빌드 스크립트가 제각각이다. 표준화가 되지 않은 빌드 스크립트는 새롭게 합류하는 개발자들에게 별도의 learning curve를 요구하게 되고, 실수를 유발한다.

또한 복잡한 형태의 빌드 프로세스를 요구 하는 개발의 경우에는 빌드 스크립트 자체를 만드는 것 자체가 복잡한 일이 된다.

 

maven은 이런 단점을 보완해서 개발되었다.

maven은 템플릿 기반으로 빌드 스크립트를 구성한다. 템플릿 기반이란, 특정 애플리케이션 타입에 대해서, 디렉토리 구조, 빌드 프로세스등이 모두 정해져있다. 그래서 애플리케이션 타입에 따라서 템플릿만 골라서 사용하게 되면 누구나 같은 디렉토리 구조에서 같은 빌드 프로세스에서 개발하게 된다. 그래서 learning curve가 상대적으로 낮고, 누구나 표준화된 환경에서 빌드가 가능하다.

반대로, 템플릿 이외의 기능에 대해서는 유연성이 떨어져서, 마음대로 무엇인가를 추가 하는 것이 어렵다. (예를 들어서 파일을 특정 클라우드에 복사한다던지). 물론 maven도 플러그인이라는 기능을 통해서 템플릿의 기능을 확장할 수 있는 기능을 제공하지만, 이 플러그인이라는 것 자체의 개발이 쉽지가 않기 때문에 템플릿의 기능을 벗어나는 순간 learning curve가 급속하게 올라간다. 다행이도 근래에는 maven에서 사용할 수 있는 플러그인들이 많이 있기 때문에, 이런 문제들은 상대적으로 줄어들고 있다.

 

의존성 관리

다음으로 라이브러리에 대한 의존성에 대해서 고민해볼 필요가 있다.

ant의 경우에는 소스코드와 라이브러리 그리고 기타 의존된 리소스 파일 (설정 파일, 스크립트, 이미지)등이 디렉토리에 있는 것을 가정하고 빌드를 진행한다. 전적으로 이러한 파일들을 챙기는 것은 개발자와 빌드 메니져의 역할인데, 이러다 보니 특히 라이브러리 관련해서 문제가 발생한다.

예를 들어 원 소스는 spring 3.0 라이브러리를 바탕으로 개발이 되었는데, 어떤 개발자는 spring 2.0을 사용해서 컴파일하고 어떤 개발자는 spring 3.1을 사용해서 컴파일 하는, 이런 일들이 발생할 수 있다는 것이다. (실제로 종종 발생하는 일)

maven의 경우 재미있는 것은 이렇게 컴파일을 하는 데 필요한 라이브러리에 대한 의존성을 정의하고, 정확한 버전을 정의하면, 컴파일 타임에 원격에 있는 repository로 부터, 명시된 버전의 라이브러리를 다운 받아서 컴파일과 패키징을 진행하기 때문에, 라이브러리의 버전 불일치가 발생될 염려가 없다. 또한 오픈소스등에서 작성한 well-known 라이브러리가 아니더라도, 자체적으로 repository 시스템을 구축하여, 팀내에서 개발한 라이브러리를 배포해놓고 사용할 수 있다. 이런 시나리오는 여러개의 모듈을 동시에 개발하는 프로젝트 팀의 경우, 모듈간의 의존 관계에서 오는 문제를 해결할 수 있는 좋은 방안이 된다.

 

근래에는 이런 장점 때문에, 유연성이 다소 적더라도 maven이 많이 사용되는 추세이다.

이제 부터 간단하게 maven 기반의 빌드 방법에 대해서 설명해보도록 한다.

여기서 소개하는 빌드 스크립트는 web application 기반의 빌드 스크립트로, 다음과 같은 시나리오를 구성할것이다.

 

-       Jersey 기반의 JSON/HTTP REST API 지원, Spring DI 기반으로 비지니스 로직 구현, MyBatis를 이용한 데이타 베이스 접근

-       빌드 환경은 개발자 PC local, 개발 환경인 dev, 스테이징 환경 stage,검증 환경인 qa 그리고 실 운영 환경이 production 환경으로 구성된다.

-       빌드 스크립트를 통해서 개발자는 빌드,배포 및 Tomcat상에서 실행 및 테스트를 진행할 수 있어야 한다.

 

maven을 이용한 Jersey + Mybatis + Spring 기반의 개발 환경 구축하기

먼저 maven 이용해서 개발을 하려면 프로젝트를 만들어야 한다. 프로젝트는 특정한 애플리케이션 타입에 맞는 템플릿을 이야기 한다. 디렉토리 구조나 빌드 프로세스들이 미리 정해져 있는 개발을 위한 하나의 비어 있는 틀이다.

 

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false  -DgroupId=spring-tutorial -DartifactId=terry -Dversion=1.0-SNAPSHOT -Dpackage=terry.spring.tutorial.ch1

 

이렇게 하면 하나의 비어 있는 프로젝트가 생성이 된다.

프로젝트가 생성이 되면, 해당 애플리케이션을 개발하는데 필요한 디렉토리 구조나 필요한 라이브러리 들이 자동으로 다운로드 되서 설치 된다. 프로젝트는 java web application 지원하는 war형태의 프로젝트이다.

maven 앞서도 설명하였듯이, 프로젝트를 생성할때, 프로젝트의 타입을 정할 있다. 여기서는 war 기반의 개발을 하기 위한 web-app 형태의 프로젝트를 생성하였는데, 프로젝트 타입은 -DarchetypeArtificatId 지정할 있다. (여기서는 가장 기본적은 maven-archetype-webapp 사용하였다.)

 

그럼 생성된 프로젝트의 모양을 살펴보자. 생성된 프로젝트의 디렉토리 구조는 다음과 같다.

 


pom.xml

ant ant.xml이나 make makefile처럼 build 대한 모든 configuration 지정한다.

 

다음으로 생성된 디렉토리를 살펴보자 src에는 *.java 소스 파일과 webapp (war root)디렉토리에 들어가는 내용들과 각종 설정 파일들이 들어간다. 상세한 내용을 살펴보자.

 

src/main/resource

디렉토리는 각종 설정 파일이 위치하는 곳이다. 디렉토리 안에 있는 파일을 class path 포함된다. war 경우에는 디렉토리에 있는 파일들은 WEB-INF/classes 디렉토리 아래에 그대로 들어간다.

예를 들어 src/main/resources/sqlmap/sqlmapper.xml 파일은 컴파일 후에, war파일내의 WEB-INF/classes/sqlmap/sqlmapper 저장된다.

 

src/main/webapp

Web resource 해당 하는 부분이다. war안에 / 디렉토리에서 부터 들어가는 html 각종 리소스 파일들을 모두 정의하낟.

 

그런데, 정작 보면 java 코드를 넣을 소스 디렉토리가 없다.

src/main/ 디렉토리 밑에 java 디렉토리를 하나 만들자.

아래 화면은 src/main/java 디렉토리를 만들고, terry.restapi.model.ContactVo.java 구현한 디렉토리 구조이다.

 

 

아래 코드는 Contact.java 클래스로, 간단하게 사용자의 이메일,이름과 전화번호를 저장하는 VO 클래스 이다.

package terry.restapi.model;

import javax.xml.bind.annotation.XmlRootElement;

 

@XmlRootElement(name="Contact")

public class ContactVo {

        String email;

        String name;

        String phone;

        public String getEmail() {

               return email;

        }

        public void setEmail(String email) {

               this.email = email;

        }

        public String getName() {

               return name;

        }

        public void setName(String name) {

               this.name = name;

        }

        public String getPhone() {

               return phone;

        }

        public void setPhone(String phone) {

               this.phone = phone;

        }

       

}

 

여기 까지 진행을 했으면, war 파일이 어떻게 만들어지는지 테스트를 해보자

% mvn package 실행하면

${HOME} 디렉토리 아래 /target/terry.war 파일이 생성된 것을 있다.

파일을 풀어보면 앞에서 만든 WEB-INF/classes/terry/restapi/model/Contact.class 패키징 되어 있는 것을 확인할 있다.

 

지금까지 간단하게 maven 프로젝트를 만들고, 소스코드를 넣고, 웹에 관련된 리소스를 정의한후에, 컴파일 war 패키징을 해보았다.

 

maven ant make 처럼 일종의 build target 제공하는데, maven에서는 이를 goal이라고 한다. pom.xml 스크립트에 따라서 다양한 goal 정할 있으나, maven에서 미리 정해져 있는 goal 중요한 goal들은 다음과 같다.

 

mvn compile : 컴파일 수행. (프로젝트내의 java 코드를 컴파일 한다.)

mvn package : jar,war,ear pom.xml에서 정해진 형태로 파일로 패키징. (컴파일을 한후, 프로젝트 내용에 따라서 패키징을 수행한다.)

mvn test : JUnit 테스트 수행.

mvn install : local repository (PC내의 디렉토리)에 패키징된 파일을 저장

mvn deploy  : remote repository (Nexus)에 패키징된 파일 저장

mvn clean : 컴파일 내용 모두 삭제

 

여기서 compile,package,clean 등은 거의 모든 빌드 스크립트에서(ant ) 공통적으로 지원하기 때문에 별도의 설명을 하지 않는다.

install deploy 대해서 살펴보자

 

앞서도 설명했듯이, maven library 대한 dependency 지정하고 스크립트를 수행하면, repository라는 곳에서 해당 라이브러리들을 읽어온다. 그러면 repository 어디일까?

mvn install 컴파일된 패키지들를 local pc 라이브러리 저장소에 배포한다. 다른 프로젝트가 라이브러리를 사용하고자 한다면, local pc 내에서 라이브러리를 찾아서 같이 컴파일 있다. 그러나 local pc에만 배포가 되었기 때문에 다른 사람은 라이브러리를 참조해서 사용할 없다. 그래서 다른 사람이 라이브러리를 참조할 있게 하려면, 네트워크 상의 공용 repository 필요하다. 이러한 공용 repository 라이브러리를 배포하는 명령이 mvn deploy이다.

spring이나 기타 라이브러리등은 각각의 공용 repository 가지고 있고, mvn 역시 이러한 repository list 기반으로 해서 라이브러리를 로딩하는데, 우리 회사나 팀에서만 사용할 있는 repository 별도로 구축하려면 어떻게 해야 할까? nexus라는 제품을 설치하면, 사내에 전용 repository 서버를 구축할 있다. (http://www.sonatype.org/nexus/)

 

maven 프로젝트 생성, 디렉토리 구조의 이해 그리고 maven 통한 컴파일 패키징에 대한 설명이 끝났다. 그러면 이제 부터, Jersey + Spring + Mybatis 개발하기 위한 설정을 해보자, 먼저 pom.xml 위의 세가지 프레임웍을 사용하기 위해서 라이브러리를 정의해야 한다.

라이브러리 정의는 <dependencies>엘리먼트 아래에 라이브러리 <dependency> 라는 엘리먼트로 정의한다.

 

<dependencies>

    <!--  jersey dependency -->

        <dependency>

            <groupId>com.sun.jersey</groupId>

            <artifactId>jersey-server</artifactId>

            <version>1.17</version>

        </dependency>

: 아래 생략

 

위의 3가지 프레임웍을 사용하기 위해서 필요한 dependency 다음과 같다.

정확하게 여기서는 JSON/REST 이용하기 위해서 Jersey 사용하고, Spring 3.1 에서 Dependency Injection만을 이용할것이며, MyBatis MySQL 사용을 위해서 MySQL JDBC Driver 사용할것이다.

아래는 지면 관계상, dependency 테이블로 정리해놨다. 글의 뒷부분의 pom.xml 전문을 따로 첨부했으니, 참고하기 바란다.

 

프레임웍 이름

groupId

artifactId

version

Jersey

com.sun.jersey

jersey-server

1.17

com.sun.jersey

jersey-servlet

1.17

com.sun.jersey

jersey-json

1.17

Spring

org.springframework

spring-core

3.1.1.RELEASE

org.springframework

spring-context

3.1.1.RELEASE

org.springframework

spring-beans

3.1.1.RELEASE

org.springframework

spring-web

3.1.1.RELEASE

org.springframework

spring-webmvc

3.1.1.RELEASE

Spring + Jersey 연결

com.sun.jersey.contribs

jersey-spring

1.17

Spring + Mybatis 연결

org.mybatis

mybatis-spring

1.0.1

MySQL JDBC

mysql

mysql-connector-java

5.1.24

 

여기서 spring+Jersey 연결에 사용되는 jsersy-spring artifact 잠시 살펴볼 필요가 있다. jersey-spring artifact 자체적으로 spring 프레임웍을 포함하고 있기 때문에, 우리가 정의한  Spring framework 중복 가능성이 있다. 그래서, jersey-spring dependency 의해서 spring framework 중복적으로 가지고 오지 않도록 해당 모듈들을 다음과 같이 exclude(제외)하도록 선언한다.

<!--  jersey + spring depdendency  -->

     <dependency>

                       <groupId>com.sun.jersey.contribs</groupId>

                       <artifactId>jersey-spring</artifactId>

                       <version>1.17</version>

                       <exclusions>

                              <exclusion>

                                      <groupId>org.springframework</groupId>

                                      <artifactId>spring</artifactId>

                              </exclusion>

                               <exclusion>

                                      <groupId>org.springframework</groupId>

                                      <artifactId>spring-core</artifactId>

                              </exclusion>

                              <exclusion>

                                      <groupId>org.springframework</groupId>

                                      <artifactId>spring-web</artifactId>

                              </exclusion>

                              <exclusion>

                                      <groupId>org.springframework</groupId>

                                      <artifactId>spring-beans</artifactId>

                              </exclusion>

                              <exclusion>

                                      <groupId>org.springframework</groupId>

                                      <artifactId>spring-context</artifactId>

                              </exclusion>

                       </exclusions>

               </dependency>

자아. 이제 빌드 스크립트는 Jersey + Mybatis + Spring DI 이용한 개발 준비가 되었다. 그러면 실제 코딩에 들어가 보자

java/terry/restapi 아래, MVC 모델에 맞춰서 service,dao,model 디렉토리를 만들고 아래와 같이 클래스들을 구현한다.

 

java/terry/restapi/dao/ContactDao.java

package terry.restapi.dao;

 

import java.util.HashMap;

 

import terry.restapi.model.ContactVo;

 

public interface ContactDao {

       

        public void create(ContactVo contact);

        public ContactVo get(String email);

        public void delete(String email);

        public void update(String email,ContactVo contact);

}

 

java/terry/restapi/dao/ContactImpl.java Mybatis 이용한 contact 테이블에 대한 CRUD 구현한다.

package terry.restapi.dao;

 

import org.mybatis.spring.support.SqlSessionDaoSupport;

 

import terry.restapi.model.ContactVo;

 

public class ContactDaoImpl extends SqlSessionDaoSupport implements ContactDao {

 

        public void create(ContactVo contact) {

               // TODO Auto-generated method stub

 

        }

 

        public ContactVo get(String email) {

               // TODO Auto-generated method stub

               ContactVo contact = (ContactVo)getSqlSession().selectOne("contactdao.getUserByEmail", email);

               return contact;

        }

 

        public void delete(String email) {

               // TODO Auto-generated method stub

 

        }

 

        public void update(String email, ContactVo contact) {

               // TODO Auto-generated method stub

 

        }

 

}

 

java/terry/restapi/model/ContactVo.java 앞에서 이미 구현했기 때문에, 앞의 코드 참고

 

다음은 Jersey 이용한 REST API 구현이다. 아래 코드는 편의상 create,select,update 구현하였다.

package terry.restapi.service;

 

import javax.ws.rs.Consumes;

import javax.ws.rs.GET;

import javax.ws.rs.POST;

import javax.ws.rs.PUT;

import javax.ws.rs.Path;

import javax.ws.rs.PathParam;

import javax.ws.rs.Produces;

import javax.ws.rs.core.MediaType;

import javax.ws.rs.core.Response;

 

import terry.restapi.dao.ContactDao;

import terry.restapi.model.ContactVo;

 

@Path("/contact")

public class ContactService {

        static ContactDao dao = null;

        public void setContactDao(ContactDao dao){this.dao = dao;}

        public ContactService(){

               //if(dao == null)      setContactDao(new ContactDao());

        }

       

        /**

         * Create Contact Record

         * @param contact

         * @return

         */

        @POST

        @Consumes(MediaType.APPLICATION_JSON)

        public Response create(ContactVo contact){

               dao.create(contact);

               return Response.status(200).entity(contact).build();

 

        }

        /**

         * Query Contact record by email id

         * @param email

         * @return

         */

        @GET

        @Produces(MediaType.APPLICATION_JSON)

        @Path("{email}")

        public ContactVo get(@PathParam("email") String email){

               return dao.get(email);

        }

        /**

         * Upadte Contact Record by email

         * @param email

         * @param contact

         * @return

         */

        @PUT

        @Path("{email}")

        @Consumes(MediaType.APPLICATION_JSON)

        @Produces(MediaType.APPLICATION_JSON)

        public Response  update(@PathParam("email") String email, ContactVo contact){

               dao.update(email, contact);

               return Response.status(200).entity(contact).build();

        }

}

 

 

자아 코드 구현이 끝났다.

이제 코드를 실행하기 위해서는 다음과 같은 추가 작업이 필요하다.

/webapp/WEB-INF/config/spring-context.xml Spring Bean 정의하기 위한 spring context 파일 작성

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xmlns:context="http://www.springframework.org/schema/context"

        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

 

        <!--  load configuration file -->

         <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

          <property name="locations">

           <value>/WEB-INF/config/config.properties</value>

          </property>

         </bean>

         

        <!--  create rest service object and inject dao -->

        <bean class="terry.restapi.service.ContactService" id="contactService">

               <property name="contactDao" ref="contactdao" />

        </bean>

        <!-- declare dao object  -->

        <bean class="terry.restapi.dao.ContactDaoImpl" id="contactdao">

               <property name="sqlSessionFactory" ref="sqlSessionFactory" />

        </bean>

       

        <!--

               mybatis configuration

               sqlSessionFactory & sqlSessionTemplate are required

         -->

        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

               <property name="dataSource" ref="dataSource" />

               <property name="configLocation" value="/WEB-INF/config/mybatis-config.xml"/>

        </bean>

        <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">

               <constructor-arg ref="sqlSessionFactory" />

        </bean>

       

        <!-- 

               data source configuration

               for testing purpose , it uses simple jdbc datasource

         -->

        <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">

               <property name="driverClass" value="${mybatis.jdbc.driverclass}"/>

               <property name="url" value="${mybatis.jdbc.url}" />

               <property name="username" value="${mybatis.jdbc.username}" />

               <property name="password" value="${mybatis.jdbc.password}" />

        </bean>

</beans>

 

그리고 위의 파일 내용을 보면, /WEB-INF/config/config.properties라는 파일을 읽게 되어 있는데, 여기에는 MYSQL DBMS 접속에 필요한 URL,PORT,사용자 id,passwd등이 들어간다.

/webapp/WEB-INF/config/config.properties

 

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

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

mybatis.jdbc.username=developer

mybatis.jdbc.password=developer

 

/webapp/WEB-INF/config/mybatis-config.xml MyBatis 사용하는 데이타 베이스 연결 정보등의 설정 파일

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "HTTP://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

 <settings>

  <setting name="cacheEnabled" value="false" />

  <setting name="useGeneratedKeys" value="true" />

  <setting name="defaultExecutorType" value="REUSE" />

 </settings>

 

 <mappers>

  <mapper resource="sqlmap/ContactDao_map.xml" />

 </mappers>

</configuration>

 

/webapp /WEB-INF/web.xml 초기에 Spring Context Jersey framework 로딩하기 위한 설정

<!DOCTYPE web-app PUBLIC

 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

 "http://java.sun.com/dtd/web-app_2_3.dtd" >

 

<web-app>

  <display-name>Archetype Created Web Application</display-name>

 

        <!--  load spring context configuration -->

        <context-param>

               <param-name>contextConfigLocation</param-name>

               <param-value>

                       /WEB-INF/config/spring-context.xml

                       <!-- /WEB-INF/config/mybatis-context.xml -->

               </param-value>

        </context-param>

 

        <!--  load listener  -->

        <listener>

               <listener-class>

                       org.springframework.web.context.ContextLoaderListener

               </listener-class>

        </listener>

       

        <!--  configure jersey/JSON servlet -->

        <servlet>

          <servlet-name>Jersey Web Application</servlet-name>

               <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>

                     <init-param>

                              <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>

                              <param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>

                 </init-param>

                 <init-param>

                  <param-name>com.sun.jersey.config.property.packages</param-name>

                  <param-value>terry.restapi</param-value>

                </init-param>

                <init-param>

                              <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>

                              <param-value>true</param-value>

                       </init-param>

                          <load-on-startup>1</load-on-startup>

            </servlet>

       

            <servlet-mapping>

               <servlet-name>Jersey Web Application</servlet-name>

                <url-pattern>/*</url-pattern>

            </servlet-mapping>

</web-app>

 

/resources/sqlmap/ContactDao_map.xml MyBatis 실행하는 SQL 들어 있는 SQL Mapper 파일 작성

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

 

<mapper namespace="contactdao">

        <!-- 

               select user by email id

        -->

        <resultMap type="terry.restapi.model.ContactVo" id="resultmap.terry.restapi.model.ContactVo">

               <id column="email" property="email"/>

               <result column="name" property="name"/>

               <result column="phone" property="phone"/>

        </resultMap>

        <select id="getUserByEmail" parameterType="String" resultMap="resultmap.terry.restapi.model.ContactVo">

               select email,name,phone

               from contact_table

               where email = #{email}

        </select>

</mapper>

 

여기 까지 구현하였으면 디렉토리는 다음과 같은 형태가 된다..


 

이제 mvn package 명령어를 이용하여 war 파일을 만들고, tomcat 배포한후,

MySQL DB 아래와 같은 scheme contact_table 만들면 실행을 위한 준비가 끝난다.

 


수동으로 Tomcat 설치하고 실행하고 배포하면 까다롭기도 하거니와, 개발자 마다 다른 버전이나 다른 설정을 있기 때문에,  이번에는 mvn 스크립트내에서 빌드 과정내에, Tomcat 자동으로 기동 시키고 배포하는 스크립트를 추가해보자.

 

과정은 maven 플러그인이라는 기능을 이용하면 된다.

pom.xml <project> 엘리먼트 아래 다음과 같은 내용을 추가한다.

<build>

    <finalName>restapi</finalName>

         <plugins>

              <!-- 

                tomcat7 plugin

                caution!!. mvn tomcat:xxx will invoke default plugin

                do. mvn tomcat7:xxx

                -->

              <plugin>

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

                  <artifactId>tomcat7-maven-plugin</artifactId>

                  <version>2.1</version>

                          <configuration>

                                 <warSourceDirectory>${basedir}/target/${artifactId}</warSourceDirectory>

                          </configuration>

             </plugin>

         </plugins>

  </build>

위의 내용은 tomcat 7 플러그인을 추가하여, 빌드 후에 tomcat 기동할 있게 해주며, tomcat 실행시 ${basedir} (pom.xml 있는 프로젝트의 루트 디렉토리)아래 /target/terry 디렉토리를 war root 디렉토리로 인식하고 기동하게 한다.

${artifactid} maven 프로젝트 생성시 지정했던 프로젝트의 이름으로, war 빌드 스크립트는 별도의 지정이 없는한, war파일명을 ${artifactid}.war ${basedir}/target/ 아래 생성한다. 또한 컴파일 과정에서 war파일이 풀린 모든 파일들을 위치해놓는다.

 

자아 이제 모든 스크립트가 완성이 되었다.

%mvn package tomcat7:run

실행해보자

package 컴파일 war파일과 war 파일이 풀린 모든 파일들(exploded war) 만들게 하고

tomcat7:run tomcat7 위에서 만든 exploded war파일들을 읽어서 기동하게 한다.

 

이제 로컬 환경에서 배포와 실행이 되었으면 REST API 호출하여 테스트를 해보자. 간단한 테스트를 위해서 Google Chrome Browser Advanced REST Client 사용하였다.

 

 



 

 

본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

  1. 강대권 2013.04.19 06:56  댓글주소  수정/삭제  댓글쓰기

    좋은 아티클 감사합니다.
    실습 진행하면서 보니 dependency 테이블에 mybatis에 관한 내용이 누락되어 있습니다
    정정 부탁 드립니다

  2. 이민영 2013.05.15 21:14  댓글주소  수정/삭제  댓글쓰기

    예제를 보고 작업을 해보았는데..
    mybatis-config.xml 에서
    Error occured processing XML 'Connection timed out: connect' See Error log for more detail 이라는 에러가 뜨는데 원인좀 알수 있을까요 ..? ㅠㅠ

    DocType 선언부에 the file cannot be validated as there was a connection problem 이라는 워닝도 같이 뜨고 있습니다. 혹시 뭐가 잘못된지 아시겠으면 댓글좀 부탁드릴게요

Maven pom properties

ALM/Build Automation (빌드 자동화) | 2013.03.26 16:35 | Posted by 조대협

POM 파일에 등장하는 설정

build : 프로젝트 빌드와 관련한 기본적인 소스 디렉토리 구조, 빌드 산출물 디렉토리 구조, 빌드시 사용할 플러그인 등을 관리

sourceDirectory : 실제 서비스를 담당하는 자바 소스 코드를 관리하는 디렉토리. 기본 값은 src/main/java

testSourceDirectory : 테스트 소스를 관리하기 위한 디렉토리. 배포시 이 디렉토리는 배포 되지 않는다. 기본값은 src/test/java

outputDirectory : soruceDiectory의 소스를 컴파일한 결과물이 위치하는 디렉토리. 기본값은 target/classes

testOutputDirectory : testSourceDirectory의 소스를 컴파일한 결과물이 위치하는 디렉토리. 기본값은 target/test-classes

resources: 서비스에 사용되는 자원을 관리하는 디렉토리. 기본값은 src/main/resources (클래스 패스에 포함됨)

scriptSourceDirectory


mvn help:effective-pom 명령어를 수행하면, 현재 pom 파일에서 default값을 포함한 full pom 파일을 볼 수 있음


본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

테스트 팀의 조직 구조

ALM/Test Automation | 2012.08.21 15:27 | Posted by 조대협

테스트 팀의 조직 구조


Facebook Server Side Architecture Group (SSAG)

http://www.facebook.com/groups/serverside

조대협


테스트를 수행하는 테스트팀의 구조는 테스트 방법론이나 개발 조직, 개발팀의 개발 방법론에 따라 모두 차이가 있다. 여기서는 일반적으로 적용할 수 있는 테스트 조직 구조에 대해서 소개한다.

각각의 역할은 중첩 될 수는 있으나, 생략 될 수 는 없다.




테스트 팀

테스트팀은 테스트를 계획하고 주도적으로 수행하는팀이다. 테스트팀의 일반적인 구조는 다음과 같다.

Test Lead

전체 테스트에 대한 모든 것을 관장한다. 테스트 팀 관리 뿐만 아니라 시스템에 대한 전체 품질 관리를 포함하여 관리한다.

-       Define strategy, methodology : 시스템의 품질 보장을 위한 테스트 전략과 운영할 방법론을 찾고, 조직에 맞게 테스트 방법론을 설계 및 수립한다.

-       Define Process : 시스템 개발 및 테스트 단계에서 운용할 테스트 프로세스를 수립한다. 테스트 프로세스는 테스트 팀만이 사용하는 방법론이 아니라, 개발 및 출시 전과정에서 적용해야 한다. 즉 테스트 팀 뿐만 아니라 개발팀에서도 사용해야 하며, 출시 여부를 결정하는 마케팅팀에서도 이 테스트 프로세스에 영향을 받는다.
수립된 테스트 프로세스는 FIX된 체로 운용되는 것이 아니라 적용 과정을 거쳐서 시스템과 조직의 성격에 맞도록 계속해서 성숙 시켜 나가야 하는데, 이 역할 역시 Test Lead가 담당해야 한다.

-       Manage test project : 테스트팀을 운용 하고 관리한다. 인원을 뽑는 것에서 부터, 일정 관리, 예산 관리와 같이 팀 관리에 해당하는 모든 업무를 수행한다.

-       Communicate with other team : Test Lead의 역할 중 가장 중요한 역할 중 하나가, 다른 팀과의 의사 소통 가교 역할을 하는 것이다. 테스트는 테스트 대상을 가지고 있으며, 제품 출시 여부를 결정 기준이 되며, 테스트 중 발견된 결함을 개발팀에서 수정되어야 하며, 테스트 운영을 위해 필요한 인원에 대한 채용, 테스트에 필요한 툴 구입을 위해서 예산을 확보해야 한다. 이러한 모든 작업은 테스트팀 자체적으로 해결할 수 없고 타팀과의 협업을 통해서만 해결할 수 있기 때문에, 타 팀과의 의사 소통은 매우 중요한 역할이다.

-       Educate team : Test Lead는 테스트 수립된 전략과 프로세스, 방법론에 따라 테스트 팀 및 개발팀이 테스트 작업을 수행할 수 있도록 교육을 진행한다.

-       Define matrix : 시스템에 대한 품질, 테스트 팀의 진척률, 개발 프로세스에 대한 품질등을 체크할 수 있는 정량화된(수치화된) Matrix 표를 정의한다. 여기에 사용될 수 있는 Matrix는 다음과 같다.

1) Defect / KLOC : 소스코드 1000라인당 발견되는 Defect의 수
2) Test Coverage :
전체 테스트 대상에 대해서 테스트가 커버하는 범위로, 전체 소스코드에 대한 테스트가 커버한 소스코드 라인 (라인 커버리지), IF와 같은 분기문에 대한 커버리지를 분석하는 브랜치 커버리지, 전체 기능 대비 테스트한 기능에 대한 기능 커버리지 등이 있다.
3) Defect / Hour :
개발 시간별 발생한 Defect
4) Days test effot / Requirement :
하나의 요구 사항에 대해서 테스트 하는데 소요된 날짜

이러한 Matrix는 전체적인 제품의 품질 현황이나 개선 추이를 그래프로 한눈에 알아볼수 있기 때문에 많은 도움이 되며, 특히 Defect/KLOC, Defect/Hour 등의 척도는 개발 과정에서 발생하는 결함의 수와 이를 해결하는데 필요한 리소스를 산정할 수 있는 지표이기 때문에, 개발과정에서 소요되는 테스트 비용과 인력 계획의 기반 자료로 사용할 수 있다.

Test Designer

테스트 디자이너는 Test Lead에 의해 정의된 전략, 방법론, 프로세스에 따라 테스트 대상 시스템을 분석하고, 상세 테스트 전략을 수립한 후 상세 테스트 케이스를 디자인 한다.

-       Analysis & design test requirement : 테스트 대상 시스템의 기능, 요구 사항과 상세 아키텍쳐를 파악하고, Defect가 발생될 수 있는 부분을 탐색한 후에, Defect의 가능성이 있는 부분을 중심으로, 테스트 전략을 수립한다.

-       Design test case : 테스트 전략을 기반으로, 상세 테스트 케이스를 설계한다.

Test Operator

설계된 테스트 케이스 디자인에 따라서 상세 테스트 케이스를 구현 및 수행 한다.

-       Implement test case : 테스트 디자이너를 기반으로 상세 테스트 케이스를 구현한다.

-       Execute test case : 테스트를 검증하고, 테스트 과정에서 구현된 테스트를 수행한다.

-       Result document : 테스트 수행 과정에서 나온 데이타를 수집하고, 결과를 리포팅 한다.

-       Generate defect report : 테스트 과정에서 결함이 발견된 다면, 결함의 내용과 결함의 발생 절차를 기록한다.

-       Track defect : 향후 결함을 개발팀과 함께 FIX할 때, 개발자와 함께 Defect에 대한 수정에 대해서 의사 소통을 하고, 결함의 해결 과정을 자세하게 리포팅 한다.

-       Test tool set up : 필요에 따라서 테스트에 필요한 툴를 셋업 한다.

Test Environment Manager

일반적인 테스트 조직에서는 존재하지 않는 경우가 많은데, 테스트 환경을 셋업하고 유지하는 역할을 한다.

테스트 환경이란, 테스트 대상이 되는 대상 시스템을 테스트 환경에 배포한 환경과 테스트를 위해 사용되는 부하 발생 툴등의 테스트 툴, 테스트 과정중 대상 시스템을 관측하기 위한 모니터링 시스템 그리고 테스트에서 발견된 결함을 로깅하기 위한 결함 관리 시스템등으로 구성된다.

이런 테스트 환경의 구성은 개발팀 또는 테스트 엔지니어가 겸하는 경우가 많은데, 테스트 환경 구축 자체가 많은 시간이 들기 때문에 이를 구축하는 개발자나 테스트 엔지니어의 리소스가 허비되고 이로 인해서 개발일정이나 테스트 일정에 차질을 가지고 올 수 있기 때문에 명시적으로 테스트 환경을 셋업하고 유지하는 역할을 만들 필요가 있다.

그리고 개통 테스트 단계가 많은 시간이 소요되는 경우가 많은데, 개통 테스트에 많은 시간이 소요되는 주요한 원인은 테스트 환경 셋업과 점검에서 발생하는 경우가 많다. IP가 틀리고, 설정 정보가 잘못되고, 제대로 문서화 되어 있지 않은 등에 사소한 문제인 경우가 대부분인데, 이러한 문제를 사전에 예방하기 위해서

, 구축도 중요하지만 해당 환경을 계속적으로 유지해야 반복적인 회귀 테스트가 가능하다.

-       Set up test environment : 테스트 대상 시스템을 테스트 환경에 배포하고, 테스트에 필요한 테스팅 툴와 모니터링 툴들을 설치 관리한다. 그리고 이 환경에 대한 설정 정보를 문서화 하여 관리한다.

-       Monitor environment during test : 테스트가 진행되는 중에 모니터링 툴를 이용하여 테스트 환경 인프라와 테스트 시스템등에 대한 모니터링을 수행하고, 테스트 진행중 환경에 대한 모니터링 정보를 저장한다.

외부 지원팀

테스트는 대상 시스템에 대한 검증을 수행하는 작업이다. 작게 보면 테스트를 수행하는 조직이 만들지 않은 외부의 것을 검증하는 작업으로, 테스트의 주체는 테스트 대상을 잘 알지 못한다. 그래서 테스트에 필요한 기술적인 지원이 필요하다.

Development Team

테스트 환경에 대한 설정에서 부터 Defect에 대한 해결까지 개발팀에 대한 지원은 필수적이다.

-       Support test environment set up : 테스트 환경에 개발 대상 시스템을 배포한다. 개발 대상 배포 시스템의 설치는 테스트팀이 독립적으로 수행할 수는 없고 테스트 대상 시스템에 대한 지식이 있어야 하기 때문에 개발 당사자인 개발팀의 지원은 필수적이다.

-       Fix defect : 발생된 결함에 대해서 테스트 엔지니어로부터 현상과 관련 자료를 받아서, 결함을 수정하고 이에 대한 확인 작업을 같이 수행한다.

-       Monitoring test : 테스트 과정중에 테스트 대상 시스템에 대한 모니터링을 수행한다.

System Engineer

시스템 엔지니어는 테스트 대상 시스템 이외의 테스트 툴, 모니터링 툴, 하드웨어 인프라나 RDBMS 또는 미들웨어 등에 대한 모니터링 작업을 지원하는 엔지니어이다. 테스트 대상 시스템에 대한 지식은 개발자가 알고 있지만, 미들웨어와 같이 개발에 사용한 기반 시스템등에 대한 지식은 미약한 경우가 많기 때문에, 제품에 대한 전문적인 지식을 가지고 있는 기술 지원 엔지니어의 지원이 있다면 조금더 효율적인 테스트가 가능하다.

-       Monitoring & Tuning : 테스트 대상 시스템 이외의 부분(위에 언급한 부분) 에 대한 제품 모니터링과 튜닝을  지원한다.

'ALM > Test Automation' 카테고리의 다른 글

Selenium WebDriver와 RC 차이  (0) 2013.12.24
Selenium 테스트 메모  (0) 2013.12.24
테스트 팀의 조직 구조  (1) 2012.08.21
JUnit Max  (1) 2009.05.06
Software Testing Proces  (0) 2009.04.09
Cloud 컴퓨팅을 이용한 대용량 Selenium 테스트  (0) 2009.02.18
본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

  1. 2015.04.16 16:46  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

감성적 리더쉽에 대해서

ALM/에세이 | 2012.03.20 00:14 | Posted by 조대협
어렸을때 부터 가장 많이 들어온 말이, "사고 방식이 참 기계적이다." 라는 말을 많이 들어왔다.
FACT를 기반으로 장단점을 분석하고, 그에 대한 백업 플랜까지 계획을 한 후에, 의사 결정을 하는 프로세스가 머릿속에 박혀있다. 그래서 일하기는 편하고, 나름 논리적이라는 평을 많이 들었는데, 얼마전 팀원으로 부터 "조금 더 팀을 감성적으로 관리 하는 것은 어떻냐?" 라는 말을 들었다.
한 2~3주 되었나? 아마 금년에 풀어야할 가장 큰 숙제가 될 것 같다.
96년에 대학교 후배한테 들었던 이야기가 있다.
후배에게.. "세상은 이끌어 가는 리더와, 이끌려 오는 평범한 사람들로 이루어져 있다. 그러니 너도 리더가 되기 위해서 노력해라..." 라고 했더니.. 후배 왈.. "형 저는 이끌어가는 리더보다는 같이 가는 사람이 되고 싶어요.."
이 이야기를 들은지 12년만에 "감성적 리더쉽"이 필요하다는 이야기를 듣게 되었다.
얼마전, 내 블로그를 돌아보다가, 2007년에 쓴 리더쉽에 대한 포스팅을 찾았다.
http://bcho.tistory.com/2

매니저 --> 리더
상황을 있는 그대로 본다 --> 상황의 가능성을 본다
일방 커뮤니케이션 --> 쌍방 커뮤니케이션
과정 계발 --> 인간 계발
일을 올바로 하자 --> 옳은 일을 하자
침체 --> 소생,성장
통치 중시 --> 관계 중시
방향 제시 --> 자유와 창의성 중시
패러다임 추종 --> 패러다임 전환 추구
제한된 시야 --> 넓은 시야
효율 중시 --> 효과 중시
종속되려고 애쓴다. --> 따라 잡으려고 애쓴다.
사실중시 --> 개념 중시
현실 중시 --> 가능성 중시
능력을 위임한다 --> 권한을 부여한다.
주어진 조건하에서 일한다. --> 조건을 계발하려고 노력한다.
구조 중시 --> 융통성 중시
받아들인다. --> 믿고 맡긴다.
안정성 추구 --> 과도기성 혼란은 적극적으로 수용

지금 내가 하고 있는 것은 Management였지, Leadership이 아니었는지도 모른다.
금년에는 Boss에서, Captain으로 진화할 수 있는 한해가 되어야 하지 않을까?


'ALM > 에세이' 카테고리의 다른 글

감성적 리더쉽에 대해서  (0) 2012.03.20
본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요

기존의 개발 프로세스에서는 요구 사항을 받아서 개발하는 형태였는데, 이 요구 사항이 완벽하지 않다는 것은 누가나 알고 있고, 이를 전재로 해서, 변경 가능한 요구 사항을 기반으로 개발하는 프로세스가 애자일 프로세스 이다.
관리 관점 뿐만 아니라, 요구 사항을 수집하는 관점도 변화가 필요한데

요구 사항은 고객이 정해주는 것이 아니라, 스스로 정하는 것이다.
고객에게 요구 사항을 받은 것이 완벽하다고 판단하지 말고, 요구 사항이 부족한 부분은 Develop하고, 완벽하게 만들어 나갈것. 즉 고객이나 다른 사람에게 요구 사항 정의에 대해 의존하지 말고, 커뮤니케이션, 가정, 레퍼런스를 통하여 스스로 요구 사항을 정리할 수 있도록 해야 한다.
완벽하지 않은 요구 사항에 대해서는
1. 고객에게 요구 사항을 커뮤케이션을 통해서 물어볼 것.
2. 고객의 요구 사항이 확실하지 않다면, 유사 레퍼런스를 통해서 요구 사항을 정의하여, 고객과 협의한다.
3. 또는 요구 사항을 가정하되, 가정의 원칙을 고객의 비지니스 밸류(가치)를 우선으로 한다.

요구 사항은 변경이될 수 도, 바뀔 수 도 있다. 그러나 원칙이 되는 것은 고객이 얻고자 하는 비지니스 밸류가 되어야 하며, 개발팀 역시 고객의 비지니스를 이해하고 이를 통해서 요구 사항을 함께 정의해야 한다. 최고의 요구 사항은 "고객의 비지니스 가치이다."

요구 사항의 정의 기법은 Scrum UserStory나 다른 기법에서도 여러 방법으로 표현하고 있지만, 요약해보면
적절한 요구 사항 정의는,
"누가? 왜? 이 행위를 원하는 것이며" - Who & Why
"이 행위의 결과로 얻을 수 있는 비지니스 가치는 무엇인가" - What
그리고, "이 비지니스 가치를 얻기 위해 하는 행위가 무엇인가가 명확하게 정의되어야 한다" - How

본인은 구글 클라우드의 직원이며, 이 블로그에 있는 모든 글은 회사와 관계 없는 개인의 의견임을 알립니다.

댓글을 달아 주세요