이제 Buildr 시리즈도 막바지를 향해 달려가는군요. 이번에는 빌드 결과물을 원격의 서버에 배포해보겠습니다.
Maven에 install, deploy 단계(phase)가 있는 것처럼 Buildr에도 배포와 관련된 install, upload, release 타스크가 있습니다만, 일반적인 웹어플리케이션 개발 프로젝트에서는 그닥 쓸모가 없습니다. 웹어플리케이션 프로젝트에서 배포는 대부분 WAS에 deploy하는 것을 의미하기 때문입니다.

로컬 WAS에 배포하는 건 간단하니 넘어가고, 리모트에 있는 개발서버나 운영서버에 우리가 빌드한 어플리케이션을 전송하는 방법을 알아보겠습니다.

요즘은 원격 서버에 연결하기 위한 프로토콜로 거의 ssh, scp를 이용합니다. Ant에서는 ssh,scp 프로토콜로 원격 서버에 연결하기 위해서 흔히 jsch 라이브러리를 사용했죠. Buildr에서는 net-ssh, net-scp 라이브러리를 사용하여 이런 작업을 처리합니다. 

먼저 profiles.yaml에 다음처럼 WAS 서버에 대한 접속정보가 설정되어 있습니다(이건 예제입니다).

development:
  wasserver:
    host: 111.111.111.111
    username: weblogic
    password: weblogic
    deploy_dir: /home/weblogic/webapps
    restart: sh /home/weblogic/restart.sh

production:
  wasserver:
    host: 222.222.222.222
    username: prod
    password: prod
    deploy_dir: /home/prod/webapps
    restart: sh /home/prod/restart.sh

WAS 서버에 웹어플리케이션을 업로드하는 타스크는 아래와 같이 작성할 수 있습니다. Net::SCP.start 메소드에 접속정보를 넘겨주고 블록 안에서 scp의 upload 메소드를 이용하여 'target/webapp' 디렉토리를 업로드하고 있습니다.

task :deploy_webapp => :package do
  require 'net/ssh'
  require 'net/scp' 

  wasserver = Buildr.settings.profile['wasserver']
  Net::SCP.start(wasserver['host'], wasserver['username'],
                       :password => wasserver['password']) do |scp|
    scp.upload!('target/webapp',  wasserver['deploy_dir'], :preserve=>true, :recursive=>true) 
  end
end

이렇게 업로드하면 로컬의 target/webapp/index.jsp 파일은 원격의 /home/weblogic/webapps/webapp/index.jsp에 위치하게 됩니다. 그러니까 로컬의 webapp 디렉토리 자체가 원격 타겟 디렉토리 밑으로 들어갑니다. 아 이건 우리가 원하는게 아닙니다. target/webapp 디렉토리는 빼고, 그 밑의 파일/디렉토리들만 원격 타겟 디렉토리 밑으로 보내고 싶습니다. 고민할 필요없이 FileList를 이용하면 됩니다.

FileList['target/webapp/*'].each do |file|
  scp.upload! file, file.sub('target/webapp',wasserver['deploy_dir']),:preserve=>true,:recursive=>true
end

exploded 모드로 빌드된 target/webapp 디렉토리 말고 그냥 하나의 패키징된 war 파일을 업로드하는 건 어떨까요? 

  scp.upload! package(:war).name, wasserver['deploy_dir'], :preserve=>true

패키징된 war 파일의 이름은 package(:war).name 로 구할 수 있었습니다. 무지 쉽군요. 

실제 실행해보시면 알겠지만, 이렇게 원격으로 업로드 시 콘솔에는 아무 것도 찍히지 않습니다. 재미가 없죠. 지금 어떤 파일이 전송되고 있는지 최소한 파일 이름이라도 나와주면 좋을 겁니다. 업로드 진행현황은 upload 메소드에 블록을 넘겨주어 표현할 수 있습니다. 다음은 업로드되는 파일의 이름과 파일의 전체 크기를 출력하는 예제입니다.

scp.upload!(package(:war).name, 
                 wasserver['deploy_dir'],
                 :preserve=>true) do |ch, name, sent, total|
  puts "uploading #{name} (#{total} byte)" if sent == 0
end

음... 전송파일의 크기가 큰 경우에는 콘솔에 변화가 별로 없으니 이것도 솔직히 별로 재미가 없습니다. 좀더 다이내믹하게 진짜로 현재의 업로드 진행 현황을 막대그래프에 #이나 * 문자가 늘어나는 식으로 보여주면 좋겠는데....
Buildr에서 메이븐 저장소에서 아티팩트를 다운로드 받을 때 다운로드 그래프가 나온다는 사실을 떠올리며 Buildr 소스를 여기저기 까보다가 ProgressBar 클래스를 발견했습니다. 나름 쓸만하네요.

local_file = package(:war).name
remote_dir = wasserver['deploy_dir']

ProgressBar.start :total=>File.size(local_file),:title=>local_file do |progress|
  scp.upload!(local_file, remote_dir, :preserve=>true) do  |ch, name, sent, total|
    progress.inc sent
  end
end

콘솔에 이렇게 출력됩니다.


웹어플리케이션을 업로드했으니, WAS를 재기동해볼까요? 서버에 있는 WAS를 재기동 or 웹어플리케이션을 재배포하는 여러 방법중에서 가장 간단한 방법은 아마도 쉘스크립트를 실행하는 방법일 겁니다. 원격 명령어 실행은 Net::SSH를 이용하여 처리합니다. Net::SCP와 유사하니 설명은 생략합니다.

