介绍
在本教程中,我们将向您展示如何使用Git钩子自动将Rails应用程序的生产环境部署到远程Ubuntu 14.04服务器。 使用Git钩子将允许您通过简单地将更改推送到生产服务器来部署应用程序,而不必手动拉并执行数据库迁移。 在继续处理应用程序时,设置某种形式的自动部署(例如Git钩子)将为您节省时间。
这个特定的设置使用一个简单的“post-receive”Git钩子,除了Puma作为应用服务器,Nginx作为Puma的反向代理,PostgreSQL作为数据库。
如果你是新来的Git钩子和想了解更多的行动之前,请阅读本教程: 如何使用Git的鱼钩来自动化开发和部署任务 。
先决条件
您将需要访问在Ubuntu服务器上具有超级用户权限的非root用户。 在我们的例子设置中,我们将使用一个叫做用户deploy
。 本教程将告诉您如何设置了: 初始服务器设置与Ubuntu 14.04 。 如果要在不输入密码的情况下进行部署,请确保设置SSH密钥。
您需要在服务器上安装Ruby。 如果你还没有这样做的话,你可以将它与使用Rails安装rbenv或RVM 。
您还需要有一个在本地开发机器上的git存储库中管理的Rails应用程序。 如果你没有一个,并且想跟随,我们将提供一个简单的示例应用程序。
让我们开始吧!
安装PostgreSQL
大多数生产Rails环境使用PostgreSQL作为数据库,所以让我们现在在你的服务器上安装它。
在生产服务器,更新apt-get的:
sudo apt-get update
然后使用这些命令安装PostgreSQL:
sudo apt-get install postgresql postgresql-contrib libpq-dev
注意:您也应该在开发机器上安装PostgreSQL,这样你就可以安装pg
Gem,PostgreSQL的适配器,本地。 这将需要运行bundle install
时,我们添加了Gem到应用程序的Gemfile中。 由于安装步骤因操作系统而异,这是一个练习留给读者。
创建生产数据库用户
为了简单起见,让我们将生产数据库用户命名为应用程序名称。 例如,如果您的应用程序被称为“appname”,您应该创建一个PostgreSQL用户,如下所示:
sudo -u postgres createuser -s appname
我们要设置数据库用户的密码,因此输入PostgreSQL控制台如下:
sudo -u postgres psql
然后在示例中设置数据库用户的密码,“appname”,如下所示:
\password appname
输入所需的密码并确认。
使用以下命令退出PostgreSQL控制台:
\q
现在,我们准备好使用正确的数据库连接信息配置您的应用程序。
准备您的Rails应用程序
在开发计算机上,最有可能在本地计算机中,我们将为您准备部署应用程序。
可选:创建Rails应用程序
理想情况下,您已经有一个要部署的Rails应用程序。 如果是这种情况,您可以跳过本小节,并在进行适当的替换。 如果没有,第一步是创建一个新的Rails应用程序。
这些命令将在我们的主目录中创建一个新的Rails应用程序,名为“appname”。 随意替换突出显示的“appname”用别的东西:
cd ~
rails new appname
然后切换到应用程序目录:
cd appname
对于我们的示例应用程序,我们将生成一个scaffold控制器,所以我们的应用程序将有一些显示:
rails generate scaffold Task title:string note:text
现在让我们确保我们的应用程序在一个git存储库。
初始化Git Repo
如果您的应用程序由于某种原因不在Git存储库中,请初始化它并执行初始提交。
在开发计算机上,更改为您的应用程序的目录。 在我们的示例中,我们的应用程序称为“appname”,它位于我们的主目录中:
cd ~/appname
git init
git add -A
git commit -m 'initial commit'
现在让我们调整我们的应用程序,准备连接到我们的生产PostgreSQL数据库。
更新数据库配置
在开发计算机上,如果你是不是已经有改变应用程序的目录。 在我们的示例中,我们的应用程序称为“appname”,它位于我们的主目录中:
cd ~/appname
现在打开您喜欢的编辑器中的数据库配置文件。 我们将使用vi
:
vi config/database.yml
寻找你的应用程序的数据库配置的生产工段,并与生产数据库连接信息替换它。 如果你完全遵循了示例设置,它将看起来像这样(在适当的情况下替换任何值):
production:
<<: *default
host: localhost
adapter: postgresql
encoding: utf8
database: appname_production
pool: 5
username: <%= ENV['APPNAME_DATABASE_USER'] %>
password: <%= ENV['APPNAME_DATABASE_PASSWORD'] %>
保存并退出。 这指定应用程序的生产环境应在本地主机(生产服务器)上使用名为“appname_production”的PostgreSQL数据库。 请注意,数据库用户名和密码设置为环境变量。 我们将在以后在服务器上指定。
更新Gemfile
如果您的Gemfile还没有PostgreSQL的适配器的Gem, pg
,并指定了Puma的Gem,你现在应该添加它们。
在您喜欢的编辑器中打开应用程序的Gemfile。 我们将使用vi
在这里:
vi Gemfile
将以下行添加到Gemfile中:
group :production do
gem 'pg'
gem 'puma'
end
保存并退出。 这指定production
环境中应该使用pg
和puma
的Gem。
配置Puma
在配置Puma之前,您应该查找服务器具有的CPU核心数。 你可以很容易地在服务器上使用这个命令:
grep -c processor /proc/cpuinfo
现在,你的开发机器上,添加Puma配置config/puma.rb
。 在文本编辑器中打开文件:
vi config/puma.rb
将此配置复制并粘贴到文件中:
# Change to match your CPU core count
workers 2
# Min and Max threads per worker
threads 1, 6
app_dir = File.expand_path("../..", __FILE__)
shared_dir = "#{app_dir}/shared"
# Default to production
rails_env = ENV['RAILS_ENV'] || "production"
environment rails_env
# Set up socket location
bind "unix://#{shared_dir}/sockets/puma.sock"
# Logging
stdout_redirect "#{shared_dir}/log/puma.stdout.log", "#{shared_dir}/log/puma.stderr.log", true
# Set master PID and state locations
pidfile "#{shared_dir}/pids/puma.pid"
state_path "#{shared_dir}/pids/puma.state"
activate_control_app
on_worker_boot do
require "active_record"
ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
ActiveRecord::Base.establish_connection(YAML.load_file("#{app_dir}/config/database.yml")[rails_env])
end
的数字更改workers
到你的服务器的CPU内核的数量。 该示例假设您有2个内核。
保存并退出。 这将配置Puma与应用程序的位置,其套接字,日志和PID的位置。 随意修改文件,或添加您需要的任何其他选项。
提交您最近的变更:
git add -A
git commit -m 'added pg and puma'
继续之前,请生成将用于应用程序生产环境的密钥:
rake secret
rake secret sample output:29cc5419f6b0ee6b03b717392c28f5869eff0d136d8ae388c68424c6e5dbe52c1afea8fbec305b057f4b071db1646473c1f9a62f803ab8386456ad3b29b14b89
您将复制输出,并用它来设置你的应用程序的SECRET_KEY_BASE
下一步。
创建Puma Upstart脚本
让我们创建一个Upstart init脚本,以便我们可以轻松地启动和停止Puma,并确保它将在启动时启动。
在生产服务器 ,请从PumaGitHub的库主目录的丛林Upstart的工具:
cd ~
wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/upstart/puma-manager.conf
wget https://raw.githubusercontent.com/puma/puma/master/tools/jungle/upstart/puma.conf
现在打开提供puma.conf
文件,这样我们就可以配置Puma部署用户:
vi puma.conf
寻找指定的两条线setuid
和setgid
,并与您的部署用户和组的名称替换“应用”。 例如,如果您的部署用户名为“deploy”,则行应如下所示:
setuid deploy
setgid deploy
现在看与此行: exec /bin/bash <<'EOT'
在它下面添加以下行,确保替换PostgreSQL用户名和密码,以及您之前创建的rake密钥:
export APPNAME_DATABASE_USER='appname'
export APPNAME_DATABASE_PASSWORD='appname_password'
export SECRET_KEY_BASE='rake_secret_generated_above'
保存并退出。
现在将脚本复制到Upstart服务目录:
sudo cp puma.conf puma-manager.conf /etc/init
在puma-manager.conf
脚本引用/etc/puma.conf
的,它应该管理的应用程序。 让我们现在创建和编辑该库存文件:
sudo vi /etc/puma.conf
在这个文件中的每一行应该是路径到您想要的应用程序puma-manager
来管理。 我们将把我们的应用程序部署到用户主目录中名为“appname”的目录。 在我们的示例中,它将是以下(确保更新路径到您的应用程序将生活:
/home/deploy/appname
保存并退出。
现在您的应用程序配置为在引导时通过Upstart启动。 这意味着即使您的服务器重新启动后,您的应用程序也将启动。 请记住,我们尚未部署应用程序,因此我们不想开始它。
安装和配置Nginx
为了使应用程序可以访问互联网,我们应该使用Nginx作为Web服务器。
使用apt-get安装Nginx:
sudo apt-get install nginx
现在使用文本编辑器打开默认服务器块:
sudo vi /etc/nginx/sites-available/default
使用以下代码块替换文件的内容。 请务必使用适当的用户名和应用程序名称(两个位置)替换突出显示的部分:
upstream app {
# Path to Puma SOCK file, as defined previously
server unix:/home/deploy/appname/shared/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
server_name localhost;
root /home/deploy/appname/public;
try_files $uri/index.html $uri @app;
location @app {
proxy_pass http://app;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
保存并退出。 这将Nginx配置为反向代理,因此HTTP请求通过Unix套接字转发到Puma应用程序服务器。 随意地做任何更改,你认为合适。
现在,我们将阻止重新启动Nginx,因为应用程序在服务器上不存在。 接下来我们将准备应用程序。
准备生产Git远程
在生产服务器上安装的git用apt-get的:
sudo apt-get install git
然后为远程存储库创建一个目录。 我们将在主目录中创建一个名为“appname_production”的裸git存储库。 随意命名任何你想要的(除了不把它放在你的远程仓库~/appname
,因为那是我们将应用程序部署到):
mkdir ~/appname_production
cd ~/appname_production
git init --bare
由于这是一个裸存储库,没有工作目录,常规设置中位于.git中的所有文件都位于主目录本身。
我们需要创建后接收git钩子,这是生产服务器收到git push时运行的脚本。 打开hooks/post-receive
在编辑器中的文件:
vi hooks/post-receive
复制以下脚本粘贴到post-receive
的文件:
#!/bin/bash
GIT_DIR=/home/deploy/appname_production
WORK_TREE=/home/deploy/appname
export APPNAME_DATABASE_USER='appname'
export APPNAME_DATABASE_PASSWORD='appname_password'
export RAILS_ENV=production
. ~/.bash_profile
while read oldrev newrev ref
do
if [[ $ref =~ .*/master$ ]];
then
echo "Master ref received. Deploying master branch to production..."
mkdir -p $WORK_TREE
git --work-tree=$WORK_TREE --git-dir=$GIT_DIR checkout -f
mkdir -p $WORK_TREE/shared/pids $WORK_TREE/shared/sockets $WORK_TREE/shared/log
# start deploy tasks
cd $WORK_TREE
bundle install
rake db:create
rake db:migrate
rake assets:precompile
sudo restart puma-manager
sudo service nginx restart
# end deploy tasks
echo "Git hooks deploy complete"
else
echo "Ref $ref successfully received. Doing nothing: only the master branch may be deployed on this server."
fi
done
请务必更新以下突出显示的值:
-
GIT_DIR
:您之前创建裸Git仓库的目录 -
WORK_TREE
:该目录要部署应用程序(这应该匹配在Puma配置中指定的位置) -
APPNAME_DATABASE_USER
:PostgreSQL的用户名(要求rake任务) -
APPNAME_DATABASE_PASSWORD
:PostgreSQL的密码(需要rake任务)
接下来,您应该检查之间的命令# start deploy tasks
和# end deploy tasks
的意见。 这些是将运行的每个主分支推到生产远程Git(时间命令appname_production
)。 如果您保留原样,服务器将尝试对您的应用程序的生产环境执行以下操作:
- 运行bundler
- 创建数据库
- 迁移数据库
- 预编译资产
- 重新启动Puma
- 重新启动Nginx
如果你想进行任何更改,或添加错误检查,请随时在这里。
完成审阅后接收脚本后,保存并退出。
接下来,使脚本可执行:
chmod +x hooks/post-receive
密码:
因为,收到后钩需要执行sudo命令,我们将允许部署用户使用无密码sudo
(此处替代你的用户名部署,如果是不同的):
sudo sh -c 'echo "deploy ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/90-deploy'
这将允许deploy
用户运行sudo
不提供密码的命令。 请注意,您可能希望限制部署用户可以使用超级用户权限运行的命令。 至少,您将要使用SSH密钥身份验证并禁用密码身份验证。
添加生产Git远程
现在我们已经在生产服务器上设置了所有内容,让我们将生产git远程添加到应用程序的存储库。
在开发计算机上,请确保你在你的应用程序的目录:
cd ~/appname
然后添加一个新的远程Git命名为“生产”指向裸Git仓库, appname_production
,您在生产服务器上创建的。 替换用户名(deploy),服务器IP地址和远程存储库名称(appname_production):
git remote add production deploy@production_server_public_IP:appname_production
现在你的应用程序已准备好与git push部署。
部署到生产
通过所做的所有准备工作,现在可以通过运行以下git命令将应用程序部署到生产服务器:
git push production master
这只是将您的本地主分支推送到您之前创建的生产远程。 当生产遥控接收推,它将执行post-receive
我们先前设置钩子脚本。 如果正确设置一切,您的应用程序现在应该可以在您的生产服务器的公共IP地址。
如果您使用我们的示例应用程序,你应该能够访问http:// production_server_IP /tasks
在Web浏览器,看到这样的事情:
结论
每次对应用程序进行更改时,都可以运行相同的git push命令部署到生产服务器。 这单独应该可以为你的项目的生命节省大量的时间。
本教程仅讨论“后接收”钩子,但是还有其他几种类型的钩子可以帮助提高部署过程的自动化。 阅读本教程以了解更多有关Git的挂钩: 如何使用Git的鱼钩来自动化开发和部署的任务 !