如何在Ubuntu14.04上使用GitHooks部署Rails应用程序
介绍
在本教程中,我们将向您展示如何使用 Git 挂钩自动将 Rails 应用程序的生产环境部署到远程 Ubuntu 14.04 服务器。 使用 Git 挂钩将允许您通过简单地将更改推送到生产服务器来部署应用程序,而不必手动拉取并执行诸如执行数据库迁移之类的事情。 当您继续处理您的应用程序时,设置某种形式的自动部署,例如 Git 挂钩,从长远来看将节省您的时间。
除了 Puma 作为应用程序服务器、Nginx 作为 Puma 的反向代理以及 PostgreSQL 作为数据库之外,这个特定的设置使用了一个简单的“post-receive”Git 挂钩。
如果您是 Git Hooks 的新手并且想在继续之前了解更多信息,请阅读本教程:如何使用 Git Hooks 自动化开发和部署任务。
先决条件
您将需要访问在您的 Ubuntu 服务器上具有超级用户权限的非 root 用户。 在我们的示例设置中,我们将使用一个名为 deploy
的用户。 本教程将向您展示如何设置: 使用 Ubuntu 14.04 进行初始服务器设置。 如果您想在不输入密码的情况下进行部署,请务必设置 SSH 密钥。
您需要在服务器上安装 Ruby。 如果您还没有这样做,您可以使用 rbenv 或 RVM 将它与 Rails 一起安装。
您还需要有一个在本地开发机器上的 git 存储库中管理的 Rails 应用程序。 如果您还没有并且想继续学习,我们将提供一个简单的示例应用程序。
让我们开始吧!
安装 PostgreSQL
大多数生产 Rails 环境都使用 PostgreSQL 作为数据库,所以现在让我们将它安装在您的服务器上。
在您的 production 服务器上,更新 apt-get:
sudo apt-get update
然后使用以下命令安装 PostgreSQL:
sudo apt-get install postgresql postgresql-contrib libpq-dev
注意: 你还应该在你的开发机器上安装 PostgreSQL,这样你就可以在本地安装 PostgreSQL 适配器 pg
gem。 当我们将 gem 添加到应用程序的 Gemfile 时,这将是运行 bundle install
所必需的。 由于安装步骤因操作系统而异,因此这是留给读者的练习。
创建生产数据库用户
为简单起见,让我们将生产数据库用户命名为与您的应用程序名称相同。 例如,如果您的应用程序名为“appname”,您应该像这样创建一个 PostgreSQL 用户:
sudo -u postgres createuser -s appname
我们要设置数据库用户的密码,所以像这样进入 PostgreSQL 控制台:
sudo -u postgres psql
然后设置数据库用户的密码,示例中为“appname”,如下所示:
\password appname
输入您想要的密码并确认。
使用以下命令退出 PostgreSQL 控制台:
\q
现在我们已准备好使用正确的数据库连接信息配置您的应用程序。
准备 Rails 应用程序
在您的 开发机器 上,很可能是您的本地计算机,我们将准备您的应用程序以进行部署。
可选:创建 Rails 应用程序
理想情况下,您已经有一个要部署的 Rails 应用程序。 如果是这种情况,您可以跳过本小节,并在继续进行时进行适当的替换。 如果没有,第一步是创建一个新的 Rails 应用程序。
这些命令将在我们的主目录中创建一个名为“appname”的新 Rails 应用程序。 随意将突出显示的“appname”替换为其他内容:
cd ~ rails new appname
然后切换到应用程序目录:
cd appname
对于我们的示例应用程序,我们将生成一个脚手架控制器,以便我们的应用程序可以显示一些内容:
rails generate scaffold Task title:string note:text
现在让我们确保我们的应用程序位于 git 存储库中。
初始化 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 部分,并将其替换为您的生产数据库连接信息。 如果您完全按照示例设置,它将看起来像这样(在适当的地方替换任何值):
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
gems。
配置彪马
在配置 Puma 之前,您应该查看服务器拥有的 CPU 内核数。 您可以在您的服务器上使用以下命令轻松地做到这一点:
grep -c processor /proc/cpuinfo
现在,在您的 开发机 上,将 Puma 配置添加到 config/puma.rb
。 在文本编辑器中打开文件:
vi config/puma.rb
将此配置复制并粘贴到文件中:
配置/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 初始化脚本,以便我们可以轻松地启动和停止 Puma,并确保它将在启动时启动。
在您的 生产服务器 上,将 Jungle Upstart 工具从 Puma GitHub 存储库下载到您的主目录:
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
的两行,并将“apps”替换为您的部署用户和组的名称。 例如,如果您的部署用户名为“deploy”,则行应如下所示:
puma.conf 摘录 1 of 2
setuid deploy setgid deploy
现在查找包含以下内容的行:exec /bin/bash <<'EOT'
。 在其下添加以下行,确保替换 PostgreSQL 用户名和密码,以及您之前创建的 rake 密码:
puma.conf 摘录 2 of 2
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”的目录中。 在我们的示例中,它将如下所示(确保更新您的应用程序所在的路径:
/etc/puma.conf
/home/deploy/appname
保存并退出。
现在,您的应用程序已通过 Upstart 配置为在引导时启动。 这意味着即使您的服务器重新启动,您的应用程序也会启动。 请记住,我们尚未部署应用程序,因此我们还不想启动它。
安装和配置 Nginx
为了使应用程序可以访问互联网,我们应该使用 Nginx 作为 Web 服务器。
使用 apt-get 安装 Nginx:
sudo apt-get install nginx
现在使用文本编辑器打开默认服务器块:
sudo vi /etc/nginx/sites-available/default
用以下代码块替换文件的内容。 请务必将突出显示的部分替换为适当的用户名和应用程序名称(两个位置):
/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 远程
在您的 生产服务器 上,使用 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 远程 (appname_production
) 时将运行的命令。 如果您保持原样,服务器将尝试为您的应用程序的生产环境执行以下操作:
- 运行捆绑器
- 创建数据库
- 迁移数据库
- 预编译资产
- 重启彪马
- 重启 Nginx
如果您想进行任何更改或添加错误检查,请随时在此处进行。
查看完接收后脚本后,保存并退出。
接下来,使脚本可执行:
chmod +x hooks/post-receive
无密码须藤
因为 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
然后添加一个名为“production”的新 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 地址上使用。
如果您使用我们的示例应用程序,您应该能够在 Web 浏览器中访问 http://production_server_IP/tasks
并看到如下内容:
结论
每当您对应用程序进行更改时,您都可以运行相同的 git push 命令来部署到生产服务器。 仅此一项就可以在项目的整个生命周期中为您节省大量时间。
本教程仅介绍了“post-receive”钩子,但还有其他几种类型的钩子可以帮助提高部署过程的自动化程度。 阅读本教程以了解有关 Git 钩子的更多信息:如何使用 Git 钩子自动化开发和部署任务!