외부 시스템 연계
서브 버전에서 원격 빌드
저장소에 커밋했을 때 특정 조건을 만족하면 자동으로 젠킨스에서 빌드를 수행하기를 원할 수도 있다.
이 요구 사항은 별도의 플러그인 없이 10장에서 익힌 서브버전의 훅 스크립트와 젠킨스의 원격 빌드 트리거를 사용하여 해결할 수 있다.
먼저 서브버전의 저장소중 hook 디렉터리 밑에 다음 내용으로 post-commit 파일을 생성한다. 이 장에 나오는 예제대로 로컬 저장소를 만들었다면 $HOME/svnrepos/hooks/post-commit 이 될 것이다.
#!/usr/bin/php
<?php
$svnlook = 'svnlook';
$repos = $argv[1];
$rev = $argv[2];
$change = `$svnlook changed -r "$rev" "$repos"`;
$list = split("/", $change);
$tmp = split("[ \t]+", $list[0]);
// Project Name
$proj_name = $tmp[1];
$url = "http://jenkins.example.com/job/$proj_name/build"; //젠킨스 URL
$tok = "mySecretToken";
$auth = " -u devel:myPasswd "; // 젠킨스 인증 정보
$param = " --data-urlencode \"token=$tok\" ";
if ($proj_name == "lib-hello") // 원격 빌드할 프로젝트 이름.
{
$cmd = "curl -v $auth $url $param";
$output = shell_exec($cmd);
//실행 결과 출력
error_log("$cmd RESULT\n\n" . $output);
}
편집이 끝났으면 chmod 로 실행 속성을 주어야 한다.
chmod +x svnrepos/hooks/post-commit
이제 lib-hello 프로젝트에서 커밋을 실행하면 자동으로 젠킨스에서 빌드를 수행하게 된다.
gitlab 에서 원격 빌드
gitlab 이 제공하는 웹 훅(webhook) 을 이용하면 원격에서 젠킨스 빌드를 할 수 있다. gitlab 의 웹 훅은 post-receive 훅이라 push 가 완료되면 실행되므로 여기에서 젠킨스의 원격 빌드 URL 을 호출하면 된다.
http://jenkins.example.com/job/hello-webapp/build?token=build_token
URL 에 젠킨스의 원격 빌드 URL 을 입력하면 되며 별도의 인증 정보를 넣는 메뉴가 없으므로 인증이 필요할 경우 URL 에 같이 기술해야 한다.
입력이 끝나면 "Add WEb Hook" 을 클릭하면 훅이 추가된다. 여러 개의 훅을 추가할 수 있으며 훅이 제대로 동작하는지 확인은 하단의 "Test Hook" 을 클릭하면 된다.
레드마인과 연계
"Redmine Plugin" 은 이슈 관리 항목에서 설명한 레드마인과 젠킨스를 연결할 수 있는 플러그인이다. 빌드와 관련된 레드마인 이슈가 있을 경우 젠킨스에서 이슈 목록을 확인할 수 있으며 링크를 통해 상세 이슈를 볼 수 있다.
플러그인 설치가 완료 되었다면 "Jenkins 관리" -> "시스템 설정" 메뉴에 들어가 보자. 다음 그림처럼 레드마인 정보를 설정하는 메뉴가 보일 것이다.
Name 은 식별할 수 있는 적절한 이름을 설정해 보자. "Base URL" 은 레드마인의 URL 을 설정하고 Version 에 는 레드마인 버전을 설정하고 저장을 하자.
이제 작업 설정에 들어가 보자. "Assign Redmine project" 버튼을 클릭하면 두 개의 설정 메뉴가 표시된다.
- "Redmine website" : 레드마인 URL 을 설정할 수 있다. 직접 입력은 안 되며 전역 설정 값중에 선택할 수 있다.
- "Redmine project name" : 현재 젠킨스 작업과 연결되는 레드마인 프로젝트 이름이다. 사전에 레드마인에 프로젝트를 생성해 두어야 한다. 아쉽게도 인증을 지원하지 않으므로 레드마인 프로젝트가 공개여야 연동이 가능하다.
이제 소스를 커밋할 때 특별한 키워드와 이슈 번호를 주면 젠킨스의 빌드 상세 화면에서 "바뀐점" 을 클릭하면 해당 이슈로 가는 링크가 표시되며 클릭하면 레드마인 이슈를 볼 수 있다.
키워드는 다음과 같다. (number 는 레드마인의 이슈 번호를 의미한다.)
- refs number
- references number
- IssueID number
- fixes number
- closes number
- #number
- refs number,number,number
젠킨스 레드마인 플러그인은 기능이 강력하지 않아서 빌드가 실패했을 때 젠킨스에서 바로 레드마인 이슈로 등록하고 이슈 내용에 젠킨스의 ${BUILD_URL) 을 자동으로 입력하거나 빌드와 테스트를 잘 마쳤을 때 레드마인 이슈 상태를 업데이트 하는 등의 작업은 지원하지 않는다.
다만 커밋 로그를 통해 빌드와 이슈를 묶어서 좀 편하게 확인할 수 있는 장점이 있으니 필요에 따라 취사 선택하여 사용하면 된다.
WAS 에 배포
아티팩트가 jar 인 lib-hello 같은 프로젝트를 생각해 보자. 개발과 빌드/테스트가 완료되면 아티팩트는 어딘가에 디플로이 되야 한다. 일반적인 jar 파일은 넥서스같은 저장소 관리자에 배치되며 사용하는 측은 메이븐등의 빌드 도구를 이용하여 가져가게 된다.
아티팩트가 war나 ear 인 경우는 어디에 디플로이 해야 할까? 바로 톰캣이나 JBoss같은 Web Application Server 에 올리게 된다.
war 나 ear 을 WAS 에 디플로이하는 것은 고려해야 할 부분도 많고 절차도 복잡하다. 예로 운영 서버인 경우 안정성을 위해 여러 대의 WAS 서버를 운영하는 경우가 많다.
N 개의 WAS 서버에 war 를 배포하고 WAS 에 반영하는 것은 기술적으로 매우 어려운 문제이며 이에 대한 해결책은 환경에 업무에 따라 다를 수 있다.
WAS 가 클러스터로 구성되었을 경우 클러스터내 서버에 war 를 배포하는 기능을 기능을 가진 WAS 도 있고 전문 배포 솔루션을 이용하여 배포할 수도 있으며 서버가 많지 않으면 자체적으로 배포 기능을 만들어서 사용할 수도 있다.
그외에도 변경 요청서, 테스트 결과서 작성등 내부 절차에 맞게 문서 작업도 필요할 수 있으며 사전에 결제를 받아야 할 수도 있다.
이렇게 운영 환경에 배포하는 것은 회사마다 환경과 절차, 요구 사항과 보안 수준이 다르기 때문에 표준화할 수 없으며 각각에 맞게 특화해서 적용할 수 밖에 없다.
하지만 개발과 테스트 서버라면 빌드와 배포를 자동화 하고 또 이과정에서 빌드나 배포가 실패하거나 WAS 가 다운되는 것은 특별한 상황이 아니라면 별 문제는 안 되는 경우가 많다.
이 절에서는 개발 또는 테스트 환경처럼 빌드와 배포를 자동화해도 문제가 안 되는 환경에서 젠킨스에서 빌드하고 톰캣에 배포하는 방법을 알아 보자.
어플리케이션을 배포하는 톰캣의 URL 은 http://app.example.com 이며 설치 위치는 /home/deploy/app-tomcat-7.0.55 이라고 가정하고 작업을 진행해 보자.
핫 디플로이로 배포
WAS 마다 자동 배포를 위한 관리자 기능이나 API 를 제공하지만 표준화 되어 있지 않으므로 하나의 WAS 에서 되도 WAS 가 변경되면 새로 배포 설정을 해야 한다.
이런 문제 해결을 위해 WAS 에 배포하는 방법을 추상화한 Cargo 라는 자바 프로젝트가 있으며 이를 이용하여 개발된 "Deploy Plugin" 이라는 플러그인을 사용하면 원격지에 있는 WAS 에 배포를 자동화할 수 있다.
Deploy 플러그인이 공식 지원하는 WAS 는 다음과 같다.
Tomcat 4.x/5.x/6.x/7.x
JBoss 3.x/4.x
Glassfish 2.x/3.x
WebLogic 이나 WebSphere 같은 WAS 는 별도의 플러그인이 존재하므로 그것을 사용해야 한다.
젠킨스의 플러그인 관리 메뉴에서 필터에 "Deploy Plugin"을 입력하여 선택후 설치해 보자.
주의 사항
플러그인을 설정하기 전에 먼저 주의 사항을 알아 보자.
먼저 가장 중요한 건 보안 문제이다. 이 플러그인은 톰캣의 manager 기능을 사용하여 디플로이하므로 제대로 보안 설정이 되어 있지 않으면 공격자가 악의적인 war 파일을 배포할 수 있다.
이에 대한 해결책으로 아파치 웹서버의 <Directory> 태그에 디플로이 가능한 IP 를 제한하고 톰캣의 설정에 디플로이용 아이디와 암호를 잘 관리해야 한다.
자세한 건 9.2.3 의 "tomcat manager" 부분과 9.3.2 의 "manager context 보안 적용" 부분을 참고하기 바란다.
두 번째는 WAS 의 핫 디플로이(Hot Deploy) 기능을 기능을 켜야 하는 점이다. 톰캣의 경우 Context 의 해당 항목에 명시적으로 reloadable="false" 로 설정되어 있지 않으면 기본 설정이므로 특별히 변경할 필요는 없지만 WAS 마다 기본 설정이 아닐 수 있으므로 WAS 의 설명서를 보고 해당 기능을 켜야 한다.
이 기능을 켜고 핫 디플로이를 자주 할 때의 문제점은 핫 디플로이는 자바 VM 의 PermGen(Permanent Generation) 영역에서 일어나므로 이 영역이 고갈되어 OutOfMemory 에러가 날 수 있는 점이다.
이를 위해서는 WAS 구동시 자바 VM 옵션에 PermGen 영역을 충분히 주어서 실행해야 하며 그래도 OutOfMemory 에러가 발생시 WAS 를 내렸다가 다시 올려야 한다.
톰캣 설정
이제 9장 톰캣을 참고해서 어플리케이션 배포용 톰캣 인스턴스를 하나 생성해 보자. 설정시 그리고 위의 주의 사항에 맞게 톰캣 설정을 변경해 주자.
같은 서버에 다른 톰캣 인스턴스가 있을 경우 포트 충돌을 막기 위해 톰캣 포트 설정을 변경한다. conf/server.xml 을 수정해야 하며 Server port 와 HTTP Connector 포트 두 개를 안 쓰는 포트로 수정해 주자.
<Server port="8005" shutdown="SHUTDOWN"> <!-- ... --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" UTIEncoding="UTF-8" /> </Server>
XML아파치 웹서버와 톰캣을 연결하여 서비스를 할 경우 아파치가 톰캣 연결이 가능하도록 SELinux 보안 설정을 했는지 확인하자. 자세한 내용은 "9.3.2.1 SELinux 설정" 을 참고하자.
톰캣 매니저 계정과 권한을 설정해야 한다. conf/tomcat-users.xml 에 계정과 권한을 설정하자. 설정 방법은 "9.2.3.1 tomcat-users.xml 설정" 을 참고하자. 아파치 웹서버에서 <Location> 지시자로 매니저 컨텍스트에 접근 제어를 설정했다면 젠킨스 서버의 IP 를 추가해 주어야 젠킨스가 디플로이 할 수 있다.
- 기본적으로 핫 디플로이 설정이 켜져 있으므로 별도로 설정할 필요는 없고 잦은 디플로이로 인한 OutofMemory 를 최소화 하기 위해 톰캣 구동시 PermGen 을 넉넉하게 설정해야 한다. 이에 대한 내용은 "9.1.3 에서 JVM 옵션 설정" 을 참고하자.
작업 설정
플러그인 설치가 끝났다면 이제 작업 설정을 변경해 보자. 배포는 빌드가 완료되어야 가능하므로 "빌드 후 조치" 항목에서 배포 설정이 가능하다.
"빌드 후 조치 추가" 를 클릭하고 "Deploy war/ear to a container " 메뉴를 선택해 보자.
- WAR/EAR files : 배포할 war 파일의 경로를 적는다. ant 문법을 사용할 수 있으며 기본 설정은 모든 war 를 의미하는 **/*.war 이다.
- Context path: 배포할 경로이다. / 로 설정하면 루트 컨텍스트가 된다. server/myapp 같이 하위 경로에 배포하려면 /myapp 를 적어주자. 이 부분은 아파치와 mod_proxy 로 연계할 경우 ProxyPass 와 ProxyPassReverse 항목도 맞게 설정해 주어야 한다.
- Containers : WAS 의 종류로 사용하는 WAS 의 종류와 버전에 맞게 선택해 주자. 우리는 톰캣 7 을 사용할 것이므로 Tomcat 7.x 를 선택했다.
- Manager user name: 톰캣 host 매니저의 이름이다. 톰캣의 conf/tomcat-users.xml 에 지정되어 있다.
- Manager password : host 매니저의 암호이다. 톰캣의 conf/tomcat-users.xml 에 지정되어 있다.
- Tomcat URL : 젠킨스에서 빌드한 war/ear 을 배포할 톰캣 서버의 URL 이다. 서비스의 URL 이므로 젠킨스의 URL 과 혼동하지 말자.
이제 설정이 끝났으므로 빌드가 정상적으로 완료되면 톰캣에 자동으로 디플로이된다.
확인을 위해 hell-webapp 의 src/main/webapp/index.jsp 를 다음과 변경해 보자.
<%@page import="java.util.*"%>
<%@page import="java.text.*"%>
<%@page import="com.example.Hello"%>
<%
Hello h = new Hello();
DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date d = new Date();
%>
<html>
<body>
<h2><%= h.getMessage() %></h2>
<h3><%= df.format(d) %></h3>
</body>
</html>
수정이 완료 되었으면 젠킨스가 가져갈 수 있게 커밋을 하여 중앙 저장소에 반영을 하자. 이제 젠킨스에서 "Build Now!" 를 클릭하면 자동으로 빌드하고 지정한 톰캣에 배포까지 진행하게 된다.
웹 브라우저로 배포한 어플리케이션 URL 에 연결하면 다음과 같은 화면이 보이고 정상 배포를 확인할 수 있다.
hello-webapp 의 빌드 트리거를 "Build whenever a SNAPSHOT dependency is built" 로 설정했다면 lib-hello 가 빌드시 hello-webapp 도 자동으로 빌드되어 배포까지 되는 것을 확인할 수 있다.
(단 lib-hello 프로젝트의 메이븐 골에 deploy 를 넣어주거나 빌드후에 수동으로 "Redeploy Artifacts" 를 선택해 주어야 넥서스에 디플로이 되어 정상 동작한다.)
실제 프로젝트에서는 이렇게 하면 너무 많은 빌드와 디플로이가 일어나겠지만 자동화가 어떻게 진행되는지에 대해 이해를 하는 데는 도움이 될 것이다.
SCP/SSH 로 배포
또 다른 방법은 빌드가 끝나면 SCP 로 아티팩트를 WAS 서버에 복사하고 SSH 를 이용하여 WAS 의 시작/구동 명령어를 호출하는 방식이다.
핫 디플로이보다 설정이 까다롭지만 PermGen 에러 발생을 원천적으로 해결할 수 있으며 안정적으로 디플로이할 수 있는 장점이 있다.
플러그인 설치
이 방식으로 배포하려면 SCP와 SSH 역할을 하는 플러그인이 필요하다. 원래는 각각 별도의 플러그인이 존재했으나 "Pulbish Over SSH Plugin" 라는 플러그인은 SCP/SSH 두 개의 역할을 모두 수행하므로 하나의 플러그인만 있으면 된다.
플러그인 관리 메뉴에 들어가서 필터에 "ssh" 를 입력후 나온 결과 화면에서 "Pulbish Over SSH Plugin" 를 설치하고 젠킨스를 재구동 해보자.
설정
먼저 "젠킨스 관리" -> "시스템 설정" 에 진입하여 설정 항목에서 "Publish over SSH" 를 찾아서 연결에 필요한 정보를 설정해 주자.
- Passphrase : SSH 연결시 암호를 사용하면 여기에 암호를 설정한다.
- Path to key: SSH 키 쌍을 이용하여 로그인할 경우 개인키 파일의 경로를 설정한다.
- Key: Path to key 와 같지만 키가 텍스트 파일로 존재할 경우 여기에 키의 내용을 입력한다.
- Disable exec: 체크아웃 SSH 명령어를 실행하지 않는다.
- SSH Servers
- Name : SSH 연결 설정시 드랍 리스트 박스에 표시할 이름을 지정한다.
- HostName : SSH로 연결할 실제 서버의 IP 나 도메인 이름을 지정한다.
- UserName : SSH로 연결할 사용자의 계정을 입력한다.
- Remote Directory : 원격 서버에 로그인 했을 때 초기에 이동할 디렉터리를 지정한다. 디렉터리는 반드시 존재해야 하며 없으면 에러가 발생한다.
그외에 SSH 가 22번 포트가 아닌 다른 포트를 사용할 경우 "고급"을 클릭하여 포트를 지정한다.
이제 빌드 작업 설정을 변경할 순서이다. hello-webapp 작업 대시보드에 "구성"을 클릭하여 작업 상세 설정에 진입해 보자.
하단의 "Post Steps" 메뉴에서 "Add post-build step" 을 클릭하고 "Send files or execute commands over SSH" 를 선택해 보자.
디플로이는 빌드가 정상적일때만 수행 해야 하므로 "" 라디오 버튼을 선택해 주자.
그리고 SSH Publishers 항목을 설정해 보자.
Name : 전역 설정에서 등록한 SSH 서버 이름이 보일 것이다. 디플로이 하려는 서버를 선택해 주자.
Transters : 서버에 보낼 아티팩트의 패턴과 실행할 명령어를 설정하는 메뉴이다.
- Source files : 서버에 SCP 로 송신할 파일의 패턴을 입력한다. 앤트의 fileset 형식을 사용할 수 있다. 우리는 war 파일을 디플로이 할 것이므로 **/*.war 를 설정하자.
- Remove Prefix : 아티팩트는 메이븐의 target/ 디렉터리에 생기므로 서버에 전송할 때 target 폴더를 만들고 이 안에 위치시키게 된다. 이러면 제대로 디플로이가 안 되므로 target 접두어를 빼고 서버에 전송해야 한다.
- Remote Directory : 서버에 파일을 전송할 디렉터리를 지정한다. 절대 경로를 사용해도 되며 상대 경로를 사용해도 되지만 상대 경로일 때 현재 디렉터리가 전역 설정에서 지정한 초기 디렉터리라는 것만 명심하면 된다. 디플로이 해야 하므로 톰캣의 webapps 를 지정하면 된다.
- Exec command : 서버에서 SSH 로 실행할 명령어를 설정한다. 입력한 순서대로 실행되며 여러 개의 명령어를 실행할 경우 엔터 키를 입력하면 된다. 우리는 다음 순서로 명령어를 실행할 것이다.
- 톰캣 디렉터리로 이동
- 톰캣 인스턴스 종료 ("9.1.3 톰캣 프로세스 우아하게 종료시키기" 의 스크립트 참고 - 스크립트내 TC_HOME 변수를 톰캣이 설치된 경로로 수정해야 한다.)
- 루트 컨텍스트에서 배포를 위해 war 파일 이름 변경
- 톰캣 인스턴스 시작
여기까지 설정했다면 이제 모든 설정을 마쳤다. "Build Now" 를 클릭하여 빌드와 디플로이를 진행해 보자.
정상적으로 빌드가 완료되었다면 SCP 와 SSH 플러그인이 동작하여 원격 서버에 아티팩트를 복사하고 톰캣을 재구동 할 것이다.