task :restart_was do
  require 'net/ssh' 

  wasserver = Buildr.settings.profile['wasserver']
  Net::SSH.start(wasserver['host'],
                 wasserver['username'],
                 :password => wasserver['password']) do |ssh|
    ssh.exec! wasserver['restart']
  end
end

만약 WAS 재기동 스크립트 실행을 :deploy_webapp 타스크 안에서 처리하고 싶으면 다음처럼 합칠 수 있습니다. (ssh.scp로 쓰인 부분을 주목하세요)

task :deploy_webapp do
  require 'net/ssh'
  require 'net/scp'
  wasserver = Buildr.settings.profile['wasserver']
  Net::SSH.start(wasserver['host'],
                 wasserver['username'],
                 :password => wasserver['password']) do |ssh|    
    ssh.scp.upload! package(:war).name, wasserver['deploy_dir'], :preserve=>true     
    ssh.exec! wasserver['restart']
  end
end

 

'Build&Deploy > Buildr' 카테고리의 다른 글

Buildr : Hudson CI 연계하기  (0) 2009.01.14
Buildr : 설정정보 관리  (0) 2008.12.24
Buildr : 코드분석 리포트 생성  (0) 2008.12.23
Buildr : 빌드결과 패키징  (0) 2008.12.18
Buildr : 아티팩트 다운로드 받기  (0) 2008.12.17
Posted by 에코지오
,

허드슨에서 scp 프로토콜을 통해 서버에 접속하는 작업을 포함하는 스크립트를 실행시 인증실패 에러가 발생하면서 빌드 작업이 중단되는 경우가 있다.

아이디/패스워드 인증 방식으로 접속하더라도 스크립트에 아이디와 패스워드만 설정해 놓고 인증에 필요한 모든 준비가 다 끝났다고 안심하면 안된다.

        <sshexec host="${wasserver.ip}" username="${wasserver.username}"
         password="${wasserver.password}" trust="true" timeout="20000" failonerror="false"
         command="${wasserver.cmd.restart}" />

허드슨으로 스크립트를 실행하기에 앞서 허드슨이 설치된 머신의 커맨드 창에서 먼저 scp에 접속해서 접속인증을 획득해 주어야한다.

The authenticity of host 'xxx.xxx.xxx.xxx' can't be established.
RSA key fingerprint is 13:70:69:51:0b:84:a3:d6:fa:ab:ab:89:1a:05:2d:22.
Are you sure you want to continue connecting (yes/no)?  => 여기서 yes를 입력해야 한다.


 

Posted by 에코지오
,

메이븐에는 wagon이라는 게 있는데 ftp, http, scp, webdav 같은 전송 프로토콜을 추상화한 것인데 site:deploy는 site 파일들을 리모트에 전송하기 위해 wagon 기능을 이용한다.  리모트 경로는 아래처럼 "프로토콜://~" 형식으로 설정하면 되며, 메이븐은 설정된 프로토콜에 적당한 프로바이더를 찾아서 파일을 전송해준다.

  <distributionManagement>
    <site>
      <id>www.yourcompany.com</id>
      <url>scp://www.yourcompany.com/www/docs/project/</url>
    </site>
  </distributionManagement>

site:deploy를 실행하고 콘솔에 찍히는 로그를 살펴보면 

- 로컬에서 .wagon12345.zip 과 같은 임시 zip 파일이 만들어진다
- zip 파일을 리모트 서버로 전송한다. ######## 표시가 늘어나는 식로 전송 진행상태를 보여준다.
- 리모트서버에서 unzip 명령으로 해당 경로에 압축을 풀고, 압축이 다 풀리면 zip 파일을 삭제한다.

그러니까 ant의 scp 타스크나 ftp 타스크가 지정된 fileset에 대해서 파일을 낱개로 하나씩 보내는 반면에,
wagon은 파일에셋을 로컬에서 압축하여 하나의 zip파일로 보낸 뒤 리모트에서 zip을 풀어내는,
나름 효율적인 방식으로 작동한다.

그러나 리모트에서 zip 파일을 푸는 방법에 문제가 있다. 리모트 서버에서 unzip이 없으면 에러가 발생하는 것이다.
실제로 지금 있는 프로젝트의 hp-ux 서버에는 unzip이 설치되어 있지 않았다.
(또 이상한 건 unzip 설치후 ssh 클라이언트로 접속해서 unzip을 실행해보면 잘 실행이 되는데도 불구하고,
wagon으로 파일을 전송해보면 unzip이 없다는 에러가 발생한다. unzip을 /usr/bin에 두어 해결은 했지만,
지금도 잘 이해가 되질 않는다. /usr/bin 이외의 다른 위치에 있으면 unzip이 없다는 에러가 발생한다는게..쫌...)

구걸링을 해보니 메이븐 1.x에서는 압축파일의 포맷과 압축해제 실행파일의 위치를 지정할 수 있게했다고 한다.
즉 tar로 묶는 것도 되고 gunzip으로 zip을 풀 수도 있었단 거다. 그러던 것이 메이븐 2.x에 와서 zip, unzip으로 고정이 돼버렸다.

http://jira.codehaus.org/browse/MSITE-30?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=147326#action_147326

황당한 생각에 wagon-ssh 프로바이더의 소스를 다운받아 까보니
org.apache.maven.wagon.providers.ssh.ScpHelper 클래스의 putDirectory() 메소드에
이렇게 하드 코딩이 돼있다.

executor.executeCommand( "cd " + path + "; unzip -q -o " + zipFile.getName() + "; rm -f " + zipFile.getName() );

왜 이렇게 fix 시켰을까?  막돼먹은 코딩인가? 아니면 관습의 강요인가?

Posted by 에코지오
,