Ruby
1. 개요
1.1. 문서 개요
1.1.1. 목적
본 문서(Ruby 애플리케이션 개발 가이드)는 개방형 플랫폼 프로젝트의 서비스팩(Mysql, Cubrid, MongoDB, RabbitMQ, Radis, GlusterFS)을 Ruby 애플리케이션과 연동하여 사용하고 Ruby 애플리케이션을 배포하는 방법에 대해 제시하는 문서이다.
1.1.2. 범위
본 문서의 범위는 Open PaaS 프로젝트의 Ruby 애플리케이션 개발과 서비스팩 연동, 애플리케이션 배포에 대한 내용으로 한정되어 있다.
1.1.3. 참고 자료
http://rubyinstaller.org/ https://docs.pivotal.io/pivotalcf/buildpacks/ruby/index.html/ http://rubykr.github.io/rails_guides/getting_started.html/ https://github.com/brianmario/mysql2/ http://www.cubrid.org/manual/93/ko/api/ruby.html/ https://docs.mongodb.org/ecosystem/drivers/ruby/ http://rubybunny.info/articles/getting_started.html/ https://github.com/redis/redis-rb/ https://github.com/fog/fog/
2. Ruby 애플리케이션 개발가이드
2.1. 개요
개방형 플랫폼에 등록된 다양한 서비스팩을 Ruby언어로 작성된 애플리케이션과 바인딩하고 해당 애플리케이션에 바인딩된 서비스 환경정보(VCAP_SERVICES)를 이용하여 애플리케이션관 연동하고 각 서비스를 사용 할 수 있도록 Windows기반 환경에서 개방형 플랫폼에 배포할 Ruby 애플리케이션을 작성하는 방법을 설명한다.
2.2. 개발환경 구성
Ruby 애플리케이션 개발을 위해 다음과 같은 환경으로 개발환경을 구성 한다.
OS : Windows 7 64bit
Ruby : 1.9.3-p551
Framwork : Ruby On Rails 4.1.8
IDE : RubyMine 7.1.1
※ CubridDB의 Ruby 드라이버 최신 지원 버전이 Ruby 1.9.3 까지 지원하여 해당 버전을 선택하였다. 각 서비스별 지원 되는 드라이버(또는 Gem)에 맞는 Ruby 버전을 사용하길 권장한다. ※ Ruby IDE는 개별 선택하여 사용한다.
2.2.1. Ruby & Ruby On Rails설치
다운로드
RubyInstallers : Ruby 1.9.3-p551
DEVELOPMENT KIT : DevKit-tdm-32-4.5.2-20111229-1559-sfx
2) Ruby 설치
Ruby 1.9.3-p551.exe 더블클릭하여 설치를 실행한다.
“OK” 버튼 클릭
“I accet the License” 선택 후 “Next” 버튼 클릭
“Add Ruby executables to your PATH” 선택 후 “Install” 버튼 클릭
“Finish” 버튼을 클릭하여 Ruby 설치를 종료한다.
3) DEVELOPMENT KIT 설치
DevKit-tdm-32-4.5.2-20111229-1559-sfx.exe을 더블클릭하여 설치를 실행한다.
설치할 폴더를 지정하고 “Extract”버튼을 클릭한다.
Windows의 CMD 창을 실행하여 DevKit 설치 폴더로 이동한다.
ruby dk.rb init
“ruby dk.rb init” 명령을 실행하여 “config.yml” 파일을 생성한다.
ruby dk.rb install
“ruby dk.rb install” 명령을 실행하여 DevKit을 설치한다.
“ruby –v” 명령을 실행하여 루비 버전을 확인한다.
4) Ruby On Rails 설치
“gem update rdoc” 명령을 실행하여 rdoc gem을 업데이트한다.(미 실행시 rails install시 에러가 발생 할 수 있다.)
“gem install rails –v 4.1.8” 명령을 실행하여 rails을 설치한다.
“rails –v” 명령을 사용하여 rails의 버전을 확인한다.
2.3. 개발
Ruby 샘플 애플리케이션을 개발하기 위한 애플리케이션의 생성과 환경설정, VCAP_SERVICES 정보의 획득 및 각 서비스의 연동 방법에 대하여 설명한다.
샘플 애플리케이션 다운로드
완성된 샘플 애플리케이션은 아래 링크의 /OpenPaaSSample/ruby-sample-app 에서 받을 수 있다.
http://extdisk.hancom.com:8080/share.cgi?ssid=0icB5ZW#0icB5ZW
2.3.1. 애플리케이션 생성
1) Rails 애플리케이션 생성(bundle install 제외)
2) 자동 생성 폴더 및 파일 정의
2.3.2. 애플리케이션 환경설정
해당 예제는 Ruby 1.9.3을 기준으로 각 드라이버의 버전을 명시적으로 선택하여 설치하였습니다. ./Gemfile 수정(설정)시 설치된 Ruby의 버전에 맞는 젬을 설치하도록 권장합니다.
1) ./Gemfile 수정
각 서비스에서 사용할 드라이버 및 필요한 젬을 정의한다.
※ Windows 환경에서 Cubrid 드라이버는 Cubrid의 라이브러리를 사용하므로 해당 Ruby 버전에 맞는 Cubrid를 설치하여 라이브러리를 참조 할 수 있도록 하여야한다. ※ 해당 샘플은 Ruby 1.9.3(64bit 미지원) 이므로 CUBRID-Windows-x86(32bit)버전을 설치하였다.
2) 젬 설치
Gemfile에 정의된 젬을 설치한다.
3) ./config/application.rb 수정
애플리케이션의 환경설정
4) ./config/routes.rb 수정
Request URL과 컨트롤러의 매핑 설정
``` Rails.application.routes.draw do
인덱스(root) 페이지 설정
root 'static#login'
정적페이지설정(.html)
get '/login' => 'static#login' get '/main/:org_id' => 'static#main' get '/manage' => 'static#manage' ...(중략)...
기능별 API Path 설정
[HTTP메서드] ‘[Uri]’ => ‘[Controller#메서드]’
get 'org-chart/:org_id/mysql' => 'org_chart_mysql#index' get 'org-chart/:org_id/cubrid' => 'org_chart_cubrid#index' get 'org-chart/:org_id/mongo' => 'org_chart_mongo#index' ...(생략)
Rails.application.configure do
Settings specified here will take precedence over those in config/application.rb.
...(중략)...
Show full error reports and disable caching.
예외 발생처리 기능 설정(Json형으로 반환 받기위함)
config.consider_all_requests_local = false config.action_controller.perform_caching = false
...(중략)...
public static html page view
./public 폴더 접근 허용 여부 설정(js, css, image 정적 리소스)
config.serve_static_assets = true
Disable request forgery protection in test environment
authenticity_token ignore
Post, Put 메서드 호출시 인증 절차 설정
config.action_controller.allow_forgery_protection = false end
Rails.application.configure do
Settings specified here will take precedence over those in config/application.rb.
...(중략)...
Disable request forgery protection in test environment
authenticity_token ignore
Post, Put 메서드 호출시 인증 절차 설정
config.action_controller.allow_forgery_protection = false
{ "VCAP_SERVICES": { "p-mysql": [ { "credentials": { "hostname": "10.30.40.63", "jdbcUrl": "jdbc:mysql://10.30.40.63:3306/cf_ea68784e_3de6_439d_afc1_d51b4e95627b?user=ZwCFnQRiT3KANqHZ\u0026password=qs7oqi4nSvWq6UQa", "name": "cf_ea68784e_3de6_439d_afc1_d51b4e95627b", "password": "qs7oqi4nSvWq6UQa", "port": 3306, "uri": "mysql://ZwCFnQRiT3KANqHZ:qs7oqi4nSvWq6UQa@10.30.40.63:3306/cf_ea68784e_3de6_439d_afc1_d51b4e95627b?reconnect=true", "username": "ZwCFnQRiT3KANqHZ" }, "label": "p-mysql", "name": "sample-mysql-instance", "plan": "100mb", "tags": [ "mysql" ] } ], ...(이하 생략)...
cf-app-utils 라이브러리 사용
require 'cf-app-utils'
module VcapService class Vcap
클래스 초기화 메서드
end end
cf-app-utils을 사용하지 않고 직접 환경 변수에 접근하여 Json형태로 정보를 읽어올수 있다.
vcap_services = JSON.parse(ENV['VCAP_SERVICES'])
require 'vcap' module Connector class MysqlService < VcapService::Vcap
end end
encoding: UTF-8 # Encoding 지정(한글지원)
require 'mysql_service' # mysql_service 클래스 추가 (각 서비스별 클래스 추가부분) class OrgChartMysqlController < ApplicationController before_action :db_connection # 전처리 메소드 호출(DB 접속) before_action :set_param, only: [:index] before_action :set_org, only: [:index] after_action :db_close # 후처리 메소드 호출 (DB 닫음)
Org 그룹 목록 조회 메서드
def index if @org == nil render json: {error: 'request value wrong'}, status: 400 else render json: {org: @org, groups: @client.query(@query.group_index(@param[:org_id]))} end end
메소드가 호출되기전 서비스 접속
def db_connection @client = Connector::MysqlService.new.connector #서비스 연동 클래스를 호출하여 접속정보를 획득하고 이를 클래스 변수로 선언하였다. @query = Connector::MysqlQuery.new end
메소드 호출이 끝난후 서비스 닫음
def db_close @client.close end
Param 처리 메소드
def set_param @param = {:org_id => params[:org_id]} end
Org 정보 조회 메서드
def set_org begin @org = @client.query(@query.org_show(@param[:org_id])).first rescue @org = nil end end end
require 'vcap' module Connector class CubridService < VcapService::Vcap
end end
encoding: UTF-8 # Encoding 지정(한글지원)
require 'cubrid_service' # cubrid_service 클래스 추가 (각 서비스별 클래스 추가부분) class OrgChartMysqlController < ApplicationController before_action :db_connection # 전처리 메소드 호출(DB 접속) before_action :set_param, only: [:index] before_action :set_org, only: [:index] after_action :db_close # 후처리 메소드 호출 (DB 닫음)
Org 그룹 목록 조회 메서드
def index if @org == nil render json: {error: 'request value wrong'}, status: 400 else result = @client.query(@query.group_index(@param[:org_id])) groups = [] while rs = result.fetch_hash rs['label'] = rs['label'].to_s.force_encoding('UTF-8') rs['desc'] = rs['desc'].to_s.force_encoding('UTF-8') rs['thumb_img_name'] = rs['url'].to_s.force_encoding('UTF-8') rs['thumb_img_path'] = rs['url'].to_s.force_encoding('UTF-8') rs['url'] = rs['url'].to_s.force_encoding('UTF-8') groups.push(rs) end render json: {org: @org, groups: groups} end end
메소드가 호출되기전 서비스 접속
def db_connection @client = Connector::CubridService.new.connector #서비스 연동 클래스를 호출하여 접속정보를 획득하고 이를 클래스 변수로 선언하였다. @query = Connector::MysqlQuery.new end
메소드 호출이 끝난후 서비스 닫음
def db_close @client.close end
Param 처리 메소드
def set_param @param = {:org_id => params[:org_id]} end
Org 정보 조회 메서드
def set_org begin @org = @client.query(@query.org_show(@param[:org_id])).first rescue @org = nil end end end
require 'vcap' module Connector class MongoService < VcapService::Vcap
end end
encoding: UTF-8 # Encoding 지정(한글지원)
require ‘mongo_service’ # mongo_service 클래스 추가 (각 서비스별 클래스 추가부분) class OrgChartMysqlController < ApplicationController before_action :db_connection # 전처리 메소드 호출(DB 접속) before_action :set_param, only: [:index] before_action :set_org, only: [:index]
Org 그룹 목록 조회 메서드
def index if @org == nil render json: {error: 'request value wrong'}, status: 400 else result = @client[:Groups].find(:orgId => BSON::ObjectId(@param[:orgId])).sort({ _id: -1 } ) groups=[] result.each do |rs| rs['created'] = Date.strptime(rs['created'].as_json['t'].to_s,'%s').strftime('%F') rs['modified'] = Date.strptime(rs['modified'].as_json['t'].to_s,'%s').strftime('%F') rs_new = {'id' => rs.delete('_id').to_s, 'org_id' => rs.delete('orgId').to_s, 'parent_id' => rs.delete('parentId').to_s, 'label' => rs.delete('label').to_s, 'desc' => rs.delete('desc').to_s, 'thumb_img_name' => rs.delete('thumbImgName').to_s, 'thumb_img_path' => rs.delete('thumbImgPath').to_s, 'url' => rs.delete('url').to_s, 'created' => rs.delete('created').to_s, 'modified' => rs.delete('modified').to_s }.merge(rs) groups.push(rs_new) end render json: {org: @org, groups: groups} end end
메소드가 호출되기전 서비스 접속
def db_connection @client = Connector:: MongoService.new.connector #서비스 연동 클래스를 호출하여 접속정보를 획득하고 이를 클래스 변수로 선언하였다. end
Param 처리 메소드
def set_param @param = {:orgId => params[:org_id]} end
Org 정보 조회 메서드
def set_org begin
end end
require 'vcap' module Connector class RedisService < VcapService::Vcap
end end
encoding: UTF-8 # Encoding 지정(한글지원)
require ‘redis_service’ # redis_service 클래스 추가 (각 서비스별 클래스 추가부분) class LoginController < ApplicationController
선처리 메소드
before_action :redis_connection # Redis 서버 접속
def login id = params[:id] pwd = params[:password]
end
def logout key = cookies['login_cookie'].to_s p key @redis.del(key) render json: {} end
def redis_connection @redis = Connector::RedisService.new.connector #서비스 연동 클래스를 호출하여 접속정보를 획득하고 이를 클래스 변수로 선언하였다. end end
require 'vcap' module Connector class RabbitmqService < VcapService::Vcap
end end
encoding: UTF-8 # Encoding 지정(한글지원)
require ‘rabbitmqservice’ # rabbitmq_service 클래스 추가 (각 서비스별 클래스 추가부분) class StatusController < ApplicationController before_action :rabbit connection # RabbitMQ 서버 접속 def status
end
def rabbit_connection @conn = Connector::RabbitmqService.new.connector #서비스 연동 클래스를 호출하여 접속정보를 획득하고 이를 클래스 변수로 선언하였다.
end end
require 'vcap' module Connector class Glusterfs < VcapService::Vcap
end end
encoding: UTF-8 # Encoding 지정(한글지원)
require ‘glusterfs_service’ # glusterfs_service 클래스 추가 (각 서비스별 클래스 추가부분) class UploadController < ApplicationController before_filter :authenticate # 메서드를 호출하기전 인증여부를 확인합니다. before_action :gs_connection # 파일 업로드를 위한 Swift 인증정보를 획득합니다.
파일을 업로드 합니다.
def upload @img = params[:file]
end
def gs_connection @service = Connector::Glusterfs.new.connector #서비스 연동 클래스를 호출하여 접속정보를 획득하고 이를 클래스 변수로 선언하였다.
end end
applications:
name: ruby-sample-app # 애플리케이션 이름
memory: 512M # 애플리케이션 메모리 사이즈
instances: 1 # 애플리케이션 인스턴스 개수
path: . # 애플리케이션 위치
command: bundle exec rails server -p $PORT # 애플리케이션 배포 후 실행 명령어
```
※애플리케이션 스테이징시 할달 받은 포트가 환경변수로 등록되어있다. 이 $PORT는 애플리케이션의 상태 체크에도 사용되므로 위와 같이 포트를 지정할 것을 권장한다.
2) 개방형 플랫폼 로그인
3) 개방형 플랫폼 서비스 생성
4) 개방형 플랫폼 애플리케이션에 서비스 바인딩 및 애플리케이션 시작
※최신 빌드팩은 Ruby 1.9.3을 지원하지 않기 때문에 ruby-buildpack 1.3.1 버전을 사용하여 배포를 진행합니다. 개방형 플랫폼에서 지원하는 기본 빌드팩을 사용할경우 –b 옵션을 제외
※애플리케이션 배포절차를 윈도우 머신에서 수행하는 경우(cf cli를 윈도우 머신에 설치하여 사용하는 경우), 애플리케이션 시작('cf start')이 제대로 되지 않을 수 있습니다. 이 때는 bin 폴더내의 3개의 파일 bundle, rake, rails를 유닉스용으로 변환하여 'cf push' 부터 다시 진행합니다. 파일 변환 절차는 다음을 따릅니다.
윈도우 커맨드 창을 열어 애플리케이션 폴더로 이동합니다.
(방법1.) 다음의 url에서 dos2unix를 다운로드 하고 압축을 해제하여 dos2unix.exe파일을 샘플 어플리케이션의 bin 폴더로 이동합니다. http://sourceforge.net/projects/dos2unix/files/latest/download
(방법2.) 샘플 어플리케이션을 'git clone'한 사용자는 다음의 명령어를 이용하여 애플리케이션 폴더 내의 dos2unix 파일의 파일명을 변경합니다. 'rename' 명령어를 사용할 수 없다면, 'ren' 명령어를 대신 사용하거나 직접 파일명을 'dos2unix.exe'로 변경하여도 무방합니다.
rename dos2unix dos2unix.exe
다음 명령어를 이용하여 bin 폴더 내의 3개의 파일을 유닉스 파일로 변환합니다.
[4) 개방형 플랫폼 애플리케이션에 서비스 바인딩 및 애플리케이션 시작] 절차를 다시 수행합니다.
2.5. 테스트
Rspec을 이용한 Ruby 애플리케이션 테스트
1) 폴더 및 파일 정의
2) 테스트 실행
bundle exec rspec ※정상적인 테스트 진행을 위해서는 해당 서비스와 접속이 가능하여야 한다.(프록시, 터널링 등..)
Last updated