部署在Ubuntu 14.04一个Rails应用程序与Capistrano的,Nginx的,和Puma

在本教程中,我们将在DigitalOcean Ubuntu的安装DropletRuby和Nginx的,并在我们的Web应用程序配置PumaCapistrano的。 Nginx的将被用来捕捉客户端的请求,并通过他们交给PumaWeb服务器正在运行的Rails。我们将使用Capistrano的自动执行常见部​​署任务,所以每次我们有我们的Rails应用程序的新版本部署到服务器,我们可以做到这一点与一些简单的命令。

介绍

Rails是一个用Ruby编写的开源Web应用程序框架。 它遵循约定优于配置理念,通过假设有做事的'最好'的方式。 这允许你写更少的代码,同时完成更多,而无需你经历无尽的配置文件。

Nginx是一个高性能的HTTP服务器,反向代理和负载均衡器,着重于并发性,稳定性,可扩展性和低内存消耗。 像Nginx一样,Puma是另一个非常快速和并发的Web服务器,具有非常小的内存占用,但是为Ruby Web应用程序而构建。

Capistrano是一个远程服务器自动化工具,主要关注Ruby Web应用程序。 它用于通过在SSH上脚本化任意工作流并自动执行常见任务(例如资产预编译和重新启动Rails服务器),将Web应用程序可靠地部署到任意数量的远程机器。

在本教程中,我们将在DigitalOcean Ubuntu Droplet上安装Ruby和Nginx,并在我们的网络应用程序中配置Puma和Capistrano。 Nginx将用于捕获客户端请求,并将它们传递到运行Rails的Puma Web服务器。 我们将使用Capistrano自动化常见的部署任务,所以每次我们必须部署一个新版本的Rails应用程序到服务器,我们可以使用几个简单的命令。

先决条件

要遵循本教程,您必须具有以下内容:

  • Ubuntu 14.04 x64 Droplet
  • 命名非root用户deploy使用sudo权限( 与Ubuntu 14.04初始服务器设置介绍了如何设置起来。)
  • 工作Rails应用程序托管在一个远程git存储库中,可以部署

可选,为加强安全,您可以通过SSH禁止root登录,并更改为描述SSH端口号与Ubuntu 14.04初始服务器设置

警告:禁止root登录后,请确保您可以ssh到你的Droplet作为deploy的用户和使用sudo关闭已打开进行这些更改根SSH会话之前,该用户。

在本教程的所有命令应该以运行deploy的用户。 如果需要该命令的root访问权限,它会在前面加sudo

第1步 - 安装Nginx

一旦VPS是安全的,我们可以开始安装软件包。 更新包索引文件:

sudo apt-get update

然后,安装Nginx:

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

第2步 - 安装数据库

安装您将在Rails应用程序中使用的数据库。 由于有很多数据库可供选择,我们不会在本指南中覆盖它们。 您可以在这里查看主要的说明:

另外一定要检查:

第3步 - 安装RVM和Ruby

我们不会直接安装Ruby。 相反,我们将使用一个Ruby版本管理器。 有很多他们可以选择(rbenv,chruby等),但我们将使用RVM本教程。 RVM允许您在同一个系统上轻松安装和管理多个Ruby,并根据您的应用程序使用正确的Ruby。 这使得生活更容易,当你必须升级你的Rails应用程序使用较新的ruby。

在安装RVM之前,需要导入RVM GPG密钥:

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

然后安装RVM来管理我们的Rubies:

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

该命令使用curl下载从RVM安装脚本https://get.rvm.io -sSL选项由三个标志:

  • -s告诉curl下载文件中的“静音模式”
  • -S告诉curl如果失败就显示错误信息
  • -L告诉curl跟随在获取安装脚本的所有HTTP重定向

下载完成后,该脚本通过管道输送bash -s选项传递stable作为参数传递给RVM安装脚本下载和安装RVM的稳定版本。

注意:如果第二个命令失败消息“GPG签名验证失败”,这意味着GPG密钥已经改变了,只需将命令从错误输出拷贝并执行下载签名。 然后对RVM安装运行curl命令。

我们需要加载RVM脚本(作为一个函数),以便我们可以开始使用它。 然后,我们需要运行的requirements命令自动安装所需的依赖和文件RVM和Ruby正常工作:

source ~/.rvm/scripts/rvm
rvm requirements

我们现在可以安装我们选择的Ruby。 我们将安装最新Ruby 2.2.1 (在写作的时间)作为我们的默认Ruby:

rvm install 2.2.1
rvm use 2.2.1 --default

第4步 - 安装Rails和Bundler

一旦Ruby设置完成,我们就可以开始安装Rubygems了。 我们将通过安装Rails的Gem,让你的Rails应用程序运行开始,然后我们将安装bundler可以读你的应用程序的Gemfile ,并自动安装所有需要的Gem。

