웹사이트 검색

Capistrano, Nginx 및 Puma를 사용하여 Ubuntu 14.04에 Rails 앱 배포


소개

Rails는 Ruby로 작성된 오픈 소스 웹 애플리케이션 프레임워크입니다. 일을 처리하는 '최상의' 방법이 있다는 가정을 함으로써 구성보다 관례 철학을 따릅니다. 이를 통해 끝없는 구성 파일을 거치지 않고도 더 적은 코드를 작성하면서 더 많은 작업을 수행할 수 있습니다.

Nginx는 동시성, 안정성, 확장성 및 낮은 메모리 소비에 중점을 둔 것으로 알려진 고성능 HTTP 서버, 리버스 프록시 및 로드 밸런서입니다. Nginx와 마찬가지로 Puma는 메모리 공간이 매우 작지만 Ruby 웹 애플리케이션용으로 구축된 매우 빠른 동시 웹 서버입니다.

Capistrano는 주로 Ruby 웹 앱에 초점을 맞춘 원격 서버 자동화 도구입니다. SSH를 통해 임의의 워크플로를 스크립팅하고 자산 사전 컴파일 및 Rails 서버 다시 시작과 같은 일반적인 작업을 자동화하여 여러 원격 시스템에 웹 앱을 안정적으로 배포하는 데 사용됩니다.

이 튜토리얼에서는 DigitalOcean Ubuntu Droplet에 Ruby와 Nginx를 설치하고 웹 앱에서 Puma와 Capistrano를 구성합니다. Nginx는 클라이언트 요청을 캡처하여 Rails를 실행하는 Puma 웹 서버로 전달하는 데 사용됩니다. 우리는 Capistrano를 사용하여 일반적인 배포 작업을 자동화하므로 새 버전의 Rails 앱을 서버에 배포해야 할 때마다 몇 가지 간단한 명령으로 이를 수행할 수 있습니다.

전제 조건

이 자습서를 따르려면 다음이 있어야 합니다.

  • 우분투 14.04 x64 물방울
  • Sudo 권한이 있는 deploy라는 이름의 루트가 아닌 사용자(Ubuntu 14.04의 초기 서버 설정에 설정 방법이 설명되어 있음)
  • 배포할 준비가 된 원격 git 저장소에서 호스팅되는 Working Rails 앱

선택적으로 보안 강화를 위해 Ubuntu 14.04의 초기 서버 설정에 설명된 대로 SSH를 통한 루트 로그인을 비활성화하고 SSH 포트 번호를 변경할 수 있습니다.

경고: 루트 로그인을 비활성화한 후 루트를 닫기 전에 deploy 사용자로 Droplet에 SSH로 연결하고 이 사용자에 대해 sudo를 사용할 수 있는지 확인하세요. 이러한 변경을 수행하기 위해 연 SSH 세션입니다.

이 자습서의 모든 명령은 deploy 사용자로 실행해야 합니다. 명령에 루트 액세스가 필요한 경우 앞에 sudo가 옵니다.

1단계 - Nginx 설치

VPS가 안전해지면 패키지 설치를 시작할 수 있습니다. 패키지 색인 파일을 업데이트합니다.

  1. sudo apt-get update

그런 다음 Nginx를 설치합니다.

  1. sudo apt-get install curl git-core nginx -y

2단계 - 데이터베이스 설치

Rails 앱에서 사용할 데이터베이스를 설치합니다. 선택할 수 있는 데이터베이스가 많기 때문에 이 가이드에서는 다루지 않습니다. 여기에서 주요 지침에 대한 지침을 볼 수 있습니다.

  • MySQL
  • PostgreSQL
  • 몽고DB

또한 다음을 확인하십시오.

  • Ubuntu 14.04에서 Ruby on Rails 애플리케이션과 함께 MySQL을 사용하는 방법
  • Ubuntu 14.04에서 Ruby on Rails 애플리케이션과 함께 PostgreSQL을 사용하는 방법

3단계 - RVM 및 Ruby 설치

우리는 Ruby를 직접 설치하지 않을 것입니다. 대신 Ruby 버전 관리자를 사용합니다. 선택할 수 있는 항목(rbenv, chruby 등)이 많지만 이 자습서에서는 RVM을 사용합니다. RVM을 사용하면 동일한 시스템에 여러 Ruby를 쉽게 설치 및 관리하고 앱에 따라 올바른 Ruby를 사용할 수 있습니다. 이것은 새로운 Ruby를 사용하기 위해 Rails 앱을 업그레이드해야 할 때 삶을 훨씬 더 쉽게 만듭니다.

RVM을 설치하기 전에 RVM GPG 키를 가져와야 합니다.

  1. gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3

그런 다음 RVM을 설치하여 Ruby를 관리합니다.

  1. curl -sSL https://get.rvm.io | bash -s stable

이 명령은 curl을 사용하여 https://get.rvm.io에서 RVM 설치 스크립트를 다운로드합니다. -sSL 옵션은 세 가지 플래그로 구성됩니다.

  • -s는 '자동 모드'에서 파일을 다운로드하도록 curl에 지시합니다.
  • -S는 curl이 실패할 경우 오류 메시지를 표시하도록 지시합니다.
  • -L은 curl이 설치 스크립트를 검색하는 동안 모든 HTTP 리디렉션을 따르도록 지시합니다.

다운로드가 완료되면 스크립트는 bash파이핑됩니다. -s 옵션은 stable을 RVM 설치 스크립트에 대한 인수로 전달하여 안정적인 RVM 릴리스를 다운로드하고 설치합니다.

참고: 두 번째 명령이 "GPG 서명 확인 실패\ 메시지와 함께 실패하면 GPG 키가 변경되었음을 의미합니다. 오류 출력에서 명령을 복사하고 실행하여 서명을 다운로드하십시오. 그런 다음 RVM에 대해 curl 명령을 실행하십시오. 설치.

사용을 시작할 수 있도록 RVM 스크립트를 함수로 로드해야 합니다. 그런 다음 requirements 명령을 실행하여 RVM 및 Ruby가 제대로 작동하는 데 필요한 종속성 및 파일을 자동으로 설치해야 합니다.

  1. source ~/.rvm/scripts/rvm
  2. rvm requirements

이제 선택한 Ruby를 설치할 수 있습니다. 최신 Ruby 2.2.1(작성 당시)을 기본 Ruby로 설치합니다.

  1. rvm install 2.2.1
  2. rvm use 2.2.1 --default

4단계 - Rails 및 Bundler 설치

Ruby가 설정되면 Rubygems 설치를 시작할 수 있습니다. 먼저 Rails 애플리케이션을 실행할 수 있는 Rails gem을 설치한 다음 앱의 Gemfile을 읽고 필요한 모든 항목을 자동으로 설치할 수 있는 bundler를 설치합니다. 보석.

Rails 및 Bundler를 설치하려면:

  1. gem install rails -V --no-ri --no-rdoc
  2. gem install bundler -V --no-ri --no-rdoc

세 가지 플래그가 사용되었습니다.

  • -V (Verbose 출력): Gem 설치에 대한 자세한 정보를 출력합니다.
  • --no-ri - (Ri 문서 건너뛰기): Ri Docs를 설치하지 않아 공간을 절약하고 설치 속도가 빨라짐
  • --no-rdoc - (RDocs 건너뛰기): RDocs를 설치하지 않아 공간을 절약하고 설치 속도를 높입니다.

참고: -v 플래그를 사용하여 요구 사항에 따라 특정 버전의 Rails를 설치할 수도 있습니다.

  1. gem install rails -v '4.2.0' -V --no-ri --no-rdoc

5단계 - SSH 키 설정

원활한 배포를 설정하고 싶기 때문에 인증을 위해 SSH 키를 사용할 것입니다. 먼저 Rails 앱의 코드베이스가 호스팅되는 GitHub, Bitbucket 또는 기타 Git Remote와 악수하십시오.

  1. ssh -T git@github.com
  2. ssh -T git@bitbucket.org

권한 거부(공개 키) 메시지가 표시되더라도 걱정하지 마십시오. 이제 서버에 대한 SSH 키(공용/개인 키 쌍)를 생성합니다.

  1. ssh-keygen -t rsa

새로 생성된 공개 키(~/.ssh/id_rsa.pub)를 리포지토리의 배포 키에 추가합니다.

  • Github 지침
  • Bitbucket 지침

모든 단계가 올바르게 완료되었으면 이제 비밀번호를 입력하지 않고 git 저장소를 (HTTP가 아닌 SSH 프로토콜을 통해) 복제할 수 있습니다.

  1. git clone git@example.com:username/appname.git

테스트용 샘플 앱이 필요한 경우 이 자습서용으로 특별히 생성된 다음 테스트 앱을 포크할 수 있습니다. GitHub의 샘플 레일 앱

git clone 명령은 앱과 동일한 이름으로 디렉토리를 생성합니다. 예를 들어 testapp_rails라는 디렉터리가 생성됩니다.

배포 키가 작동하는지 확인하기 위해서만 복제하고 있으므로 새로운 변경 사항을 푸시할 때마다 리포지토리를 복제하거나 가져올 필요가 없습니다. 우리는 Capistrano가 우리를 위해 모든 것을 처리하도록 할 것입니다. 원하는 경우 이제 이 복제된 디렉토리를 삭제할 수 있습니다.

로컬 컴퓨터에서 터미널을 엽니다. 로컬 컴퓨터에 대한 SSH 키가 없는 경우 SSH 키도 생성하십시오. 로컬 터미널 세션에서:

  1. ssh-keygen -t rsa

Droplet의 Authorized Keys 파일에 로컬 SSH 키를 추가합니다(포트 번호를 사용자 지정 포트 번호로 교체해야 함).

  1. cat ~/.ssh/id_rsa.pub | ssh -p your_port_num deploy@your_server_ip 'cat >> ~/.ssh/authorized_keys'

6단계 - Rails 앱에서 배포 구성 추가

로컬 시스템에서 Rails 애플리케이션의 Nginx 및 Capistrano에 대한 구성 파일을 생성합니다. Rails 앱의 Gemfile에 다음 행을 추가하여 시작하십시오.


group :development do
    gem 'capistrano',         require: false
    gem 'capistrano-rvm',     require: false
    gem 'capistrano-rails',   require: false
    gem 'capistrano-bundler', require: false
    gem 'capistrano3-puma',   require: false
end

gem 'puma'

bundler를 사용하여 방금 Gemfile에 지정한 gem을 설치합니다. 다음 명령을 입력하여 Rails 앱을 번들로 묶습니다.

  1. bundle

번들링 후 다음 명령을 실행하여 Capistrano를 구성합니다.

  1. cap install

이렇게 하면 다음이 생성됩니다.

  • Rails 앱의 루트 디렉토리에 있는 Capfile
  • config 디렉터리의
  • deploy.rb 파일
  • config 디렉토리의
  • deploy 디렉토리

Capfile의 내용을 다음으로 바꿉니다.

# Load DSL and Setup Up Stages
require 'capistrano/setup'
require 'capistrano/deploy'

require 'capistrano/rails'
require 'capistrano/bundler'
require 'capistrano/rvm'
require 'capistrano/puma'

# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

Capfile은 Capistrano 구성 파일에 사전 정의된 일부 작업을 로드하여 자동으로 다음과 같이 번거로움 없이 배포할 수 있도록 합니다.

  • 올바른 Ruby 선택
  • 자산 사전 컴파일
  • Git 저장소를 올바른 위치에 복제
  • Gemfile이 변경된 경우 새 종속성 설치

config/deploy.rb의 내용을 다음으로 바꾸고 빨간색으로 표시된 필드를 앱 및 Droplet 매개변수로 업데이트합니다.


# Change these
server 'your_server_ip', port: your_port_num, roles: [:web, :app, :db], primary: true

set :repo_url,        'git@example.com:username/appname.git'
set :application,     'appname'
set :user,            'deploy'
set :puma_threads,    [4, 16]
set :puma_workers,    0

# Don't change these unless you know what you're doing
set :pty,             true
set :use_sudo,        false
set :stage,           :production
set :deploy_via,      :remote_cache
set :deploy_to,       "/home/#{fetch(:user)}/apps/#{fetch(:application)}"
set :puma_bind,       "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state,      "#{shared_path}/tmp/pids/puma.state"
set :puma_pid,        "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.error.log"
set :puma_error_log,  "#{release_path}/log/puma.access.log"
set :ssh_options,     { forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub) }
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true  # Change to false when not using ActiveRecord

## Defaults:
# set :scm,           :git
# set :branch,        :master
# set :format,        :pretty
# set :log_level,     :debug
# set :keep_releases, 5

## Linked Files & Directories (Default None):
# set :linked_files, %w{config/database.yml}
# set :linked_dirs,  %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}

namespace :puma do
  desc 'Create Directories for Puma Pids and Socket'
  task :make_dirs do
    on roles(:app) do
      execute "mkdir #{shared_path}/tmp/sockets -p"
      execute "mkdir #{shared_path}/tmp/pids -p"
    end
  end

  before :start, :make_dirs
end

namespace :deploy do
  desc "Make sure local git is in sync with remote."
  task :check_revision do
    on roles(:app) do
      unless `git rev-parse HEAD` == `git rev-parse origin/master`
        puts "WARNING: HEAD is not the same as origin/master"
        puts "Run `git push` to sync changes."
        exit
      end
    end
  end

  desc 'Initial Deploy'
  task :initial do
    on roles(:app) do
      before 'deploy:restart', 'puma:start'
      invoke 'deploy'
    end
  end

  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      invoke 'puma:restart'
    end
  end

  before :starting,     :check_revision
  after  :finishing,    :compile_assets
  after  :finishing,    :cleanup
  after  :finishing,    :restart
end

# ps aux | grep puma    # Get puma pid
# kill -s SIGUSR2 pid   # Restart puma
# kill -s SIGTERM pid   # Stop puma

