CI(Continuous integration)는 다음과 같은 원칙을 장려하는 소프트웨어 개발 프로세스이다.
- 하나의 소스 저장소 유지
- 빌드 자동화
- 자체 테스트 환경 구축
- 모든 사람이 매일 커미트
- 커미트할 때마다 통합 시스템에서 주요 코드를 빌드
- 빌드 과정을 신속하게 유지
- 복제된 프로덕션 환경에서 테스트
- 모든 사람이 최신 실행 파일을 쉽게 얻을 수 있도록 함
- 모든 사람이 진행 과정을 확인할 수 있음
- 전개 자동화
CI의 기본 개념은 Martin Fowler가 널리 대중화하였으며 코드를 트렁크에 병합할 때 각 분기에서 소프트웨어를 계속해서 테스트하여 빌드하는 것을 말한다. 그 결과 코드 베이스의 안정성이 전체적으로 증가한다. 또한, 팀 구성원과의 의사전달이 원활해지고 코드의 전체 품질에 관한 피드백을 얻을 수 있는 기회가 증가한다. 때로는 이러한 주기를 사용하여 코드 적용 범위 보고서나 기타 통계를 생성하는 경우도 있다.
다른 CI 시스템과 마찬가지로 Buildbot을 이용하면 이러한 체크아웃과 빌드, 테스트 주기를 자동화할 수 있다. Buildbot slaves는 일반적으로 Win32, Solaris, Intelx64 등과 같은 다양한 플랫폼에서 실행한다. 빌드가 중단되면, Buildbot이 이메일로 상황을 알려주며 또한, 실행 중인 모든 빌드를 추적한다. 따라서 개발자는 프로세스를 전체적으로 조망할 수 있다. 마지막으로 사람들은 자동화된 주기를 이용하여 특정 시점에서의 소프트웨어 품질과 관련된 지표를 생성하곤 한다. 이 기사의 마지막 부분에서는 지표와 CI 시스템에서 이러한 지표를 실행하는 것이 타당한 이유를 설명한다.
Buildbot과 관련된 기본적인 사항을 살펴보기 전에 먼저, Buildbot의 아키텍처를 확인해 보자. 그림 1에 표시된 바와 같이 본질적으로 빌드 프로세스 맨 위에는 세 개의 계층이 있다. 버전 제어 계층(version control layer)에서는 버전 제어 시스템에서 통지를 받는다. 빌드 계층(build layer)에서는 빌드 마스터와 통신하여 빌드 결과를 리턴한다. 마지막으로 통지 계층(notification layer)은 빌드에 실패하는 경우 이메일이나 IRC 메시지를 전송하도록 구성되거나 시간에 따라 수집된 빌드 결과가 웹 페이지에 표시되도록 구성된다.
그림 1. Buildbot 아키텍처 개요
Buildbot의 기타 핵심 기능 중에는 Python 기반의 Twisted 라이브러리에 의존하여 마스터와 슬레이브 간의 비동기 통신을 처리하는 기능이 있다. 이러한 콜백 기반의 아키텍처에서는 매우 간단하지만 강건한 마스터/슬레이브 피드백 루프가 허용된다. Twisted에 관한 자세한 세부사항은 이 기사의 마지막 부분에 있는 참고자료 섹션을 확인하기 바란다.
Buildbot에 관해 들어본 적이 없는 경우에는 Google에서 조금만 검색하면 크고 작은 오픈 소스 프로젝트와 관련된 마스터와 슬레이브 콜렉션을 많이 확인할 수 있다. 앞서 잠시 언급했던 슬레이브는 문자 그대로 마스터 Buildbot 서버에서 제어하는 슬레이브 시스템을 의미한다. 일반적으로 슬레이브는 각각 다른 플랫폼에서 실행하는 다수의 슬레이브 중 하나이다. 이러한 개념은 Buildbot 서버 분야에서 중요한 개념이다. 예를 들어, 오픈 소스 프로젝트의 메일링 리스트에 가입되어 있으면 누군가가 "Windows 슬레이브 가상 시스템을 자발적으로 제공할 사람 있습니까?"라고 요청하는 메시지를 들을 수도 있다.
Python 언어 프로젝트에서는 대량의 Buildbot 슬레이브 콜렉션을 사용하여 가능한 많은 플랫폼에서 Python의 최신 버전을 계속해서 빌드하고 테스트한다. 그림 2에는 Python 트렁크로 이루어진 이러한 슬레이브 빌드와 테스트를 실행하는 대량의 시스템 콜렉션이 표시되어 있다. 최근에는 가상화가 진전되면서 이제는 개발 커뮤니트 구성원들에게 Buildbot 슬레이브를 호스트하거나 다양한 하드웨어 구성을 에뮬레이트하는 몇 가지 가상 시스템을 간단히 실행하는 방법을 묻는 경우가 일반화되었다.
그림 2. Python Buildbot, 확대 이미지 참조
Buildbot을 사용한 사례 중 눈에 띄는 경우는 Google Chrome 브라우저 프로젝트를 들 수 있다. 그림 3에는 다양하게 사용자 정의되어 Buildbot 사용자 인터페이스의 모양이 매우 개선된 Buildbot 버전이 표시되어 있다. 다행히도 Google에서는 이러한 Buildbot의 개선사항을 오픈 소스로 공개했으며 아래에 있는 참고자료 섹션에서 소스를 얻어서 이러한 사용자 정의 버전을 빌드할 수 있다.
그림 3. Google Chrome 브라우저 프로젝트에서 개선된 Buildbot, 확대 이미지 참조
이 기사에서는 이러한 특정 구성을 빌드하는 과정을 다루지 않지만 자체적으로 살펴볼 것을 권장한다. 이제 Buildbot 마스터 서버를 신속하게 실행해 볼 차례이다.
이 기사에서는 Ubuntu 8.10에서 이러한 단계를 수행했지만 다음과 같이 Linux 배포판 대부분에서 이러한 단계를 수행할 수 있다.
- ez_setup.py를 다음과 같이 다운로드한다.
wget http://peak.telecommunity.com/dist/ez_setup.py - 다음과 같이 easy_install을 설치한다.
sudo python ez_setup.py - apt-get을 사용하여 Python Twisted 패키지를 설치한다.
sudo apt-get install python-Twisted - collective.buildbot "recipe"를 다음과 같이 실행한다.
sudo easy_install collective.buildbot
이 시점에서 다량의 패키지가 다운로드되고 자동으로 설치되면서 많은 잡다한 내용이 쉘에 표시되기 시작한다. 이 과정이 완료되면 Buildbot을 작성할 수 있게 된다. 설치 과정이 올바르게 진행되었으며 쉘 프롬프트에 다음과 같이 입력한다.
$ paster create -t buildbot my.project
$ cd my.project
실제로 모든 과정이 거의 완료되었지만 그전에 Buildbot을 처음 구성할 때 실패할 수 있는 몇 가지 사항을 살펴보도록 한다. my.project/master.cfg 파일에서 다음과 같은 내용을 확인해야 한다.
Listing 1. master.cfg의 내용
[buildout]
master-parts =
master
passing.project
# uncomment this to enable polling
poller
[master]
recipe = collective.buildbot:master
project-name = passing.project project
# allow to force build with the web interface
allow-force = true
# internal port
port = 9051
# http port
wport = 9081
# buildbot url. change this if you use a virtualhost
url = http://localhost:9081/
# static files
public-html = ${buildout:directory}/public_html
slaves =
localhost NaOaPSWb
[passing.project]
recipe = collective.buildbot:project
slave-names = localhost
vcs = hg
repositories = /home/ngift/myhgrepo
# notifications
mail-host = localhost
email-notification-sender = buildbot@cortese
email-notification-recipient =
super@example.com
# run test each hour
periodic-scheduler=60
# cron build
cron-scheduler = 0 8 * * *
# You can change the sequences to build / test your app
# default options should work for most buildout based projects
build-sequence =
# /usr/bin/python2.5 bootstrap.py -c project.cfg
# /usr/bin/python2.5 bin/buildout -c project.cfg
test-sequence =
nosetests
# zope.testing require exit with status
# bin/test --exit-with-status
[poller]
recipe = collective.buildbot:poller
# don't forget to check this
# since it's generated from the paster template it may be a wrong url
repositories = /home/ngift/myhgrepo
#user = h4x0r
#password = passwd
poll-interval = 120
|
처음에 확인해야 할 가장 중요한 사항은 소스 제어 저장소가 적절한지, 처음에 build-sequence를 공백으로 지정했는지 그리고
지정된 저장소에서 코드가 확인될 때 test-sequence(이 경우에는 "nose")에서 테스트가 전달되는지 확인하는 것이다. 그밖에 궁금한 사항이 있는 경우에는
collective.buildbot 참고자료 안내서를 살펴보도록 한다(관련 링크는 참고자료 확인).
구성 파일을 설정한 다음에는 다음과 같은 두 가지 명령을 간단히 실행하면 된다.
$ python bootstrap.py
$ ./bin/buildout
buildout 명령을 실행하면 다음과 같은 내용이 다수 표시된다.
Listing 2. buildout 명령을 실행한 결과
{673} > ./bin/buildout
Unused options for buildout: 'master-parts'.
Installing master.
New python executable in /home/ngift/my.project
Installing setuptools............done.
[output suppressed for space]
|
이 명령이 완료되면 Buildbot 설치 과정이 종료되어 실행할 수 있게 된다. 쉘에서 다음과 같은 명령을 실행하여 두 개의 Buildbot 데몬을 시작한다.
$ ./bin/master start
$ ./bin/yourhostname start
그런 다음, 브라우저에서 master.cfg 파일에 설정된 URL(기본적으로 http://localhost:9081/)을 가리키면 새로운 Buildbot이 멋지게 표시된다. 물론, 아마도 아직은 작동하지 않을 것이다. Buildbot에서 빌드 스크립트와 테스트 실행기를 지정하면 Buildbot 코드를 적절히 확인하여 코드를 빌드하고 자동으로 테스트한다. 물론 구성 옵션을 일부 사용하여 검색하는 과정이 남아 있지만 중요한 작업은 모두 완료되었다.
최근에는 연속적인 통합 주기를 활용하여 소스 코드와 관련된 지표를 생성하는 과정이 "테스트 매니아" 간에 지능적으로 발전되었다. 가장 일반적인 기술 중 하나는 coverage 옵션을 사용하여 nosetest 테스트 컬렉터를 실행하는 것이다. "foo"라는 프로젝트가 있는 경우 일반적으로 다음과 같이 실행한다.
nosetests --with-coverage --cover-package=example --cover-html \
--cover-html-dir=example_report.html test_example.py
이렇게 하면 다루지 않은 코드의 모든 행이 표시된 HTML 보고서가 생성되고 표준 출력으로 다음과 같은 결과가 출력된다.
Listing 3. nosetest에서 출력된 내용
nglep% nosetests --with-coverage --cover-package=example
--cover-html-dir=example_report.html test_example.py
.
Name Stmts Exec Cover Missing
---------------------------------------
example 2 2 100%
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
|
다운로드 섹션에서 example.py와 test_example.py를 다운로드할 수 있다.
코드가 개정될 때마다 이 보고서가 실행되어 개발자와 관리자에게 실제로 코드에서 일어나는 상황과 관련된 메타데이터를 제공한다. 따라서 CI를 하면서 지표를 평가하는 것이 프로젝트에 유익하다.
코드에 관한 메타데이터를 제공하는 또 다른 지표 도구로는 PyMetrics의 McCabe 평가가 있다. 1970년에 Thomas McCabe는 코드와 관련하여 간단하지만 독창적인 생각을 떠올렸다. 즉, 코드가 복잡할수록 코드가 자주 중단된다는 사실이다. 이러한 사실이 분명해 보일 수도 있지만 불행히도 개발자 대다수는 이러한 관계를 인식하지 못하고 있다. PyMetrics 명령행 도구를 사용하게 되면 총 함수당 분기수를 결정할 수 있다.
인간의 두뇌로는 컨텍스트에서 한 번에 일곱 개 이상의 상황을 유지하는 것은 어렵기 때문에 일반적으로 개발자는 작성하는 모든 메소드나 함수에서 분기수를 10보다 작게 유지하려고 한다. 평가 기준으로서 점수가 50보다 높은 코드는 기본적으로 테스트가 불가능하거나 유지할 수 없는 코드가 된다.
필자는 개인적으로 점수가 140보다 높은 프로덕션 코드를 본적이 있으며 이 코드는 상태가 매우 좋지 않았다. 따라서 이 코드를 통해 McCabe의 이론에 대한 유효성을 확인할 수 있었다. 이처럼 복잡하고 취약한 코드를 초기 개발 과정에서 발견하여 표시할 수 있으면 이러한 코드가 모든 테스트 과정을 통과했다고 하더라도 프로덕션 상황에서 이러한 코드를 사용하게 되는 일은 결코 없을 것이다.
CI를 통해 소프트웨어 빌드와 테스트를 자동화하고 옵션으로 소프트웨어 지표를 생성함으로써 품질 보장 주기를 효율화할 수 있는 혜택을 얻을 수 있다. 이러한 빌드 과정은 소스 코드가 변경될 때마다 트리거되며 프로젝트의 수명과 관련된 보고서와 즉각적인 피드백을 제공한다. CI를 올바르게 구성하면 코드를 작성하는 만큼 CI가 코드를 작성하는 프로세스에 실제로 통합된다.
CI를 테스트할 수 있는 유일한 도구가 Buildbot만 있는 것은 아니다. Hudson이나 Bitten을 고려할 수도 있다. Hudson은 Python으로 작성되었지만 Python으로 된 플러그인을 사용하면 이러한 도구를 사용자 정의할 수 있다. 이러한 시스템에 관한 자세한 정보는 아래에 있는 참고자료를 확인하도록 한다.
| 설명 | 이름 | 크기 | 다운로드 방식 |
|---|---|---|---|
| Sample Python scripts | example.zip | 1KB | HTTP |
교육
- CI(Continuous Integration)에 관한 Martin Fowler의 기사를 읽어보자.
- Wikipedia에서 CI(Continuous Integration) 테스트에 관한 배경 지식을 확인할 수 있다.
- Twisted 핵심 문서에서 Twisted 프레임워크에 관한 개요와 튜토리얼을 확인할 수 있다.
-
Statement coverage for Python에서 Python coverage 모듈인 coverage.py에 대한 소개와 설명을 확인할 수 있다.
- David Stanek가 Python Cyclomatic Complexity의 측정에 관해 설명한다.
- "Using Python to create UNIX command line tools"(developerWorks, 2008년 3월): 이 기사에서는 관리자와 개발자가 필요로 하는 명령행 도구를 Python으로
작성하는 방법에 관해 살펴본다.
- "Agile planning in real life"(developerWorks, 2009년 4월): 이 기사를 통해 회사에서 애자일 개발 작업을 수행하는 데 필요한 유익한 조언을 얻을 수 있다.
-
"Automation for the people"은 developerWorks 시리즈 기사로 Java 개발자를 대상으로 하고 있지만 모든 언어에 쉽게 적용할 수 있으며 소프트웨어 개발
프로세스의 다양한 특성을 자동화하고 효율화하기 위한 여러 가지 방식을 다루고 있다.
- 또한, Java 개발자를 대상으로 하는 "Spot defects early with Continuous Integration"(developerWorks, 2007년 11월) 기사에서 CI에 대한 개요를 확인할 수 있다.
-
developerWorks 리눅스 영역에서는 Linux 개발자와 관리자에게 도움이 되는 수백 편의 사용법 기사 및 튜토리얼과 다운로드, 토론 포럼 및 기타 다양한 참고자료를 볼 수 있다.
-
developerWorks 기술 행사 및 웹 캐스트를 통해 다양한 IBM 제품 및 IT 산업 주제에 대한 최신 정보를 얻을 수 있다.
-
무료 developerWorks Live! briefing을 통해 최신 IBM 제품 및 도구에 대한 정보뿐만 아니라 IT 업계의 최신 경향까지도 빠르게 확인할 수 있다.
-
developerWorks on-demand demos에서는 입문자를 위한 제품 설치 및 설정부터 숙련된 개발자를 위한 고급 기능까지 망라된 다양한 데모를 제공한다.
-
Twitter의 developerWorks를 팔로우(follow)하거나 developerWorks에 대한 Linux 트윗(tweet)의 피드를 구독하자.
제품 및 기술 얻기
- Google Chrome Buildbot 소스를 얻자.
- Buildbot에 대한 대안이 될 수 있는 Hudson과 Bitten을 확인해 보자.
- nose 테스트 프레임워크에 관해 자세히 알아보자.
- collective.buildbot 사이트에서는 Buildbot "buildout" recipe 콜렉션을 제공한다.
-
PyMetrics는 Cyclomatic Complexity Score를 생성하는 도구이다.
-
자신에게 가장 적합한 방법으로 IBM 제품을 평가해 보자. 시험판 제품을 다운로드하거나 온라인으로 제품을 사용해 보거나 클라우드 환경에서 제품을 사용하거나
SOA Sandbox에서 SOA(Service Oriented Architecture)를 효과적으로 구현하는 방법을 배울 수 있다.
토론
-
My developerWorks 커뮤니티에 참여하자.
개발자 중심 블로그, 포럼, 그룹 및 Wiki 검색 중에 다른 developerWorks 사용자와 의견을 교환해 보자.

Noah Gift는 O'Reilly에서 출판한 "Python For UNIX and Linux System Administration"의 공동 저자이며 Manning을 위한 "Google App Engine In Action"에도 참여하고 있다. Gift는 저자, 연사, 컨설턴트 및 커뮤니티 리더로 IBM Developerworks, Red Hat Magazine, O'Reilly 및 MacTech에 글을 기고하고 있다. Gift가 운영하는 컨설팅 회사의 웹 사이트는 http://www.giftcs.com이며 http://noahgift.com에서 그가 쓴 많은 글을 찾아볼 수 있다. Noah의 Twitter에서도 그의 소식을 접할 수 있다.
그는 Cal State Los Angeles에서 CIS 석사 학위를 받았으며 Cal Poly San Luis Obispo에서 영양학 학사 학위를 받았다. Apple 및 LPI 인증 시스템 관리자이며 Caltech, Disney Feature Animation, Sony Imageworks 및 Turner Studios에서 근무했었다. 현재는 뉴질랜드의 Weta Digital에서 일하고 있다. 여가 시간에는 부인 Leah, 아들 Liam과 함께 시간을 보내거나 피아노 연주, 마라톤 달리기 및 종교적인 수양을 하면서 보낸다.