使用 Capistrano、Nginx 和 Puma 在 Ubuntu 14.04 上部署 Rails 应用程序

简介

Rails是一个用Ruby编写的开源Web应用程序框架。它遵循配置哲学上的约定,假设有最佳的做事方式。这允许您编写更少的代码,同时完成更多的工作,而不必经历无数的配置文件。

Nginx是一个高性能的HTTP服务器、反向代理和负载均衡器,以其对并发性、稳定性、可伸缩性和低内存消耗的关注而闻名。和Nginx一样,Puma是另一个速度极快的并发Web服务器,内存占用非常小,但它是为Ruby Web应用程序构建的。

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

在本教程中,我们将在DigitalOcean Ubuntu Drop上安装Ruby和Nginx,并在我们的Web应用程序中配置Puma和Capstrano。Nginx将用于捕获客户端请求,并将其传递给运行Rails的彪马Web服务器。我们将使用Capstrano自动执行常见的部署任务,所以每次我们必须将新版本的Rails应用程序部署到服务器上时,我们都可以通过几个简单的命令来完成。

前提条件

要遵循本教程,您必须具备以下条件:

  • Ubuntu 14.04 x64 Drop
  • 拥有sudo权限的非根用户14.04](https://andsky.com/tech/tutorials/initial-server-setup-with-ubuntu-14-04)([Ubuntu初始服务器设置]解释了如何设置。)
  • 托管在准备部署的远程Git存储库中的工作Rails应用程序

或者,为了提高安全性,您可以禁用通过SSH的root登录并更改SSH端口号,如使用Ubuntu 14.04进行初始服务器设置中所述。

<$>[警告] 警告: 关闭根登录后,请确保您可以以ploy用户的身份SSH到您的Droplet,并在_关闭您打开的根SSH会话之前使用sudo来进行这些更改。 <$>

本教程中的所有命令都应以ploy用户身份运行。如果该命令需要超级用户访问权限,则前面会有sudo

Step 1-安装Nginx

一旦VPS安全,我们就可以开始安装包了。更新程序包索引文件:

1sudo apt-get update

然后,安装Nginx:

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

第二步-安装数据库

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

也一定要看看:

第三步-安装RVM和Ruby

我们不会直接安装Ruby。相反,我们将使用Ruby版本管理器。它们有很多可供选择(rbenv、chruby等),但在本教程中我们将使用RVM。RVM允许您轻松地在同一系统上安装和管理多个红宝石,并根据您的应用程序使用正确的红宝石。当您必须升级您的Rails应用程序以使用较新的Ruby时,这将使您的工作变得容易得多。

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

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

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

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

该命令使用curlhttps://get.rvm.io.下载rvm安装脚本-sSL选项由三个标志组成:

  • -s告诉cURL以‘静默模式’下载文件
  • -S告诉cURL在失败时显示错误消息
  • -L告诉cURL在检索安装脚本时遵循所有HTTP重定向

下载后,脚本被_piped_ to bash-s选项将stable作为参数传递给RVM安装脚本,以下载和安装RVM的稳定版本。

<$>[备注] 注意: 如果第二条命令失败,并提示GPG签名验证失败,则表示GPG密钥已更改,只需从错误输出中复制命令并运行即可下载签名。然后为RVM安装运行curl命令。 <$>

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

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

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

1rvm install 2.2.1
2rvm use 2.2.1 --default

第四步-安装导轨和捆绑器

一旦设置好Ruby,我们就可以开始安装Rubygems了。我们将从安装rails gem开始,它将允许您的rails应用程序运行,然后我们将安装bundler,它可以读取您的应用程序的Gemfile,并自动安装所有必需的gem。

安装Rails和Bundler:

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

使用了三个标志:

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

<$>[注] 注意: 您也可以根据自己的需求安装特定版本的Rails,使用-v标志:

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

<$>

第五步-设置SSH密钥

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

如果收到`许可被拒绝(公钥)‘的消息,请不要担心。现在,为您的服务器生成SSH密钥(公钥/私钥对):

1ssh-keygen -t rsa

将新创建的公钥~/.ssh/id_rsa.pub添加到您仓库的部署密钥中:

如果所有步骤都正确完成,您现在应该能够在不输入密码的情况下‘克隆’您的Git存储库(通过SSH协议,而不是HTTP):

1git clone [email protected]:username/appname.git

如果您需要用于测试的示例应用程序,您可以使用以下专门为本教程创建的测试应用程序:GitHub上的示例Rails应用程序

git clone命令将创建一个与您的应用程序同名的目录。例如,将创建一个名为testapp_tras的目录。

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

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

1ssh-keygen -t rsa

将您的本地SSH密钥添加到Droplet的授权密钥文件中(请记住将端口号替换为您自定义的端口号):

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

Step 6-在Rails App中添加部署配置

在您的本地机器上,在您的Rails应用程序中为nginx和Capstrano创建配置文件。首先,将这些行添加到Rails应用程序的Gemfile中:

 1[label Gemfile]
 2
 3group :development do
 4    gem 'capistrano', require: false
 5    gem 'capistrano-rvm', require: false
 6    gem 'capistrano-rails', require: false
 7    gem 'capistrano-bundler', require: false
 8    gem 'capistrano3-puma', require: false
 9end
10
11gem 'puma'

使用bundler安装您刚才在Gemfile中指定的gem。输入以下命令来捆绑您的Rails应用程序:

1bundle

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

1cap install

这将创建:

  • Rails应用程序根目录中的Capfile
  • config目录下的ploy.rb文件
  • config目录中的ploy目录

用以下内容替换您的Capfile的内容:

 1[label Capfile]
 2# Load DSL and Setup Up Stages
 3require 'capistrano/setup'
 4require 'capistrano/deploy'
 5
 6require 'capistrano/rails'
 7require 'capistrano/bundler'
 8require 'capistrano/rvm'
 9require 'capistrano/puma'
10
11# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
12Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

这个Capfile会将一些预定义的任务加载到你的Capistrano配置文件中,以使你的部署变得轻松,例如自动:

  • 选择正确的Ruby
  • 预编资产
  • 将Git存储库克隆到正确的位置
  • 在Gemfile更改时安装新的依赖项

config/ploy.rb的内容替换为以下内容,并使用您的应用程序和Droplet参数更新标记为红色的字段:

 1[label config/deploy.rb]
 2
 3# Change these
 4server 'your_server_ip', port: your_port_num, roles: [:web, :app, :db], primary: true
 5
 6set :repo_url,        '[email protected]:username/appname.git'
 7set :application,     'appname'
 8set :user,            'deploy'
 9set :puma_threads,    [4, 16]
10set :puma_workers, 0
11
12# Don't change these unless you know what you're doing
13set :pty, true
14set :use_sudo, false
15set :stage,           :production
16set :deploy_via,      :remote_cache
17set :deploy_to,       "/home/#{fetch(:user)}/apps/#{fetch(:application)}"
18set :puma_bind,       "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
19set :puma_state,      "#{shared_path}/tmp/pids/puma.state"
20set :puma_pid,        "#{shared_path}/tmp/pids/puma.pid"
21set :puma_access_log, "#{release_path}/log/puma.error.log"
22set :puma_error_log,  "#{release_path}/log/puma.access.log"
23set :ssh_options,     { forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub) }
24set :puma_preload_app, true
25set :puma_worker_timeout, nil
26set :puma_init_active_record, true  # Change to false when not using ActiveRecord
27
28## Defaults:
29# set :scm,           :git
30# set :branch,        :master
31# set :format,        :pretty
32# set :log_level,     :debug
33# set :keep_releases, 5
34
35## Linked Files & Directories (Default None):
36# set :linked_files, %w{config/database.yml}
37# set :linked_dirs,  %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
38
39namespace :puma do
40  desc 'Create Directories for Puma Pids and Socket'
41  task :make_dirs do
42    on roles(:app) do
43      execute "mkdir #{shared_path}/tmp/sockets -p"
44      execute "mkdir #{shared_path}/tmp/pids -p"
45    end
46  end
47
48  before :start, :make_dirs
49end
50
51namespace :deploy do
52  desc "Make sure local git is in sync with remote."
53  task :check_revision do
54    on roles(:app) do
55      unless `git rev-parse HEAD` == `git rev-parse origin/master`
56        puts "WARNING: HEAD is not the same as origin/master"
57        puts "Run `git push` to sync changes."
58        exit
59      end
60    end
61  end
62
63  desc 'Initial Deploy'
64  task :initial do
65    on roles(:app) do
66      before 'deploy:restart', 'puma:start'
67      invoke 'deploy'
68    end
69  end
70
71  desc 'Restart application'
72  task :restart do
73    on roles(:app), in: :sequence, wait: 5 do
74      invoke 'puma:restart'
75    end
76  end
77
78  before :starting,     :check_revision
79  after  :finishing,    :compile_assets
80  after  :finishing,    :cleanup
81  after  :finishing,    :restart
82end
83
84# ps aux | grep puma    # Get puma pid
85# kill -s SIGUSR2 pid   # Restart puma
86# kill -s SIGTERM pid   # Stop puma

这个ploy.rb文件包含一些开箱即用的合理默认设置,可以帮助您管理应用程序版本,并在进行部署时自动执行一些任务:

  • 使用Production作为您的Rails应用程序的默认环境
  • 自动管理应用程序的多个版本
  • 使用优化的SSH选项
  • 检查您的GIT遥控器是否为最新
  • 管理应用程序的日志
  • 在管理彪马工作人员时将应用程序预加载到内存中
  • 完成部署后启动(或重新启动)Puma服务器
  • 在您的版本中的特定位置打开到Puma服务器的套接字

您可以根据需要更改所有选项。现在,需要配置nginx。在您的Rails项目目录中创建config/nginx.conf,并在其中添加以下内容(再次替换为您的参数):

 1[label config/nginx.conf]
 2
 3upstream puma {
 4  server unix:///home/deploy/apps/appname/shared/tmp/sockets/appname-puma.sock;
 5}
 6
 7server {
 8  listen 80 default_server deferred;
 9  # server_name example.com;
10
11  root /home/deploy/apps/appname/current/public;
12  access_log /home/deploy/apps/appname/current/log/nginx.access.log;
13  error_log /home/deploy/apps/appname/current/log/nginx.error.log info;
14
15  location ^~ /assets/ {
16    gzip_static on;
17    expires max;
18    add_header Cache-Control public;
19  }
20
21  try_files $uri/index.html $uri @puma;
22  location @puma {
23    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
24    proxy_set_header Host $http_host;
25    proxy_redirect off;
26
27    proxy_pass http://puma;
28  }
29
30  error_page 500 502 503 504 /500.html;
31  client_max_body_size 10M;
32  keepalive_timeout 10;
33}

与前面的文件一样,这个nginx.con文件包含的默认设置与您的ploy.rb文件中的配置一样,开箱即用。这将侦听端口80上的流量并将请求传递给您的Puma套接字,将nginx日志写入您的应用程序的当前版本,压缩所有资产并将它们缓存到最大到期时间的浏览器中,将公共文件夹中的HTML页面作为静态文件提供服务,并设置默认的最大Client Body Size和`RequestTimeout‘值。

第7步-部署Rails应用程序

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

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

<$>[备注] 注意: 如果这是您第一次在本系统使用giHub,您可能需要通过您的giHub用户名和邮箱地址发出以下命令:

1git config --global user.name 'Your Name'
2git config --global user.email [email protected]

<$>

同样,从您的本地计算机进行第一次部署:

1cap production deploy:initial

这将把Rails应用推送到Droplet,安装应用所需的所有gem,并启动Puma Web服务器。这可能需要5-15分钟,具体取决于您的应用使用的宝石数量。在此过程中,您将看到调试消息。

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

在Droplet上,将nginx.conf符号链接到sites-enabled目录:

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

重启Nginx服务:

1sudo service nginx restart

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

正常部署

每当您对应用程序进行更改,并希望在服务器上部署新版本时,提交更改,像往常一样推送到您的GIT遥控器,然后运行ploy命令:

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

<$>[备注] 注意: 如果您修改了config/nginx.con文件,则在部署您的应用程序后,您需要在服务器上重新加载或重启您的Nginx服务:

1sudo service nginx restart

<$>

结论

好了,现在你应该已经在你的Droplet上运行了一个Rails应用程序了,Puma作为你的Web服务器,以及配置了基本设置的Nginx和Capstrano。现在,您应该看看其他文档,这些文档可以帮助您优化配置,以最大限度地利用您的Rails应用程序:

Published At
Categories with 技术
comments powered by Disqus