安装Rails和Bundler:

gem install rails -V --no-ri --no-rdoc
gem install bundler -V --no-ri --no-rdoc

使用了三个标志:

  • -V (详细输出):打印有关Gem安装的详细信息
  • --no-ri - (跳过日文档):不安装日文档,节省空间,使安装快捷
  • --no-rdoc - (跳过RDocs):不安装RDocs,节省空间,加快安装

注意:您也可以根据您的要求通过安装Rails的特定版本-v标志:

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

第5步 - 设置SSH密钥

由于我们希望设置顺利的部署,我们将使用SSH密钥进行授权。 首先与GitHub,Bitbucket或任何其他Git Remote握手,其中托管您的Rails应用程序的代码库:

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

如果你得到一个别担心Permission denied (publickey)消息。 现在,为您的服务器生成SSH密钥(公钥/私钥对):

ssh-keygen -t rsa 

添加新创建的公钥( ~/.ssh/id_rsa.pub )到存储库的部署键:

如果所有的步骤都正确完成,您现在应该能够clone ,而无需输入密码的git仓库(通过SSH协议,而不是HTTP):

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

如果你需要测试一个示例应用程序,你可以派生专门为本教程创建了以下测试程序: 样品的Rails应用程序在GitHub上

git clone命令将创建一个目录具有相同的名称为您的应用程序。 例如,一个名为testapp_rails将被创建。

我们克隆只是为了检查我们的部署密钥是否正常工作,我们不需要每次推送新的更改时都克隆或拉取我们的存储库。 我们会让Capistrano为我们处理一切。 现在,您可以删除此克隆目录。

在本地计算机上打开终端。 如果您没有本地计算机的SSH密钥,也请为其创建一个SSH密钥。 在本地终端会话中:

ssh-keygen -t rsa 

当地的SSH密钥添加到您的Droplet的授权密钥文件(记得您的自定义端口号来替换端口号):

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

第6步 - 在Rails应用程序中添加部署配置

在本地机器上,在Rails应用程序中为Nginx和Capistrano创建配置文件。 通过将这些线将开始Gemfile的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安装你只是在你指定的GemGemfile 输入以下命令捆绑您的Rails应用程序:

bundle

捆绑后,运行以下命令配置Capistrano:

cap install

这将创建:

  • Capfile在你的Rails应用程序的根目录
  • deploy.rb在文件config目录
  • deploy在该目录config目录

更换你的内容Capfile有以下几点:

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参数字段:

config / deploy.rb

# 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文件包含了一些工作外的开箱帮助您管理您的应用程序发布和自动执行某些任务时,你犯了一个健全的部署默认:

  • 使用production为您的Rails应用程序的默认环境
  • 自动管理您应用程式的多个版本
  • 使用优化的SSH选项
  • 检查你的git远程是否是最新的
  • 管理应用程式的记录
  • 管理Puma工作人员时,在内存中预加载应用程序
  • 在完成部署后启动(或重新启动)Puma服务器
  • 在版本中的特定位置打开Puma服务器的套接字

您可以根据需要更改所有选项。 现在,Nginx需要配置。 创建config/nginx.conf在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页面文件夹的静态文件,并设置默认的最大Client Body SizeRequest Timeout值。

第7步 - 部署您的Rails应用程序

如果您使用自己的Rails应用程序,请提交您刚刚所做的更改,并将它们从本地计算机推送到远程:

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

注意:如果这是GitHub上使用此系统的第一次,你可能必须发出带有您的GitHub上的用户名和电子邮件地址如下命令:

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

再次,从本地机器,使您的第一次部署:

cap production deploy:initial

这将推送您的Rails应用程序到Droplet,安装所有必需的Gem为您的应用程序,并启动Puma Web服务器。 这可能需要5-15分钟之间,具体取决于您的应用程序使用的Gem数量。 在此过程发生时,您将看到调试消息。

如果一切顺利,我们现在准备将您的Puma Web服务器连接到Nginx逆向代理。

在Droplet,符号链接nginx.confsites-enabled目录:

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

重启Nginx服务:

sudo service nginx restart

您现在应该能够将您的Web浏览器指向您的服务器IP,并看到您的Rails应用程序在行动!

正常部署

当您更改您的应用程序,并需要部署一个新的版本到服务器,提交更改,推送到远程Git像往常一样,并运行deploy命令:

git add -A
git commit -m "Deploy Message"
git push origin master
cap production deploy

注意:如果您更改您config/nginx.conf文件,你必须在部署你的应用程序后,重新载入或服务器上重新启动Nginx的服务:

sudo service nginx restart

结论

好吧,现在你将运行一个Rails应用程序在您的Droplet与Puma作为您的Web服务器,以及Nginx和Capistrano配置基本设置。 您现在应该看看其他文档,可以帮助您优化您的配置,以获得最大的Rails应用程序: