使用Capistrano、Nginx和Puma在Ubuntu14.04上部署Rails应用程序
介绍
Rails 是一个用 Ruby 编写的开源 Web 应用程序框架。 它遵循 约定优于配置 的理念,假设存在“最佳”做事方式。 这使您可以编写更少的代码,同时完成更多工作,而无需查看无休止的配置文件。
Nginx 是一个高性能的 HTTP 服务器、反向代理和负载均衡器,以其专注于并发性、稳定性、可扩展性和低内存消耗而闻名。 与 Nginx 一样,Puma 是另一个非常快速和并发的 Web 服务器,内存占用非常小,但专为 Ruby Web 应用程序构建。
Capistrano 是一个远程服务器自动化工具,主要专注于 Ruby Web 应用程序。 它用于可靠地将 Web 应用程序部署到任意数量的远程计算机,方法是通过 SSH 编写任意工作流脚本,并自动执行常见任务,例如资产预编译和重启 Rails 服务器。
在本教程中,我们将在 DigitalOcean Ubuntu Droplet 上安装 Ruby 和 Nginx,并在我们的 Web 应用程序中配置 Puma 和 Capistrano。 Nginx 将用于捕获客户端请求并将它们传递给运行 Rails 的 Puma Web 服务器。 我们将使用 Capistrano 自动执行常见的部署任务,因此每次我们必须将新版本的 Rails 应用程序部署到服务器时,我们都可以使用一些简单的命令来完成。
先决条件
要学习本教程,您必须具备以下条件:
- Ubuntu 14.04 x64 液滴
- 一个名为
deploy
且具有 sudo 权限的非 root 用户(Initial Server Setup with Ubuntu 14.04 解释了如何设置它。) - 托管在准备好部署的远程 git 存储库中的工作 Rails 应用程序
或者,为了提高安全性,您可以禁用通过 SSH 的 root 登录并更改 SSH 端口号,如 使用 Ubuntu 14.04 的初始服务器设置中所述。
警告:禁用root登录后,请确保您可以以deploy
用户身份SSH到您的Droplet并为此用户使用sudo
之前关闭您为进行这些更改而打开的根 SSH 会话。
本教程中的所有命令都应以 deploy
用户身份运行。 如果该命令需要 root 访问权限,它将在前面加上 sudo
。
第 1 步 — 安装 Nginx
一旦 VPS 安全,我们就可以开始安装软件包了。 更新包索引文件:
sudo apt-get update
然后,安装 Nginx:
sudo apt-get install curl git-core nginx -y
第 2 步 — 安装数据库
安装您将在 Rails 应用程序中使用的数据库。 由于有很多数据库可供选择,我们不会在本指南中介绍它们。 您可以在此处查看主要说明:
还请务必检查:
- 如何在 Ubuntu 14.04 上将 MySQL 与 Ruby on Rails 应用程序一起使用
- 如何在 Ubuntu 14.04 上将 PostgreSQL 与 Ruby on Rails 应用程序一起使用
第三步——安装 RVM 和 Ruby
我们不会直接安装 Ruby。 相反,我们将使用 Ruby 版本管理器。 有很多可供选择(rbenv、chruby 等),但我们将在本教程中使用 RVM。 RVM 允许您在同一系统上轻松安装和管理多个 rubies,并根据您的应用程序使用正确的一个。 当您必须升级 Rails 应用程序以使用更新的 ruby 时,这会让生活变得更加轻松。
在安装 RVM 之前,您需要导入 RVM GPG Key:
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
然后安装 RVM 来管理我们的红宝石:
curl -sSL https://get.rvm.io | bash -s stable
此命令使用 curl
从 https://get.rvm.io
下载 RVM 安装脚本。 -sSL
选项由三个标志组成:
-s
告诉 curl 以“静默模式”下载文件-S
告诉 curl 如果失败则显示错误消息-L
告诉 curl 在检索安装脚本时遵循所有 HTTP 重定向
下载后,脚本为 piped 到 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
- (跳过 Ri 文档):不安装 Ri 文档,节省空间并加快安装速度--no-rdoc
- (跳过 RDocs):不安装 RDocs,节省空间并加快安装速度
注意: 你也可以根据自己的需求,使用 -v
标志安装特定版本的 Rails:
gem install rails -v '4.2.0' -V --no-ri --no-rdoc
第 5 步 — 设置 SSH 密钥
由于我们希望设置顺利部署,我们将使用 SSH 密钥进行授权。 首先与托管您的 Rails 应用程序代码库的 GitHub、Bitbucket 或任何其他 Git Remote 握手:
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
如果您需要一个示例应用程序进行测试,您可以 fork 以下为本教程专门创建的测试应用程序:GitHub 上的示例 Rails 应用程序
git clone
命令将创建一个与您的应用程序同名的目录。 例如,将创建一个名为 testapp_rails
的目录。
我们克隆只是为了检查我们的部署密钥是否正常工作,我们不需要在每次推送新更改时克隆或拉取我们的存储库。 我们会让 Capistrano 为我们处理这一切。 如果您愿意,您现在可以删除这个克隆的目录。
在本地计算机上打开终端。 如果您没有本地计算机的 SSH 密钥,也请为其创建一个。 在您的本地终端会话中:
ssh-keygen -t rsa
将本地 SSH 密钥添加到 Droplet 的 Authorized Keys 文件中(请记住将端口号替换为您自定义的端口号):
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 应用程序:
bundle
捆绑后,运行以下命令配置 Capistrano:
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 参数更新标记为红色的字段:
配置/部署.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。 在你的 Rails 项目目录中创建 config/nginx.conf
,并添加以下内容(同样,替换为你的参数):
配置/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 Size
和 Request 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.conf
符号链接到 sites-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
结论
好的,现在您将在您的 Droplet 上运行 Rails 应用程序,使用 Puma 作为您的 Web 服务器以及配置基本设置的 Nginx 和 Capistrano。 您现在应该查看其他文档,这些文档可以帮助您优化配置以充分利用 Rails 应用程序: