Capistrano 처음부터…

레일스 어플리케이션을 배포하는 것은 매우 까다로와 초보수준에서는 여간 어려운 일이 아닌 것 같습니다. 그러나 Passenger(aka “mod_rails”) 모듈을 아파치나 “Nginx” 서버에 붙여서 사용하면 쉽게 배포할 수 있어 수고를 덜어 주게 되었습니다. 그래서 저도 아파치+Passenger 조합으로 웹서버를 운영하고 있습니다. 그러나 레일스 공식 홈페이지에 나와 있는 레일스 배포에 관한 내용을 보면 “Capistrano” 젬을 이용한 레일스 어플리케이션의 배포가 관리적인 면에서 편리한 것 같습니다. 그리고 규모가 큰 서버군을 운영할 경우에는 더더욱 Capistrano를 이용해서 배포해야 특히 SCM과의 연계는 여러모로 도움이 될 것 같습니다.

그 동안 멀리서만 바라보던 Capistrano를 이제 사용해야할 시점이 된 것 같아 2-3일에 걸쳐 열심히 공부했습니다. Capistrano를 시작하는 분들에게 도움이 될까하여 Capistrano 웹사이트에 있는 내용 중에 “From the beginning” 부분을 한글로 번역하였습니다.

==================================

좋습니다. 레일스 어플리케이션을 막 완성했다면 이제는 그것을 어딘가에 배포해야 할 때입니다. 도메인 네임도 구입했고 웹호스팅 업체도 알았고 레일스 어플리케이션을 배포하는 방법에 대해서도 알게 되었습니다. 이 과정 중에 대부분의 사람들이, 레일스 어플리케이션을 일괄적으로 배포할 수 있는 “Capistrano”라는 것을 추천한다는 것을 알게 될 것입니다.

Capistrano의 설치는 너무 쉬워서 `gem install capistrano ` 라고 명령을 실행하면 됩니다.
자, 그러면, 이후부터의 과정을 함께 살펴 보도록 하겠습니다.

### 배포정책의 결정

Capistrano를 효과적으로 설정하기 위해서는 우리는 몇가지 배포관련 정책을 결정해야 합니다. Capistrano가 대신해 주지 않지만 어떤 식으로든 결정만 하고 나면 나머지는 Capistrano가 기본사항을 대신해서 결정해 줄 것입니다.

우리가 선택할 수 있는 옵션을 살펴 보겠습니다. 이것은 마치 비행전 체크리스트와 같이 생각해 볼 수 있습니다. 이 모든 조건을 만족하지 않을 경우 배포가 성공하지 못할 것입니다. 서버를 설정하는 것을 즐거워하지 않는 이상 이러한 일은 매우 재미없고 지루한 일이 될 것이지만, 일단 체크리스트를 모두 통과하고 나면 재차 확인할 필요가 없게 됩니다.

### 웹 서버

먼저, 어떤 웹서버 소프트웨어를 사용할지를 결정해야 합니다. 이 글을 쓸 당시, `Apache`, `Lighttpd`, `nginx` 는 대표적인 3가지 예라고 할 수 있습니다. 만약 웹호스팅과 같은 공용 서버를 사용할 경우에는 이미 웹서버에 대한 결정을 내려진 것이 다름없는 것입니다. 특별히 선호하는 웹서버 소프트웨어가 없다면 `nginx`를 한번 사용해 수도 있습니다.

### 데이터베이스

다음으로는 운영환경에서는 사용하게 될 데이터베이스의 종류를 결정할 필요가 있습니다. `MySQL`과 `PostgreSQL` 이 오픈소스 커뮤니티에서는 가장 흔히 사용하는 데이터베이스인 것 같습니다. 물론 규모가 큰 회사에서는 `Oracle`과 같은 데이터베이스를 사용할 수도 있습니다.

일부에서는 운영서버에서 `SQLite`를 사용하고 있는데 이것을 그리 권장할 만한 것을 아닙니다. 이것은 싱글유저에 대해서는 훌륭한 데이터베이스가 될 수 있지만, 웹 환경에서는 사실 제대로 확장하기가 어려운 문제가 있습니다.

사용가능한 옵션 중에, `MySQL`은 일반적으로 설치와 설정하기가 가장 쉬워서, `PostgreSQL`에 대한 경험이 없다는지, 아니면 딱히 `MySQL`을 사용해서는 안 될 상황이 아니라면 `MySQL` 데이터베이스를 사용할 것을 권합니다.

### 루비

