필자는 최근 맥 서버(OSX El Capitan)로 레일스 프로젝트를 배포하는 작업을 1주일간에 걸쳐 진행했었다. 구글 검색시에도 이와 관련된 자료가 많지 않아서, 맥의 서비스 관리 툴인 launchd
에 대한 공부와 함께 수차례의 시행착오 끝에 성공적으로 배포작업을 완료할 수 있었다. 이 글을 읽는 독자가 혹 필자와 같이 맥 서버로 레일스 프로젝트를 배포해야할 상황에 닥칠 때 이 글이 도움이 될 수 있기를 바란다.
Xcode Command Line Tools 설치
가장 먼저 Xcode Command Line Tools
를 설치해야 한다. 아래의 명령을 실행할 때, 설치되어 있지 않을 경우 아래와 같은 에러가 발생한다.
$ xcode-select -p
xcode-select: error: unable to get active developer directory, use \`xcode-select --switch\` to set one (or see \`man xcode-select\`)
--install
옵션을 이용하면 설치할 수 있다.
$ xcode-select --install
rbenv 설치
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ . ~/.bash_profile
# 제대로 설치되었는지 확인하기
$ type rbenv
rbenv is a function
ruby-build 설치
rbenv
을 이용하여 루비를 설치하기 위해서는 ruby-build
라는 플러그인을 설치해야 한다.
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
이제 설치 가능한 루버 버전 목록을 보기 위해서는 아래와 같은 명령을 실행한다.
$ rbenv install -l
노트 : 원하는 버전이 없는 경우는
cd ~/.rbenv/plugins/ruby-build && git pull
명령을 실행하여ruby-build
를 업데이트 한다.
ruby 설치
$ rbenv install 2.2.3
$ rbenv global 2.2.3
$ rbenv rehash
Homebrew 설치
OSX
용 패키지 매니저인 homebrew
를 설치한다.
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
노트 : 아래와 같은 경고문이 보이지만 비밀번호를 입력하고 계속 진행한다. WARNING: Improper use of the sudo command could lead to data loss or the deletion of important system files. Please double-check your typing when using sudo. Type “man sudo” for more information. To proceed, enter your password, or type Ctrl-C to abort.
Nginx 설치
homebrew
를 이용하여 nginx
를 설치한다.
$ brew install nginx
설치 후 안내문은 아래와 같다.
Docroot is: /usr/local/var/www
The default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 so that nginx can run without sudo. nginx will load all files in /usr/local/etc/nginx/servers/.
To have launchd start nginx at login:
mkdir -p ~/Library/LaunchAgents
ln -sfv '/usr/local/opt/nginx/*.plist ~/Library/LaunchAgents'
Then to load nginx now:
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.nginx.plist
Or, if you do not want/need launchctl, you can just run: nginx
$ mkdir -p ~/Library/LaunchAgents
$ ln -sfv '/usr/local/opt/nginx/*.plist ~/Library/LaunchAgents'
Nginx 시작하기
$ nginx
노트 : 설치 후 안내문를 보면 기본 포트가 8080임을 알 수 있다. 따라서 브라우저에서 서버로 연결하기 위해서는 url 주소에 8080 포트를 추가해야 한다.
80 포트로 변경하기 위해서는 /usr/local/etc/nginx/nginx.conf
파일의 36번 코드라인의 8080을 80으로 변경한다. 80 포트로 변경한 후 nginx
를 다시 실행한다. 이 때는 sudo
로 실행한다.
$ sudo nginx
nginx
작동 명령을 요약하면 아래와 같다.
$ sudo nginx # 시작
$ sudo nginx -s stop # 중단
$ sudo nginx -s quit
$ sudo nginx -s reopen
$ sudo nginx -s reload # 재시작
MySQL 설치
$ brew install mysql
설치 후 안내문은 아래와 같다.
A "/etc/my.cnf" from another install may interfere with a Homebrew-built server starting up correctly.
To connect:
mysql -uroot
To have launchd start mysql at login:
ln -sfv '/usr/local/opt/mysql/*.plist ~/Library/LaunchAgents'
Then to load mysql now: launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist
Or, if you do not want/need launchctl, you can just run:
$ mysql.server start $ ln -sfv '/usr/local/opt/mysql/*.plist ~/Library/LaunchAgents'
$ mysql.server start
$ mysql_secure_installation
노트 : Enter current password for root (enter for none): 와 같은 프롬프트가 보이면 그냥 엔터키를 치고, 이어서 나타나는 Set root password? [Y/n] 프롬프트에서는 Y 값을 입력하여 루트 비밀번호를 설정한다. Remove anonymous users? [Y/n] 프롬프트가 보이면 Y 값을 입력한다. Disallow root login remotely? [Y/n] 프롬프트에서도 Y 값을 입력한다. Remove test database and access to it? [Y/n] 프롬프트에서도 Y 값을 입력한다. Reload privilege tables now? [Y/n] 프롬프트에서도 Y 값을 입력하고 작업을 종료 한다.
참고 : 서버에서 sudo mysql.server start 명령실행시, ERROR! The server quit without updating PID file와 같은 에러가 발생하면 서버에서 sudo chmod -R 777 /usr/local/var/mysql/ 명령을 실행하면 해결된다. 이것은 웹서버로 배포시 mysql.socket 접속 에러를 유발한다.
ImageMagick 설치
$ brew install imagemagick
Node.js 설치
$ brew install node
배포용 사용자 계정 생성하기
1. deployer 배포 계정의 추가
레일스 프로젝트를 서버로 배포하기 위해 deployer
라는 시스템 사용자 계정을 생성한다. http://www.techradar.com/how-to/computing/apple/terminal-101-creating-new-users-1305687
노트 : 계정 삭제 How to Delete a Local User Using Command Line on Mac OS X
# 사용자계정 생성
$ LastUserID=$(dscl . -list /Users UniqueID | awk '{print $2}' | sort -n | tail -1)
$ NextUserID=$((LastUserID + 1))
$ sudo dscl . create /Users/deployer
$ sudo dscl . create /Users/deployer RealName "Rails Deployer"
$ sudo dscl . passwd /Users/deployer
$ sudo dscl . create /Users/deployer hint "Password Hint"
$ sudo dscl . create /Users/deployer UniqueID $NextUserID
# 그룹 생성
$ LastGroupID=$(dscl . readall /Groups | grep PrimaryGroupID | awk '{ print $2 }' | sort -n | tail -1) $ NextGroupID=$(($LastGroupID + 1 ))
$ sudo dscl . create /Groups/deployer
$ sudo dscl . create /Groups/deployer RealName "Rails Deployer Group" $ sudo dscl . create /Groups/deployer passwd "*"
$ sudo dscl . create /Groups/deployer gid $NextGroupID
# 사용자를 그룹에 등록하고 사용자 환경 셋팅
$ sudo dscl . create /Users/deployer PrimaryGroupID $NextGroupID
$ sudo dscl . create /Users/deployer UserShell $(which bash)
$ sudo dscl . create /Users/deployer NFSHomeDirectory /Users/deployer $ sudo cp -R /System/Library/User\ Template/English.lproj /Users/deployer
$ sudo chown -R deployer:deployer /Users/deployer
로그인 화면으로부터 deployer
사용자 계정 숨기기
$ sudo defaults write /Library/Preferences/com.apple.loginwindow HiddenUsersList -array-add deployer
로그인 화면으로부터 deployer
사용자 계정 보이게 하기
$ sudo defaults delete /Library/Preferences/com.apple.loginwindow HiddenUsersList
노트 : 로컬 터미널에서
ssh
로 원격 서버로 접속하기 위해서는 서버의 시스템환경설정의 공유 메뉴에서 원격로그인 항목을 선택한 후Rails Deployer
또는Rails Deployer Group
을 추가해 주어야 한다.ssh
를 이용하여 비밀번호 없이 원격서버로 접속하기 위해서 로컬 터미널의 공개키를 원격 서버로 복사해 준다.
$ ssh-copy-id -i ~/.ssh/id_rsa.pub deployer@REMOTE_SERVER_IP
이후부터는 ssh deployer@REMOTE_SERVER_IP
로 접속시 비밀번호를 입력하지 않아도 된다. 원격 서버에 deployer
계정으로 접속한 후 sudo
명령을 사용할 때 비밀번호를 입력하지 않도록 하기 위해서는 아래와 같이 명령을 실행하여 /etc/sudoers
파일을 열고,
$ sudo visudo
66번 라인에 아래와 같이 추가해 준다.
deployer ALL=(ALL) NOPASSWD= ALL
2. DB 사용자 계정의 추가
레일스 프로젝트에서 사용할 MySQL 데이터베이스에 접속하기 위한 DB 사용자 계정을 생성한다.
$ mysql --user=root -p mysql
mysql> CREATE USER 'deployer'@'localhost' IDENTIFIED BY 'some_pass';
mysql> GRANT ALL PRIVILEGES ON \*.\* TO 'deployer'@'localhost';
mysql> \q # 종료
방금 생성한 계정으로 MySQL
서버로 접속해 본다.
$ mysql -u deployer -p
Unicorn 서비스 등록하기
맥 서버로 배포할 때 가장 어려웠던 것은 unicorn
서비스를 실행하는 것이었다.
우선, 맥에서 서비스(데몬)를 실행하기 위해서는 launchd
이라는 오픈소스 통합 서비스 관리 프레임워크에 대한 이해가 필요하다.
참고 : Useful Mac OS X shell commands and their Linux equivalents
Mac OSX에 Unicorn 서비스 등록하기
이를 위해서 아래의 열거한 링크를 참고했고, launchd
에 대해 공부한 내용을 정리해 놓았다.
- Rails 3 Deploy With Nginx Unicorn on OSX
- How to start/stop/restart launchd services from the command line?
- Start unicorn on OSX Startup
launchd란?
위키피디아의 관련 내용을 참고하면 도움이 된다.
정의 : launchd은 오픈소스 통합 서비스 관리 프레임워크로써 데몬, 애플리케이션, 프로세스, 스크립트를 시작, 중단, 관리해 준다. 애플의 Dave Zarzycki가 만들었고 맥 OSX 타이거에서 처음으로 도입되어 아파치 라이센스하에 보호 받고 있다.
launchd
시스템은 두개의 프로그램으로 구성되어 있다.
1. launchd
시스템과 사용자 레벨에서 각종 데몬을 관리해 준다. launchd은 두 가지 주요 기능을 가지고 있다.
- 시스템 부팅
- 각종 서비스의 로드와 관리
2. /Library/LaunchDaemons와 ~/Library/LaunchAgents
LaunchDaemons
폴더에는 루트 권한으로 백그라운드 프로세스를 실행하는 서비스 항목들이 위치한다. LaunchAgents
폴더에는 사용자 권한으로 실행되는 에이전트 애플리케이션 작업들이 위치한다.
3. launchctl
launchd
과 통신하는 커맨드라인 애플리케이션이다. launchd
의 작업을 정의하는 property list
파일(.plist
)을 읽어 들여 데몬을 로드하거나 언로드하여 특정 서비스 작업을 시작하거나 중단하게 된다. launchd
이 동작하는 상태에서 서비스의 제어는 launchctl
애플리케이션이 수행한다. launchctl
은 커맨드라인에서 표준입력 또는 인터액티브 상태로 직접 명령을 읽어 들이게 된다. 루트권한으로 실행할 때 시스템 전체에 변화를 줄 수 있다. /etc/launchd.conf
파일에 저장된 launchctl
명령은 영구적으로 실행될 수 있다. lauchctl
은 IPC
방식으로 launchd
과 통신하게 된다.
Property List(Plist)
plist
는 launchd
이 프로그램 설정을 위해 사용하는 파일이다. launchd
이 특정 폴더를 스캔하거나 launchctl
이 특정 작업을 실행할 때 프로그램이 실행되는 방법을 기술해 놓은 plist
파일을 읽게 된다. plist
파일에서 자주 사용하는 키는 아래와 같다.
Key | Type | Description |
---|---|---|
Label
|
String | The name of the job. By convention, the job label is the same as the plist file name, without the .plist extension. Required. |
Program
|
String |
A path to an executable. Useful for simple launches. At least one of Program orProgramArguments is required.
|
ProgramArguments
|
Array of strings |
An array of strings representing a UNIX command. The first string is generally a path to an executable, while latter strings contain options or parameters. At least one ofProgram or ProgramArguments is required.
|
UserName
|
String (defaults to root or current user)
|
The job will be run as the given user, who may (or may not) be the user who submitted it to launchd. |
OnDemand (Deprecated since 10.5)
|
Boolean (defaults to YES )
|
Deprecated as of 10.5 with the more powerful KeepAlive option. A boolean flag that defines if a job runs continuously or not.
|
RunAtLoad
|
Boolean (defaults to NO )
|
A boolean flag that defines if a task is launched immediately when the job is loaded into launchd. |
StartOnMount
|
Boolean (defaults to NO )
|
A boolean flag that defines if a task is launched when a new filesystem is mounted. |
QueueDirectories
|
Array of strings |
Watch a directory for new files. The directory must be empty to begin with, and must be returned to an empty state before QueueDirectories will launch its task again.
|
WatchPaths
|
Array of strings | Watch a filesystem path for changes. Can be a file or folder. |
StartInterval
|
Integer | Schedules job to run on a repeating schedule. Indicates number of seconds to wait between runs. |
StartCalendarInterval
|
Dictionary of integers or Array of dictionaries of integers | Job scheduling. The syntax is similar to cron. |
RootDirectory
|
String | The job will be chrooted into this directory before execution. |
WorkingDirectory
|
String | The job will be chdired into this directory before execution. |
StandardInPath , StandardOutPath , StandardErrorPath
|
String | Keys to determine files for input and output for the launched process. |
LowPriorityIO
|
Boolean | Tells the kernel that this task is of a low priority when doing filesystem I/O. |
AbandonProcessGroup
|
Boolean (defaults to NO )
|
A boolean flag that defines whether subprocesses launched from a task launched by launchd will be killed when the task ends. Useful where a short-lived task starts a long-lived subtask, but may result in zombie processes. |
참고 : http://launchd.info
데몬이란?
사용자 입력이 필요없이 백그라운드에서 실행되는 프로그램을 말한다.
데몬과 에이전트
launchd
은 데몬과 에이전트로 구분된다. 주된 차이점은, 에이전트가 로그인한 사용자의 권한으로 실행되는 반면, 데몬은 루트 사용자나 User
키로 지정한 사용자의 권한으로 실행된다는 것이다.
작업 정의
데몬 또는 에이전트의 실행동작은 프로퍼티 리스트(property list)라는 특수한 형태의 XML 파일에 정의되어 있다. 특정 작업이 저장되는 위치에 따라 데몬이 되기도 하고 에이전트가 되기도 한다. 특히, 운영시스템의 동작에 중요한 역할을 하는 작업 정의는 /System/Library
디렉토리에 저장되어 있다. 결코 이 디렉토리에 대해서 개인적인 데몬이나 에이전트를 정의해서는 안된다. 모든 사용자들에게 관련이 있는 작업에 대한 정의는 /Library
디렉토리에 저장하도록 한다. 특정 사용자에 대한 작업 정의는 해당 사용자의 ~/Library
디렉토리에 저장하도록 한다.
정의된 작업의 자동 로딩
시스템이 부팅될 때 루트 launchd
프로세스는 데몬 디렉토리인 /System/Library/LaunchDaemons
와 /Library/LaunchDaemons
에 정의된 작업을 검색하여 각 작업에 정의된 Disabled
키와 override database
의 내용에 따라 해당 작업을 로드할지 결정하게 된다. 특정 사용자가 로그인하게 될 경우는 새로운 launchd
프로세스가 시작되어 에이전트 디렉토리인/System/Library/LaunchAgents
, /Library/LaunchAgents
, ~/Library/LaunchAgents
에 정의된 작업을 검색하여 각 작업에 정의된 Disabled
키와 override database
의 내용에 따라 해당 작업을 로드할지 결정하게 된다.
작업 로딩과 시작
특정 작업을 로딩한다고 해서 반드시 해당 작업이 시작되는 것은 아니다. 해당 작업의 시작여부는 작업 정의에 따라 결정된다. 즉, RunAtLoad
또는 KeepAlive
가 명시되어 있는 경우에만 작업이 로딩될 때 조건에 무관하게 해당 작업이 시작된다.
lunchy 젬의 소개
레일스 배포시 필요한 애플리케이션 서버 unicorn
서비스를 맥 서버에서 편리하게 사용하도록 도와주는 젬이다. capistrano
를 이용하여 배포할 때 capistrano-unicorn-nignx
젬을 이용하면 unicorn
과 nginx
설정 파일을 편리하게 서버로 배포할 수 있는데, 필자는 이 젬에 lunchy
젬을 추가하고 몇가지 unicorn
서비스 관련 부분을 수정하여 capistrano-unicorn-nginx-osx
이라는 젬을 제작하여 <a href="https://rubygems.org/gems/capistrano-unicorn-nginx-osx" target="_blank">rubygems.org</a>
로 배포해 놓았다.
Unicorn Plist 작성
맥 서버에서 unicorn
서비스를 launchd
의 에이전트로 사용하기 위해서 plist
파일을 작성해야 한다. 파일명을 unicorn.plist.erb
로 정하고 내용 중에 ‘erb’
코드를 이용하여 배포시 사용하는 변수를 지정할 수 있도록 했다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key><string>/Users/<%= fetch(:deploy_user)%>/.rbenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
</dict>
<key>Label</key><string>apps.<%= fetch(:application)%>.unicorn</string>
<key>KeepAlive</key><true/>
<key>ProgramArguments</key>
<array>
<string>/Users/<%= fetch(:deploy_user)%>/.rbenv/shims/unicorn</string>
<string>-c</string>
<string>/Users/<%= fetch(:deploy_user)%>/apps/<%= fetch(:application) %>/shared/config/unicorn.rb</string>
<string>-E</string>
<string>production</string>
</array>
<key>RunAtLoad</key><true/>
</dict>
</plist>
여기서 사용한 :deploy_user
변수는 레일스 프로젝트의 config/deploy.rb
파일에서 지정해 놓으면 된다.(여기서는 배포 계정을 deployer
로 지정했음)
# Deploy Account
set :deploy_user, 'deployer'
소스코드를 보면 알 수 있듯이 루비 버전관리자로 rbenv을 사용하였고, unicorn 젬이 설치될 때 사용하게 되는 unicorn 실행파일명 앞에 shims 경로를 추가해 주었다. 이 파일은 capistrno-unicorn-nginx-osx 젬 소스에 포함되어 있다. 또한 배포시에 이 파일을 업로드하는 코드를 아래와 같이 작성하였다.
desc 'Setup Unicorn initializer'
task :setup_initializer do
on roles :app do
execute :mkdir, '-pv', File.dirname(fetch(:unicorn_config))
upload! template('unicorn.rb.erb'), fetch(:unicorn_config)
sudo_upload! template('unicorn.plist.erb'), fetch(:unicorn_plist)
end
end
6번 코드라인에 unicorn.plist.erb
파일을 template
메소드로 렌더링한 후 ~/Library/LaunchAgents/unicorn.plist
경로로 업로드한다. 이 소스는 capistrno-unicorn-nginx-osx
젬 파일로 업데이트되어 있다. 동일 파일 내에 :unicorn_config
와 :unicorn_plist 변수가 정의되어 있다.
set :unicorn_config, -> { unicorn_default_config_file }
set :unicorn_plist, -> { unicorn_default_launchd_plist }
레일스 프로젝트의 배포 준비
이제는 배포할 프로젝트를 capistrano
젬을 이용하여 배포해 보자.
우선 Gemfile
파일을 열고 관련 젬을 추가하고 bundle install
한다.
# Use Unicorn as the app server
gem 'unicorn'
# Use Capistrano for deployment
gem 'capistrano-rails', group: :development
gem 'capistrano-rbenv' # required
gem 'capistrano-rbenv-install'
gem 'capistrano-unicorn-nginx-osx', '~> 3.4.0.1' <====
gem 'capistrano-upload-config'
gem 'capistrano-safe-deploy-to'
gem 'capistrano-ssh-doctor'
gem 'capistrano-rails-console'
gem 'capistrano-rails-collection'
gem 'capistrano-rails-tail-log'
gem 'capistrano-faster-assets'
gem 'capistrano3-delayed-job', '~> 1.0' gem 'daemons'
1. 배포용 작업 파일 생성하기
$ cap install
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile
Capified
2. Capfile의 수정
프로젝트 루트에 있는 Capfile을 열고 아래와 같이 변경한다.
# Load DSL and set up stages
require 'capistrano/setup'
# Include default deployment tasks
require 'capistrano/deploy'
# require 'capistrano/rails' or
require 'capistrano/bundler'
# Rails needs Bundler, right?
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano/rbenv' require 'capistrano/rbenv_install'
require 'capistrano/unicorn_nginx_osx'
require 'capistrano/faster_assets'
require 'capistrano/upload-config'
require 'capistrano/safe_deploy_to'
require 'capistrano/ssh_doctor'
require 'capistrano/rails/console'
require 'capistrano/rails/collection'
require 'capistrano/rails_tail_log'
# require 'capistrano/delayed-job'
# Load custom tasks from \`lib/capistrano/tasks\` if you have any defined Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
3. deploy.rb 파일의 수정
config/deploy.rb 파일을 열고 아래와 같이 수정한다.
# config valid only for current version of Capistrano
lock '3.4.0'
set :application, '[application-name]'
set :repo_url, "git@github.com:[user-name]/#{fetch(:application)}.git"
# Deploy Account
set :deploy_user, 'deployer'
set :deploy_to, "/home/[deployer-account]/apps/#{fetch(:application)}"
set :rbenv_type, :user # or :system, depends on your rbenv setup
set :rbenv_ruby, '2.2.2'
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w{rake gem bundle ruby rails}
set :rbenv_roles, :all # default values # Default value for :linked_files is []
set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
set :config_files, fetch(:linked_files)
set :pty, true
set :keep_releases, 5
set :linked_dirs, %w{log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
before 'deploy:check:linked_files', 'config:push'
# after 'deploy:published', 'restart' do
# invoke 'delayed_job:restart'
# end
namespace :deploy do
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
# Here we can do anything such as:
# within release_path do
# execute :rake, 'cache:clear'
# end
end
end
end
4. config/deploy/production.rb 파일 수정
server '[server-ip]', user: '[deploy-username]', roles: %w{web app db}
set :nginx_server_name, '[domain-name]'
set :unicorn_workers, 3
5. database.yml과 secrets.yml 파일의 별도 관리
이 두 파일의 내용은 보안상 노출되지 않도록 하는 것이 좋다.
따라서 git
저장소에 추가하지 않도록 한다.
대신에 이미 Gemfile
에 추가하여 설치한 capistrano-upload-config
젬에서 제공하는 rake
작업을 이용하여 배포시 로컬 머신의 이 두 파일을 서버로 직접 복사하도록 한다.
위의 26번 코드라인은 배포시에 이 두 파일을 서버로 직접 업로드 되도록 해 준다.
아래와 같이 config/database.yml
과 config/secrets.yml
이 두 파일을 .gitignore
파일에 등록하여 git
소스관리에 포함하지 않도록 한다.
···
config/secrets.yml
config/database.yml
이제 cap production config:init
명령을 실행하여 config/database.production.yml
과 config/secrets.production.yml
파일을 생성하고 database.yml
과 secrets.yml
파일로부터 내용을 복사한 후 적절하게 수정하여 사용한다.
이 때 주의할 것은 이 두 개의 파일은 git
소스관리에 포함할 것이 때문에 민감한 정보가 외부로 노출될 수 있다는 것이다. 따라서 데이터베이스 접속을 위한 database.yml
의 username
와 password
, 그리고 secrets.yml
의 production key
값은 시스템 환경변수에서 가져오도록 해야 한다.
이를 위해서 원격 서버로 접속한 후 sudo vi ~/.bash_profile
명령을 실행하여 3개의 환경변수를 지정한다.
DEPLOY_USERNAME=[deploy-username]
DEPLOY_PASSWORD=[deploy_password]
SECRET_KEY_BASE=[secret_key_base]
참고 :
SECRET_KEY_BASE
키에 할당한 값은 로컬 터미널에서rake secret
명령을 실행하여 얻을 수 있다.
위에서 생성한 두 개의 파일에 추가할 내용은 아래와 같다.
secrets.production.yml
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
database.production.yml
production:
adapter: mysql2
encoding: utf8
reconnect: false
database: [database-name]
pool: 5
username: <%= ENV['DEPLOY_USERNAME'] %>
password: <%= ENV['DEPLOY_PASSWORD'] %>
host: localhost
로컬 머신에서 환경변수 사용하기
로컬 머신에서도 환경변수를 편리하게 사용할 수 있다. 아래와 같이 Gemfile
에 젬을 추가하고 bundle install
한다.
gem 'dotenv-rails', :groups => [:development, :test]
그리고 레일스 프로젝트 루트 디렉토리에 .env
파일을 생성하고 .gitignore
파일에 추가해서 git
에서 tracking하지 못하도록 한다. 방금 생성한 .env
파일을 열고 아래와 같이 작성한다. 잊어서는 안 될 사항은 .env
파일 역시 git
소스관리에 포함되지 않도록 해야 한다. 따라서 .gitignore
파일에 추가해 주도록 한다.
export DEPLOY_USERNAME='[user-name]'
export DEPLOY_PASSWORD='[user-password]'
export SECRET_KEY_BASE='[secret_key_base']
배포 실행
$ cap production setup
$ cap production deploy
실제 배포과정은 두 번의 명령을 실행하여 완성된다.