如何在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。 如果您还没有这样做,您可以使用 rbenvRVM 将它与 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 环境应该使用 pgpuma 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

查找指定 setuidsetgid 的两行,并将“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 钩子自动化开发和部署任务