루비는 레일스 어플리케이션에서 매우 결정적인 역할을 합니다. 필요로하는 루비의 버전을 결정해야 하고 어떤 루비 포맷을 사용할 것이지도 결정해야 합니다. 예를 들면, JRuby는 최근에 레일스 어플리케이션을 실행할 수 있게 되었습니다. 그래서 MRI(일반적인 루비, Matz’s Ruby Interpreter) 루비보다는 JRuby로 배포하고자 한다면 배포 설정방식을 상당히 변경해야 할 것입니다.

### 어플리케이션 레이어

`어플리케이션 레이어`는 어플리케이션을 실제로 실행하는 메모리 스택상의 일부분을 말합니다. `Mongrel`이 이 레이어 있어서 매우 인기있는 옵션이긴 하지만, 최근에는 `Thin`과 `Passenger(일명 mod_rails)`가 인기를 얻고 있습니다.

일부에서는 루비와 함께 배포되는 웹서버인 `WEBrick`에 어플리케이션을 배포하기도 했지만, 이것은 절대로 추천되지 않는 방법입니다. `WEBrick` 웹서버는 레일스 어프릴케이션을 개발하고 테스트할 때 개발환경으로써는 충분하지만, 운영서버에서는 거의 확장성이 없습니다.

또한, `Passenger`을 이용하고자 한다면 이를 지원하는 웹서버를 사용해야 합니다. (예를 들어, `Passenger`는 `Apache 2`와 `nginx`에서만 작동합니다.)

### 소스컨트롤(소스 버전관리)

배포 설정할 때 소스컨트롤을 고려하는 것이 이상하게 보일 수도 있습니다만, Capistrano는 최소한 기본적으로 소스컨트롤시스템 (SCM)에 매우 의존적입니다.

Capistrano는 몇가지 SCM을 별다른 추가 설정없이 바로 사용할 수 있도록 지원합니다. 이러한 것들로는, 최근 레일스 프로그래머들 사이에서 가장 인기 있는 것 중에 `Subversion`과 `Git` 두개를 포함할 것입니다. 편안하게 사용할 수 있는 것으로 하나를 선택하면 될 것입니다. 난해한 시스템만 아니라면 Capistrano가 지원할 것입니다.

### 이 튜토리얼에서는

아래의 셋업 절차에 촛점을 맞추어 설명을 할 것입니다. 각자의 셋업에 차이가 있다면 몇군데에서 맞추어 나갈 필요가 있을 것입니다.

– nginx
– MySQL
– MRI Ruby
– Mongrel
– Subversion

### Capification

Capistrano를 설치한 후 제일 먼저 해야할 것은 어플리케이션을 “capify”하는 것입니다. 이것은 어플리케이션을 배포하기 위해 Capistrano를 구성하는 과정입니다. 너무나 쉬워서 어플리케이션 루트 디렉토리에 위치한 상태에서 `capify .`(즉, “capify” 다음에 한칸 띄고 쩜을 찍는다)라고 입력하면 됩니다.

이것은 두개의 파일을 생성하게 됩니다:

`capfile` 이것은 Capistrano가 필요로하는 가장 중요한 파일입니다. “make”가 자동으로 “Makefile”을 로드하고 “rake”가 자동으로 “Rakefile”을 로드하듯이, Capistrano는 기본적으로 “Capfile”을 찾아서 로드하게 됩니다. capify가 생성하는 기본 Capfile에는 극히 최소한의 내용만 들어 있습니다. 이 파일이 하는 일이란 것이 “config/deploy.rb” 파일을 로드하는 것입니다.

`config/deploy.rb` 이 파일에는 레일스 어플리케이션의 배포시 구성할 내용이 들어 있습니다. 레일스는 모든 구성파일이 config 디렉토리에 위치하는 것을 선호하기 때문에, Capistrano는 Capfile이 config/deploy.rb 파일을 로드하도록 원칙을 준수하려고 합니다.

일반적으로, Capfile은 건들리지 않고 config/deploy.rb 파일에서 설정을 하게 됩니다. 레일스 외의 환겨에서 Capistrano를 사용할 경우라면, config/deploy.rb파일없이 단지 Capfile만이 생성될 것입니다. (이 부분에 대해서는 나중에 설명을 할 것입니다. 여기에서는 레일스 어플리케이션을 배포하는데 초점을 맞출 것입니다.)

### 구성

필요로 하는 파일이 준비되었고, 다음으로는 Capistrano에게 배포할 서버에 대한 정보를 알려주어야 합니다. 처음에는 작은 규모로 시작할 것이기 때문에, 하나의 서버만을 가지고 작업을 하게 될 것입니다. 이 서버는 웹서버, 레일스 어플리케이션, 데이터베이스를 올인원으로 호스팅하게 될 것입니다.

구성 과정은 실제로 그렇게 어렵지 않습니다. Capistrano는 대개 단지 약간의 정보만을 요구합니다.

기본으로 생성된 config/deploy.rb 파일을 보면, 그 안의 내용이 많지 않다는 것을 알게 될 것입니다. 단지 몇가지 사항만 Capistrano에게 알려 주면 됩니다. 먼저, 어플리케이션의 이름을 알려 줍니다. 여기서는 “tutorial”이라고 이름을 정할 것이지만, 각자는 배포에 가장 적절한 것으로 이름을 정해야 합니다.

set :application, “tutorial”

그리고나서, Capistrano에게 소스코드가 어디에 있는지를 알려 주어야 합니다. 이것은 어플리케이션 소스가 있는 저장소의 주소가 될 것이며 기본적으로 로컬 머신과 운영 서버에서 모두 접근할 수 있어야 합니다. 다음의 URL은 예로 든 것이지만 해당 저장소의 위치를 명시하는 방법을 알려 줍니다:

set :repository, “svn+ssh://code.capify.org/repos/tutorial”

이제, Subversion을 사용하지 않을 것이라면 별도로 Capistrano에게 사용하게 될 SCM을 알려 주어야 합니다.

set :scm, :git

여기서는 Subversion(기본설정)을 사용할 것이기 때문에 별도로 SCM을 명시할 필요가 없습니다.

다음으로는, Capistrano에게 레일스 어플리케이션 소스를 서버상의 어디에 배포할 것인지를 알려 주어야 합니다. 이것이 의미하는 바를 잘 이해하기 위해서는 잠시 여기서 벗어나, Capistrano가 어플리케이션을 배포하기 위해 사용하게 될 디렉토리 구조에 대해서 먼저 이야기를 할 필요가 있습니다.

### 배포 디렉토리 구조

Capistrano를 이용하여 배포가 성공적으로 완료되면 다음과 같은 디렉토리 구조가 생성될 것입니다. 여기서 [deploy_to]는 Capistrano가 서버상에 배포하게 될 위치를 의미합니다.

[deploy_to]
[deploy_to]/releases
[deploy_to]/releases/20080819001122
[deploy_to]/releases/…
[deploy_to]/shared
[deploy_to]/shared/log
[deploy_to]/shared/pids
[deploy_to]/shared/system
[deploy_to]/current -> [deploy_to]/releases/20100819001122

배포할 때마다, “releases” 디렉토리에 새로운 디렉토리가 생성되며, 그 곳에 새 버전이 위치하게 될 것입니다. 이 때 “current”라는 심볼릭 링크가 새로 생성된 디렉토리를 가리키도록 갱신될 것입니다. (현재 상태에서는 shared 디렉토리에 대해서 신경을 쓰지 않도록 할 것입니다. 나중에 언급될 것입니다.)

웹서버가 어플리케이션에 대한 루트 웹 디렉토리로 [deploy_to]/current/public를 찾도록 설정되었는지를 확인할 필요가 있습니다.

### 구성으로 돌아가서…

이제, 구성으로 돌아와서, Capistrano에게 서버상에 어플리케이션의 위치를 알려 줄 필요가 있습니다. 기본 설정은 “/u/apps/#{application}”가 될 것이며, 여기서 #{application}은 위에서 어플리케이션의 이름으로 설정한 것이 될 것입니다. 그러나, “/var/www”와 같은 위치로 배포하고자 할 경우에는, :deploy_to 변수에 이 값을 할당해 주면 됩니다:

set :deploy_to, “/var/www”

마지막으로, Capistrano에게 서버의 위치와 각 서버가 수행하게 될 role을 알려주어야 할 필요가 있습니다. (여기서는 하나의 서버만 있기 때문에, 하나의 서버에서 모든 role을 수행하게 될 것입니다) “role” 선언을 해 주어 이러한 작업을 하게 됩니다.

role :app, “tutorial.com”
role :web, “tutorial.com”
role :db, “tutorial.com”, :primary => true

여기서는 하나의 서버만 존재하므로, 위의 role 선언은 다소 중복되어 보입니다. 따라서 대체 문법으로 “server”라는 키워드를 사용할 수 있습니다.

server “tutorial.com”, :app, :web, :db, :primary => true

이 경우에, 두가지 방법은 기능적으로 동일할 것이지만, 전자가 후자보다 다중 서버에 대해서 유지관리 면에서 있어서 더 잘 대응할 수 있습니다.

app, web, db 이 세가지 role이, Capistrano가 레일스 배포시에 필요로 하는 세가지인 것입니다. 언제든지 이외에도 자신만의 task를 위해서 role을 추가할 수 있지만, 레일스를 배포할 때 app, web, db 각각에 대해서 최소한 하나의 서버를 선언해 주어야 합니다.

– `web` : 이것은 웹서버 소프트웨어가 실행되는 위치입니다. 웹으로부터의 요청은 이 곳으로 바로 전달됩니다. 트래픽은 많은 사이트의 경우에는 로드 밸런스 뒤에 2개 또는 그 이상의 웹서버를 둘 수 있습니다.
– `app` : 이것은 어플리케이션 레이어가 실행되는 위치입니다. 하나의 웹서버만으로 로드 밸런스를 통해서 4-5개의 앱 서버로 요청을 보낼 수 있습니다.
– `db` : 마이그레이션이 실행되는 위치입니다. 경우에 따라서는 데이터베이스가 운영되고 있는 서버상에서 코드를 실행하지 않는 것을 선호할 경우에는 앱 서버 중에 하나로 위치를 설정할 수 있습니다. Capistrano는 어플리케이션을 이 role(`db`)에 있는 서버로 배포할 것입니다. “:primary => true” 옵션은 이것이 “primary” 데이터베이스 서버라는 것을 알려 주게 됩니다. 이것은 데이터베이스 슬라이브 경우와 같이 원하는 수 만큼의 데이터베이스 서버를 가질 경우에 해당하지만, Capistrano는 “primary”로 지정된 데이터베이스 서버에서만 마이그레이션을 수행하게 될 것입니다.

각각의 role에 설정하는 URL 주소는 명령을 수행하기 위해 Capistrano가 SSH로 연결할 수 있는 주소이어야 합니다.

### 기타 구성요소

이상의 변수들은 다수의 사람들을 충족시킬 수 있지만, 원할 경우 추가할 수 있는 변수가 몇가지 더 있습니다.

– `set :user, “foo”` 로컬 머신에 로그인한 것과 다른 계정으로 서버에 로그인하고자 할 경우, Capistrano에게 해당 계정을 알려줄 필요가 있습니다.
– `set :scm_user, “foo”` 로컬 머신에 로그인한 것과 다른 계정으로 소스 저장소에 접근을 하고자 할 경우, Capistrano가 알 필요가 있습니다. 모든 SCM이 scm_user 변수를 지원하지 않기 때문에 주의해야 하며, 이 때는 scm_username을, “svn+ssh://#{scm_username}@fool.bar.com/path/to/repo”와 같이 저장소 위치에 삽입해 둘 필요가 있습니다.
– `set :use_sudo, false` 기본적으로, 서버를 셋업한다든지, 웹어플리케이션을 재시작한다든지 등과 같은 작업을 수행할 경우에, Capistrano는 sudo를 사용하려고 시도할 것입니다. 그러나, 웹호스팅의 경우와 같이 호스트를 공유할 경우에는, sudo를 사용할 수 없거나, sudo 사용을 회피할 수도 있습니다.

### Capistrano에게 요청하기

자, 이제 모든 구성을 마친 상태이므로, Capistrano에게 어떤 요청을 할 수 있게 되었습니다. 이것은 “서로를 알게 되는” 단계입니다.

먼저, Capistrano에게 자신에 대해서 알고 있는 바를 물어 볼 수 있습니다:

$ cap -h

이것은 자신이 수용할 수 있는 모든 옵션들에 대한 목록을 내 뱉을 것입니다. 다른 옵션을 보겠습니다:

$ cap -H

대분자 H를 사용할 경우에는, 각각의 옵션에 대한 자세한 설명과 함께 보여 줄 것입니다.

다음으로, Capistrano에게 자신이 알고 있는 task를 물어 보도록 합시다. “Task”는 Capistrano의 작업 단위입니다. Capistrano가 몇가지 내장 task를 번들로 제공해 주긴 하지만, 자신의 task를 작성해서 작업의 흐름을 자동화 할 수도 있습니다. 이제, Capistrano가 알고 있는 task에 대해서 알아 보겠습니다:

$ cap -T

본 튜토리얼에서는 task 몇가지에 대해서만 다룰 것이지만, “-e” 스위치를 이용하면 task 각각에 대한 자세한 내용을 알 수 있습니다.

$ cap -e deploy:web:disable

이것은 이전에 알지 못했던 task에 대해서 배울 수 있는 훌륭한 방법입니다.

### 서버 셋업

