在本教程中,我们将向您展示如何使用Git hooks自动将Rails应用程序的生产环境部署到远程Ubuntu 14.04服务器。使用Git hooks将允许您通过简单地将更改推送到生产服务器来部署应用程序,而不必手动拉动并执行诸如执行数据库迁移之类的操作。当您继续处理应用程序时,设置某种形式的自动部署(例如Git hooks)将为您节省时间。
这个特殊的设置使用简单的“post-receive”Git hooks,除了Puma作为应用服务器,Nginx作为Puma的反向代理,PostgreSQL作为数据库。
deploy
的用户。如果要在不输入密码的情况下进行部署,请务必设置SSH密钥。没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后再购买服务器。让我们开始吧!
大多数生产Rails环境使用PostgreSQL作为数据库,所以现在让我们将它安装在您的服务器上。
在生产服务器上,更新apt-get:
sudo apt-get update
然后使用以下命令安装PostgreSQL:
sudo apt-get install postgresql postgresql-contrib libpq-dev
注意:您还应该在开发计算机上安装PostgreSQL,这样您就可以在本地安装pg
gem,PostgreSQL适配器。当我们将gem添加到应用程序的Gemfile时,需要运行此bundle install
命令。由于安装步骤因操作系统而异,因此这是留给读者的练习。
为了简单起见,我们将生产数据库用户命名设为与您的应用程序名称相同。例如,如果您的应用程序名为“appname”,则应创建一个PostgreSQL用户,如下所示:
sudo -u postgres createuser -s appname
我们想设置数据库用户的密码,所以进入PostgreSQL控制台,如下所示:
sudo -u postgres psql
然后在示例中为数据库用户设置密码“appname”,如下所示:
\password appname
输入所需的密码并确认。
使用以下命令退出PostgreSQL控制台:
\q
现在,我们已准备好使用正确的数据库连接信息配置您的应用程序。
在您的开发机器上,很可能是您的本地计算机,我们将准备您要部署的应用程序。
理想情况下,您已经拥有了要部署的Rails应用程序。如果是这种情况,您可以跳过此小节,并在跟随时进行适当的替换。如果没有,第一步是创建一个新的Rails应用程序。
这些命令将在我们的主目录中创建一个名为“appname”的新Rails应用程序。随意替换“appname”为其他名字:
cd ~
rails new appname
然后切换到应用程序目录:
cd appname
对于我们的示例应用程序,我们将生成一个脚手架控制器,以便我们的应用程序可以显示:
rails generate scaffold Task title:string note:text
现在让我们确保我们的应用程序位于git存储库中。
如果您的应用程序由于某种原因尚未存在于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'] %>
保存并退出。这指定应用程序的生产环境应该在localhost-生产服务器上使用名为“appname_production”的PostgreSQL数据库。请注意,数据库用户名和密码设置为环境变量。我们稍后会在服务器上指定它们。
如果你的Gemfile还没有指定PostgreSQL适配器gem, pg
和指定了Puma gem,你应该立即添加它们。
在您喜欢的编辑器中打开应用程序的Gemfile。我们将在这里使用vi
:
vi Gemfile
将以下行添加到Gemfile:
group :production do
gem 'pg'
gem 'puma'
end
保存并退出。这指定production
环境应该使用pg
和puma
gems。
在配置Puma之前,您应该查找服务器具有的CPU核心数。您可以使用此命令轻松地在服务器上执行此操作:
grep -c processor /proc/cpuinfo
现在,在您的开发计算机上,在config/puma.rb
中添加Puma配置。在文本编辑器中打开文件:
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
更改服务器的CPU核心数workers
。该示例假设您有2个核心。
保存并退出。这会将Puma配置为应用程序的位置,以及其接口,日志和PID的位置。随意修改文件,或添加您需要的任何其他选项。
提交您最近的更改:
git add -A
git commit -m 'added pg and puma'
在继续之前,生成一个将用于应用程序生产环境的密钥:
rake secret
rake secret sample output:29cc5419f6b0ee6b03b717392c28f5869eff0d136d8ae388c68424c6e5dbe52c1afea8fbec305b057f4b071db1646473c1f9a62f803ab8386456ad3b29b14b89
您将复制输出并使用它在下一步中设置应用程序的SECRET_KEY_BASE
。
让我们创建一个Upstart 初始化脚本,这样我们就可以轻松启动和停止Puma,并确保它在启动时启动。
在生产服务器上,从Puma GitHub存储库下载Jungle 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启动。这意味着即使在重新启动服务器后,您的应用程序也会启动。请记住,我们尚未部署应用程序,因此我们暂时还不想启动它。
为了使应用程序可以访问Internet,我们应该使用Nginx作为Web服务器。
使用apt-get安装Nginx:
sudo apt-get install nginx
现在使用文本编辑器打开默认服务器块:
sudo vi /etc/nginx/sites-available/default
使用以下代码块替换文件的内容。请务必使用适当的用户名和应用程序名称(两个位置)替换deploy/appname的部分:
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,因为服务器上还没有应用程序。我们接下来准备申请。
在生产服务器上,使用apt-get安装git:
sudo apt-get install git
然后为远程存储库创建一个目录。我们将在主目录中创建一个名为“appname_production”的裸git存储库。随意将您的远程存储库命名为您想要的任何名称(除非不将其放入~/appname
,因为这是我们将应用程序部署到的地方):
mkdir ~/appname_production
cd ~/appname_production
git init --bare
由于这是一个裸存储库,因此没有工作目录,并且传统设置中位于.git中的所有文件都在主目录中。
我们需要创建post-receive git hook,这是在生产服务器收到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 remote(appname_production
)时将运行的命令。如果保持原样,服务器将尝试对应用程序的生产环境执行以下操作:
如果您想进行任何更改或添加错误检查,请随时在此处执行此操作。
完成查看接收后脚本后,保存并退出。
接下来,使脚本可执行:
chmod +x hooks/post-receive
因为post-receive hook需要运行sudo命令,我们将允许deploy用户使用无密码sudo
(如果不同,请在此处替换您的部署用户名):
sudo sh -c 'echo "deploy ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/90-deploy'
这将允许deploy
用户在不提供密码的情况下运行sudo
命令。请注意,您可能希望限制部署用户可以使用超级用户权限运行的命令。您至少需要使用SSH密钥身份验证并禁用密码身份验证。
现在我们已经在生产服务器上设置了所有内容,让我们将生产git remote添加到我们的应用程序的存储库中。
在开发计算机上,确保您位于应用程序的目录中:
cd ~/appname
然后添加一个名为“production”的新git远程,它指向您在生产服务器上创建的裸git存储库appname_production
。替换用户名(部署),服务器IP地址和远程存储库名称(appname_production):
git remote add production deploy@production_server_public_IP:appname_production
现在您的应用程序已准备好使用git push进行部署。
完成所有准备工作后,您现在可以通过运行以下git命令将应用程序部署到生产服务器:
git push production master
这只是将您的本地主分支推送到您之前创建的生产远程中。当生产远程接收推送时,它将执行我们之前设置的post-receive
hook脚本。如果正确设置了所有内容,现在应该可以在生产服务器的公共IP地址上使用您的应用程序。
如果您使用我们的示例应用程序,您应该能够在Web浏览器中访问http://production_server_IP/tasks
并看到如下内容:
每次对应用程序进行更改时,都可以运行相同的git push命令来部署到生产服务器。仅此一项就可以在项目的整个生命周期中为您节省大量时间。
本教程仅介绍了“post-receive”hook,但还有其他几种类型的挂钩可以帮助改善部署过程的自动化。
想要了解更多关于Linux开源信息教程,请前往腾讯云+社区学习更多知识。
参考文献:《How To Deploy a Rails App with Git Hooks on Ubuntu 14.04》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。