deploy.rb 파일에는 앱 릴리스를 관리하고 배포할 때 일부 작업을 자동으로 수행하는 데 도움이 되도록 기본적으로 작동하는 정상적인 기본값이 포함되어 있습니다.

  • Rails 앱의 기본 환경으로 production 사용
  • 앱의 여러 릴리스를 자동으로 관리
  • 최적화된 SSH 옵션 사용
  • Git 리모컨이 최신 상태인지 확인
  • 앱 로그 관리
  • Puma 작업자 관리 시 메모리에 앱 미리 로드
  • 배포 완료 후 Puma 서버 시작(또는 다시 시작)
  • 릴리스의 특정 위치에서 Puma 서버에 대한 소켓을 엽니다.

요구 사항에 따라 모든 옵션을 변경할 수 있습니다. 이제 Nginx를 구성해야 합니다. Rails 프로젝트 디렉토리에 config/nginx.conf를 생성하고 다음을 추가합니다(역시 매개변수로 대체).


upstream puma {
  server unix:///home/deploy/apps/appname/shared/tmp/sockets/appname-puma.sock;
}

server {
  listen 80 default_server deferred;
  # server_name example.com;

  root /home/deploy/apps/appname/current/public;
  access_log /home/deploy/apps/appname/current/log/nginx.access.log;
  error_log /home/deploy/apps/appname/current/log/nginx.error.log info;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @puma;
  location @puma {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_pass http://puma;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 10M;
  keepalive_timeout 10;
}

이전 파일과 마찬가지로 이 nginx.conf에는 deploy.rb 파일의 구성과 함께 기본적으로 작동하는 기본값이 포함되어 있습니다. 이것은 포트 80에서 트래픽을 수신하고 요청을 Puma 소켓에 전달하고 nginx 로그를 앱의 '현재' 릴리스에 작성하고 모든 자산을 압축하고 최대 만료 시간으로 브라우저에 캐시하고 HTML 페이지를 공개적으로 제공합니다. 폴더를 정적 파일로 저장하고 기본 최대 클라이언트 본문 크기요청 시간 초과 값을 설정합니다.

7단계 - Rails 애플리케이션 배포

자체 Rails 앱을 사용하는 경우 방금 변경한 내용을 커밋하고 로컬 머신에서 원격으로 푸시합니다.

  1. git add -A
  2. git commit -m "Set up Puma, Nginx & Capistrano"
  3. git push origin master

참고: 이 시스템에서 GitHub를 처음 사용하는 경우 GitHub 사용자 이름 및 이메일 주소로 다음 명령을 실행해야 할 수 있습니다.

  1. git config --global user.name 'Your Name'
  2. git config --global user.email you@example.com

다시 한 번 로컬 컴퓨터에서 첫 번째 배포를 수행합니다.

  1. cap production deploy:initial

그러면 Rails 앱이 Droplet으로 푸시되고 앱에 필요한 모든 gem이 설치되며 Puma 웹 서버가 시작됩니다. 앱에서 사용하는 Gem의 수에 따라 5~15분 정도 소요될 수 있습니다. 이 프로세스가 발생하면 디버그 메시지가 표시됩니다.

모든 것이 순조롭게 진행된다면 이제 Puma 웹 서버를 Nginx 리버스 프록시에 연결할 준비가 된 것입니다.

Droplet에서 nginx.confsites-enabled 디렉토리에 Symlink로 연결합니다.

  1. sudo rm /etc/nginx/sites-enabled/default
  2. sudo ln -nfs "/home/deploy/apps/appname/current/config/nginx.conf" "/etc/nginx/sites-enabled/appname"

Nginx 서비스를 다시 시작합니다.

  1. sudo service nginx restart

이제 웹 브라우저에서 서버 IP를 가리키고 Rails 앱이 작동하는 것을 볼 수 있습니다!

일반 배포

앱을 변경하고 새 릴리스를 서버에 배포하고 싶을 때마다 변경 사항을 커밋하고 평소와 같이 git remote에 푸시하고 deploy 명령을 실행합니다.

  1. git add -A
  2. git commit -m "Deploy Message"
  3. git push origin master
  4. cap production deploy

참고: config/nginx.conf 파일을 변경하면 앱을 배포한 후 서버에서 Nginx 서비스를 다시 로드하거나 다시 시작해야 합니다.

  1. sudo service nginx restart

결론

이제 기본 설정으로 구성된 Nginx 및 Capistrano뿐만 아니라 Puma를 웹 서버로 사용하여 Droplet에서 Rails 앱을 실행하게 됩니다. 이제 Rails 애플리케이션을 최대한 활용하기 위해 구성을 최적화하는 데 도움이 되는 다른 문서를 살펴봐야 합니다.

  • Puma 구성
  • 카피스트라노의 Puma DSL
  • Capistrano에서 로컬 자산 사전 편집
  • RAM을 기반으로 Puma 작업자 자동 재시작
  • 높은 트래픽 부하에 대한 Nginx 최적화