다음은, 비로소 Capistrano를 통해서 서버에 요청을 할 수 있게 되었습니다. 제일 먼저 Capistrano에게 자신이 사용하게 될 기본 디렉토리 구조를 셋업하도록 요청할 필요가 있습니다:

$ cap deploy:setup

이로서 서버에 로그인하게 될 것이고 몇차례의 “mkdir” 명령을 호출할 것입니다. 그러나 주의할 것은, deploy.rb 파일에서 use_sudo를 false로 설정한 경우와 같이 sudo를 사용하지 않을 경우에는, deploy_to 디렉토리에 대한 접근권한이 있는지를 확인할 필요가 있습니다. 그렇지 않을 경우, deploy:setup은 실패하게 될 것입니다. 퍼미션 문제를 해결하기 위해서는, 서버에 로그인해서 권한설정을 하기 위해 chown 명령을 몇차례 호출해야 할 필요가 있을 것입니다. (이 문제는 구성에 따라 크게 영향을 받기 때문에 방법을 모를 경우에는 Capistrano 메일링 리스트에서 자유롭게 질문을 하기 바랍니다)

비록 sudo를 사용한다고 하더라도 deploy:setup이 생성하는 디렉토리에 대한 퍼미션을 수정할 필요가 있을 수 있습니다. 이럴 때는 제대로 쓰기 권한을 가지기 위해서 해당 디렉토리들이 배포하는 계정에 대한 올바른 접근권한을 가지는지를 확인해야 합니다.

### 의존성에 대한 점검

이제 배포할 디렉토리 골결구조를 가지게 되었으므로, Capistrano에게 요청하여 모든 의존성이 제대로 설정되었는지를 알아 보아야 합니다. 여기에는 디렉토리 퍼미션 뿐만 아니라 로컬과 원격에서 필요한 프로그램들이 포함됩니다. 이 작업은 뭐 그리 어렵지 않습니다:

$ cap deploy:check

Capistrano는 다양한 항목에 대해서 로컬 및 원격 서버를 점검하게 될 것입니다. 의존성이 제대로 설정되지 않았을 경우에, 무슨 문제가 있는지를 에러 메시지로 알려 주게 됩니다. “접근권한이 없습니다”와 같은 메시지가 보일 때는, 서버에 로그인해서 수작업으로 접근권한이 만족할 때까지 디렉토리에 대해 chmod 또는 chown 명령을 수행할 필요가 있을 것입니다. Subversion을 사용할 경우에는 “svn” executable missing 과 같은 메시지가 보일 때는 해당 툴이 설치되었는지를 확인해 봐야 합니다.

SCM으로 어떤 것을 사용하더라도 상관없이, subversion을 설치했지만, 일반적인 경로 외에 위치할 경우(표준 경로는 대개 /bin:/usr/bin:/usr/sbin)가 있습니다. 이런 경우에는 Capistrano가 svn 실행파일을 찾지 못하게 되는데 이 때는 Capistrano에게 명시적으로 위치를 알려 줄 필요가 있습니다. 이를 위해서는, :scm_command를 원격 서버상의 정확한 경로로 지정해 주면 됩니다.
그러나 이렇게 되면 로컬 서버상에서 해당 명령을 더 이상 찾을 수 없게 될 수 있습니다. 그래서 이런 경우에는 :local_scm_command를 :default 또는 로컬 서버상의 명확한 경로로 지정해 주면 됩니다.

Capistrano가 통과했다는 메시지를 보일 때까지 설정을 변경한 후에는 계속해서 “deploy:check”을 실행해야 합니다. 이러한 작업은 하나의 소동꺼리라는 것을 알지만, 일단 한번만 겪으면 되는 것입니다. 서버 설정이 제대로만 되면 차후 배포는 쉽게 진행할 수 있습니다.

### 데이터베이스 초기화

자, 이제 첫번째 배포 순간에 더 가까워졌습니다. 이전에 데이터베이스가 준비되었는지를 확인해야 합니다. 이미 데이터베이스는 설치되었지만, 다음의 세가지 항목을 확인할 필요가 있습니다:

– 어플리케이션에서 사용할 데이터베이스를 생성했는가? 데이터베이스 소프트웨어와는 별개로 또한 논리상의 데이터베이스 개념이 있습니다. MySQL의 단일 인스턴스를 예를 들면, 다수의 논리상의 데이터베이스를 관리할 수 있습니다. 많은 DBMS(데이터베이스 운영시스템)에서 이것은, superuser로 로그인해서 “CREATE DATABASE”를 호출하면 될 정도로 간단합니다. (그러나, 사용하고 있는 해당 데이터베이스의 매뉴얼을 읽어 볼 수도 있습니다.)
– config/database.yml 파일의 “production” 부분을 추가했는가? 일부에서는 운영서버 로그인 정보를 소스코드 저장소에 추가하는 것을 불편해 합니다. 그러나 편의상, 본 튜토리얼에서는 언급한 바와 같은 상황으로 가정을 할 것입니다. (그렇게 하지 않을 경우에는 구글 검색을 통해서 대안을 찾거나 메일링 리스트에 질의해 볼 수 있습니다. 역시, Mike Clark의 “Advanced Rails Recipes”에는 실무에서 복사후 붙여넣기를 할 수 있는 좋은 예제들이 들어 있습니다.)
– 어플리케이션의 데이터베이스에 대한 접근권한이 적절하게 설정되었는가? database.yml 에서 production 데이터베이스 옵션에 지정한 사용자가 해당 데이터베이스에 접근할 수 있어야 합니다. 이 말은 적어도 읽기와 쓰기 권한이 있어야 한다는 것이지만 정확한 퍼미션과 설정방법은 어플리케이션마다, DBMS마다 다를 수 있습니다.

### Spinner와 Spawner

주의 : 이 부분은 레일스 2.4+에서 해당되지 않습니다.

### Pushing the Code, Kicking the Tires

아직까지 실제 배포를 하지 않을 것이지만, 현재가지의 작업이 문제가 없다는 것을 확인하기 위해 소스코드를 서버로 복사할 것입니다. 이렇게 하는 이유는, 정식으로 배포하는 것보다 이런 식으로 했을 때 발생할 수 있는 문제점을 수정하기가 더 쉽기 때문입니다.

이제 서버로 소스를 복사하도록 하겠습니다:

$ cap deploy:update

이것은 소스코드를 서버로 복사하고 “current”라는 symlink가 해당 소스를 가리키도록 업데이트하지만, 이 과정은 실제로 어플리케이션 레이어를 시작하는 것은 아닙니다.

이 과정에서 실패가 발생하면 결과물을 면밀히 검토해서 잘 못된 원인을 알아낼 필요가 있습니다. 아마도 그 원인은, 퍼미션 에러일 수 있고, svn 실행파일을 찾지 못한 경우일 수도 있습니다. 이 시점에서 흔히 발생하는 에러는 해당 서버에 공개키가 없어서 subversion이 저장소 서버로 접근을 할 수 없기 때문입니다. 이러한 에러의 대부분은 deploy:check 단계에서 발견되었어야 하지만, 드문 예기는 하지만 공개키가 깨져서 발생할 수도 있습니다. 이러한 문제를 수정한 후에 성공할 때가지 “deploy:update” 계속 시도합니다.

일단 성공하면, 서버로 로그인해서 예를 들면, [deploy_to]/current 디렉토리로 이동합니다. 우선, 데이터베이스로 스키마를 로드할 필요가 있습니다. (주의: 이미 데이터베이스에 데이터가 존재할 경우에는 기존 데이터를 지워버릴 것이기 때문에 스키마 로드를 해서는 안됩니다. 이미 경고를 받았을 것입니다만…) 이것은 또한 운영(production) 데이터베이스의 설정이 정확한지를 검증하게 될 것입니다.

$ rake RAILS_ENV=production db:schema:load

위의 작업이 성공하면, 레일스가 데이터베이스로 “create table”과 “alter table” 명령을 보내게 되고 텍스트 문장들이 빠르게 스크롤 될 것입니다. 실패하게 되면, 그 이유를 밝혀내어야 하는데, 대개는 운영 데이터베이스의 설정이 잘 못된 경우일 것입니다(예를 들면, 데이터베이스명이 잘 못되었다든지, 사용자명이 잘 못되었다든지, 비밀번호가 잘 못된 경우일 것입니다). 레일스가 설치되지 않은 경우에도 실패할 수 있습니다. (대개 vendor 디렉토리에 레일스 복사본을 넣어 두어 서버에 레일스가 설치되었던 그렇지 않은 상황에서도 항상 가용한 상태로 만들어 둡니다. “rake rails:freeze:edge”와 “rake rails:freeze:gems”에 대해서 구글을 검새해 보기 바랍니다. 문제를 수정한 후에, 물론, 소스 저장소에도 수정된 내용을 커밋해야 합니다.

작업이 완료되면, 콘솔창을 시작할 때 실제 어플리케이션을 로드하게 되는지를 점검해 볼 수 있습니다:

$ rails c production

이 때 (현재 우분투 11.10 버전에서 작업 중임) 다음과 같은 에러가 발생할 수 있습니다.

/usr/local/rvm/rubies/ruby-1.9.3-p125/lib/ruby/1.9.1/irb/completion.rb:9:in `require’: cannot load such file — readline (LoadError)

해결방법은 http://blog.jasonmeridth.com/2010/11/25/readline-error-with-rvm-and-rails-3.html 를 참고하시 바랍니다.

(저의 경우는 /usr/local/rvm/src/ruby-1.9.3-p125/ext/readline 디렉토리로 이동하니 extconf.rb 파일이 있더군요.)

제대로 작동을 했다면 콘솔 창이 열리고 프롬프트가 보이게 될 것입니다. 콘솔 창에서 “app” 헬퍼 명령을 이용해서 HTTP 요청을 시뮬레이션할 수 있습니다. 자, 이제, 루트 URL을 불러와 보겠습니다:

>> app.get(“/”)

이것은 HTTP 상태코드를 반환할 것입니다. 200 또는 302( 또는 2xx 또는 3xx 코드, 어플리케이션에서 “/” url을 설정하지 않았다면 심지어 4xx 코드를 )를 반환한다면 제대로 세팅이 된 것입니다. 500번대 코드를 반환한다면 log/production.log 파일을 검토해서 그 원인을 알 수 있을 것입니다.

다음으로, 웹서버가 제대로 설정되어 정적 자원들을 제공해 줄 수 있는지를 점검해야 보겠습니다. 자바스크립트나 스타일시트 파일 중에 하나(여기서는 대부분의 레일스 어플리케이션에서 디폴트로 제공되기 때문에 prototype.js를 선택하겠습니다만, 원하는 것으로 어떤 것을 선택해도 무방합니다)를 선택합니다. 브라우저를 열고 어플리케이션 주소에 “javascript/prototype.js”을 추가한 후에 해당 URL로 이동합니다. 브라우저상에 prototype.js 파일의 내용을 보게 되면 제대로 셋팅이 된 것이지만, 그렇지 못할 경우, 브라우저에 그 내용이 보일 때까지, 웹서버의 구성내용을 면밀히 살펴보고 수정한 후에 웹서버를 재시동하여 확인하는 작업을 계속합니다. (이 부분은 웹서버 설정에 경험이 없는 경우 매우 힘든 과정이 될 수 있습니다. 도움이 필요한 경우, rails-deploy나 Capistrano 메일링 리스트에 질문을 해 보기 바랍니다.)

마지막으로, 어플리케이션 레이어를 시작하고 동적인 컨텐츠가 제대로 보이는지 확인해 보겠습니다. 로컬 머신에서 다음 task를 실행합니다:

$ cap deploy:start

이것은, 이미 작성해 둔 script/spin 스크립트를 이용해서, 어플리케이션 레이어를 cold상태(실행되지 않은 상태)로부터 실행하게 될 것입니다. 에러가 발생하면, 결과물을 자세히 검토하면 이유를 알 수 있을 것입니다. 아마도 script/spin 이 실행되지 않거나, 스크립트에 오타가 있거나, mongrel이 설치되지 않았기 때문일 수 있습니다.

deploy:start가 성공적으로 종료되면 고객과의 접점에 도달하게 될 것입니다. 이 시점까지 모든 것이 제대로 설정되었다면, 브라우저 상에 어플리케이션을 볼 수 있어야 합니다. 이제 브라우저에서 확인해 보고 결과를 알아보도록 합시다.

제대로 동작한다면, 정확히 기대했던 내용을 보게 될 것입니다. 반대로, 제대로 셋업이 되지 않았다면, 에러가 발생하거나 기대하지 않았던 것을 보게 될 것입니다. 대개는 여기서 “proxy” 에러를 보게 될 것입니다. 이것은 웹서버가 잘 못된 포트로 경유를 하려고 하거나 mongrel 이 실행되지 않거나 잘 못된 포트에서 실행된다는 의미입니다. 적어도 mongrel은 쉽게 점검해 볼 수 있습니다. 서버에 로그인해서 “curl http://localhost:8000/blah”(여기서 포트는 어떤 것이라도 상관없음)를 실행해 봅니다. “/blah”는 어플리케이션에서 적용가능한 라우트로 바꾸기 바랍니다. 기대했던 웹페이지를 보게되면 mongrel이 기대했던 포트에서 실행되고 있는 것입니다. 만약 curl이 불평을 하게 되면, 그렇지 않은 경우입니다. 이 때 “ps wwaux | grep mongrel”을 실행하면 mongrel이 현재 실행되고 있는지를 알려 줍니다.

그럼에도 불구하고 여전히 작동을 하지 않으면, 웹서버 로그, 레일스 로그, 기타 문제를 진단할 수 있는 비슷한 것들을 살펴 볼 필요가 있습니다. rails-deploy와 Capistrano 메일링 리스트에 질문을 해 보기 바랍니다. 그러나 이 때 가능한한 문제에 관련된 최대한의 정보를 제공해 주어야 합니다.

이 시점에서 제대로 작동한다면, 축하합니다. 어플리케이션 셋팅이 제대로 되어 서버에서 실행된 것입니다. 이제부터는 모든 일이 순조롭게 진행될 것입니다.

### 재시작과 재배포

이제 검증해야 할 두가지가 더 있습니다. 먼저, Capistrano가 어플리케이션 레이어를 성공적으로 재시작할 수 있는지를 확인해 보겠습니다.

$ cap deploy:restart

실행한 후에 브라우저에서 어플리케이션을 다시 보기 바랍니다. 제대로 작동했다면, 어플리케이션을 다시 볼 수 있어야만 합니다. 그렇지 못하면, 문제를 해결해야 할 필요가 있습니다.

마지막 검증작업으로, 전체를 배포해 보도록 하겠습니다. 이 시점까지 설정을 검증했고, 코드를 서버에 복사하고 어플리케이션 레이어를 재시작하고, 등과 같은 배포과정을 검증했습니다. 이제 이론적으로는 오류가 나서는 안 됩니다.

$ cap deploy

이 명령문이 작동을 해야 합니다. 그렇지 못하면 에러를 찾아서 수정하고 제대로 작동할 때까지 “cap deploy”를 반복 실행해야 합니다. 일단 문제없이 작동을 하게 될 때, 이후의 배포에서도 제대로 작동해야만 합니다.

이제 다음 튜토리얼을 공부할 단계가 되었습니다. 여기에서는 좀 더 수준 높은 토픽을 다루게 될 것입니다. 잘 못된 배포를 롤백하고, 이전의 배포를 제거하고 배포할 변경내용을 알게 될 것입니다.

### deploy:cold

주의: cold 배포에 의존하는 것은 추천되지 않는데, 웹 어프리케이션이 실패할 수 있고 `cold` 상태에 있게 되기 때문입니다. 유지관리와 배포를 수행하는 완벽한 task를 작성하도록 시도해 보기 바랍니다.

“잠시만요, 다른 블로그에서 이와 같은 내용을 읽었는데 거기에서는 cap deploy:cold를 사용해서 이 모든 일을 처리했습니다.”라고 합니다.

무엇보다도, deploy:cold는 좋지 않은 생각입니다. 이것이 이 튜토리얼에서 기술했던 내용을 하려고 시도했지만, 충분한 옵셔을 고려하지 않았고 구성에 대한 충분한 옵션도 고려하지 않았습니다. 새로운 머신에서 새로운 앱을 셋업하는 것을 일반적으로 자동화할 수는 없다는 결론에 내리게 됩니다. 특정 OS에 대한 개개의 셋업은 가능할 수 있지만(Mike Bailey의 Deprec recipes for setting up Ubuntu servers를 생각해 보기 바랍니다), 임의의 레일스 어플리케이션을 셋업하는 것에 대한 일반적인 해법을 찾으려고 하는 것은, 나의 책에서는 “바보 같은 실수”라고 말할 것입니다.

따라서, 새로운 어플리케이션을 셋업하는 것이 일관적인 작업이 될 수 없다는 것은 나쁜 소식이지만, 최소한 Capistrano에서는 예외입니다. 좋은 뉴스는 Capistrano가 모든 것을 수작업으로 하는 것보다 더 쉽게 작업을 할 수 있다는 것입니다. 최상의 뉴스는 일단 한번 셋업을 하고나면, 이후의 배포과정은 일괄적으로 처리할 수 있어서 단지 “cap deploy”하기만 하면 되는 것입니다.

그러나, 마지막으로, “deploy:cold”나 남게 됩니다. cold 배포를 원할 경우 할 수 있습니다. 오히려 그것이 더 신뢰성이 있고 유용할 경우가 있을 수 있습니다. 그러나 일반적으로 여기서는 cold 배포를 권하지 않습니다.


> *References:*
>
> – https://github.com/capistrano/capistrano/wiki/2.x-From-The-Beginning

글쓴이: 최효성

외과전문의,웹프로그래밍,컴퓨터 일러스트레이션 / Surgeon, Medical Illustration, Web Programmer

3 thoughts on “Capistrano 처음부터…”

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중