在Ubuntu 16.04上使用Webhooks和Slack部署React应用程序

当开发人员对应用程序进行连续更改时,具有webhook的部署系统可以简化开发,特别是对于团队。如果团队的一部分依赖像API这样的后端软件,那么将用于代码更改的Slack通知集成到团队的工作流程中也会很有帮助。在本教程中,您将使用`create-react-app`设置一个应用程序,并配置一个集成了GitHub和Slack的webhook部署系统。

作者选择技术教育基金作为Write for DOnations计划的一部分接受捐赠。

介绍

当开发人员对应用程序进行连续更改时,具有webhook的部署系统可以简化开发,特别是对于团队。 如果团队的一部分依赖像API这样的后端软件,那么将用于代码更改的Slack通知集成到团队的工作流程中也会很有帮助。

在本教程中,您将使用create-react-app npm构建一个React应用程序 该软件包简化了通过语法转换引导React项目并使用依赖项和先决条件工具简化工作的工作。 将您的应用程序代码添加到GitHub存储库后,您将配置Nginx以提供更新的项目文件。 然后,您将下载并设置webhook服务器,并配置GitHub以在代码修改时与其通信。 最后,您将配置Slack作为另一个webhook服务器,当成功部署被触发时,它将接收通知。

最终,您在本文中构建的部署系统将如下所示:

示例部署

这个简短的视频显示了一个空的提交并推送到GitHub存储库,这会触发Slack中的应用程序构建和通知。

先决条件

要完成本教程,您需要:

第1步 - 使用create-react-app创建React应用程序

首先构建我们将用于使用create-react-app测试webhook create-react-app 然后,我们可以创建一个GitHub存储库并将项目代码推送给它。

在本地机器上,将create-react-app节点模块添加到您的全局存储库,并在您的shell环境中使create-react-app命令可用:

sudo npm install -g create-react-app

接下来,运行create-react-app来创建一个名为do-react-example-app

create-react-app do-react-example-app

导航到do-react-example-app

cd do-react-example-app

使用nano或您最喜欢的文本编辑器,打开package.json文件:

nano package.json

该文件应该看起来像这样:

〜/ DO-反应-示例应用内/的package.json

{
  "name": "do-react-example-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-scripts": "1.0.17"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

package.json文件包含以下脚本:

  • start :此脚本负责启动应用程序的开发版本。 它运行一个服务于该应用程序的HTTP服务器。
  • build :这个脚本负责制作应用程序的生产版本。 您将在服务器上使用此脚本。
  • test :此脚本运行与项目相关的默认测试。
  • eject :此脚本是create-react-app软件包的高级功能。 如果开发人员对包中提供的构建环境不满意,可以“弹出”应用程序,这将产生不可用的选项(包括自定义CSS转换器和JS处理工具等)。

完成检查代码后关闭文件。

接下来,我们为该项目创建一个GitHub存储库。 你可以按照这个教程创建一个GitHub仓库来获得指导。 记下存储库的来源(即其GitHub URL)。

回到你的do-react-example-app目录中,用git初始化仓库:

git init

接下来,使用您的GitHub网址添加远程来源:

git remote add origin your-github-url

在项目目录中放置所有文件:

git add .

提交他们:

git commit -m "initial commit"

并将它们推送到存储库:

git push origin master

有关创建GitHub存储库和使用git初始化现有应用程序的更多信息,请参阅GitHub的文档

完成存储库设置后,我们可以继续在我们的服务器上指定配置详细信息。

第2步 - 目录设置和Nginx配置

使用存储库后,现在可以从GitHub获取应用程序代码,并配置Nginx来为应用程序提供服务。

登录到您的服务器,转到您的主目录,然后克隆您的存储库:

cd ~
git clone your-github-url

转到克隆的项目:

cd do-react-example-app

要在项目中创建构建目录以及Nginx提供的文件,您将需要运行yarn build命令。 这将运行项目的构建脚本,创建构建目录。 该文件夹包括一个index.html文件,一个JavaScript文件和一个CSS文件。 yarn命令将为您的项目下载所有需要的节点模块:

yarn && yarn build

接下来,我们将/var/www/目录中的符号链接创建到~/do-react-example-app目录。 这将使应用程序保持在我们的主目录中,同时使Nginx能够从/var/www目录中提供服务:

sudo ln -s ~/do-react-example-app /var/www/do-react-example-app

请注意,这会链接到项目目录,而不是链接到生成目录,而生成目录的更改频率更高。 创建此链接对于您部署应用程序的新版本的情况特别有用:通过创建指向稳定版本的链接,可以简化随后部署更多版本的过程。 如果出现问题,您也可以用相同的方式恢复到以前的版本。

应该在符号链接上设置一些权限,以便Nginx能够正确地提供它:

sudo chmod -R 755 /var/www

接下来,让我们配置一个Nginx服务器块来为构建目录提供服务。 输入以下内容以创建新的服务器配置

sudo nano /etc/nginx/sites-available/test-server

复制以下配置,将your_server_ip_or_domain替换为您的IP或域(如果适用):

在/ etc / nginx的/网站可用/测试服务器
server {
        listen 80;

        root /var/www/do-react-example-app/build;
        index index.html index.htm index.nginx-debian.html;

        server_name your_server_ip_or_domain;

        location / {
                try_files $uri /index.html;
        }
}

该文件中的指令包括:

  • listen :配置服务器监听端口的属性。
  • root :Ngnix将从中提供文件的文件夹的路径。
  • index :服务器首先尝试提供的文件。 它会尝试从/var/www/ do-react-example-app /build目录中提供以下任何文件: index.htmlindex.htmindex.nginx-debian.html ,优先级index.nginx-debian.html
  • server_name :服务器域名或IP。

接下来,在sites-enabled目录中创建一个符号链接:

sudo ln -s /etc/nginx/sites-available/test-server /etc/nginx/sites-enabled/test-server

这将告诉Nginx从sites-available文件夹启用服务器块配置。

检查配置是否有效:

sudo nginx -t

最后,重新启动Nginx以应用新的配置:

sudo systemctl restart nginx

有了这些配置详细信息,我们可以继续配置webhook。

第3步 - 安装和配置Webhooks

Webhooks是简单的HTTP服务器,具有可配置的端点挂钩 在收到HTTP请求后,webhook服务器执行符合一组可配置规则的可定制代码。 已经有很多webhook服务器集成到互联网上的应用程序中,包括Slack。

使用最广泛的webhook服务器是使用 Go编写的Webhook 我们将使用这个工具来设置我们的webhook服务器。

确保您位于服务器的主目录中:

cd ~

然后下载webhook

wget https://github.com/adnanh/webhook/releases/download/2.6.6/webhook-linux-amd64.tar.gz

提取它:

tar -xvf webhook-linux-amd64.tar.gz

通过将二进制文件移动到/usr/local/bin使二进制文件在您的环境中可用:

sudo mv webhook-linux-amd64/webhook /usr/local/bin

最后,清理下载的文件:

rm -rf webhook-linux-amd64*

通过输入以下内容在您的环境中测试webhook的可用性:

webhook -version

输出应显示webhook版本:

webhook version 2.6.5

接下来,让我们在/opt目录中设置hooksscripts文件夹,第三方应用程序的文件通常位于该文件夹中。 由于/opt目录通常由root拥有,因此我们可以使用root权限创建目录,然后将所有权转移给本地$USER

首先,创建目录:

sudo mkdir /opt/scripts
sudo mkdir /opt/hooks

然后将所有权转移给您的$USER

sudo chown -R $USER:$USER /opt/scripts
sudo chown -R $USER:$USER /opt/hooks

接下来,让我们通过创建一个hooks.json文件来配置webhook服务器。 使用nano或您最喜欢的编辑器,在/opt/hooks目录中创建hooks.json文件:

nano /opt/hooks/hooks.json

为了在GitHub发送HTTP请求时触发webhook ,我们的文件将需要一个JSON数组规则。 这些规则由以下属性组成:

{
    "id": "",
    "execute-command": "",
    "command-working-directory": "",
    "pass-arguments-to-command": [],
    "trigger-rule": {}
}

具体而言,这些规则定义了以下信息:

  • id :webhook服务器将要提供的端点的名称。 我们将称此redeploy-app
  • execute-command :触发​​挂钩时将执行的脚本路径。 在我们的例子中,这将是位于/opt/scripts/redeploy.shredeploy.sh脚本。
  • command-working-directory :执行该命令时将使用的工作目录。 我们将使用/opt/scripts因为这是redeploy.sh所在的位置。
  • pass-arguments-to-command :从HTTP请求传递给脚本的参数。 我们将传递一个提交消息,推送者名称,以及来自HTTP请求负载的提交ID。 这些相同的信息也将包含在你的Slack消息中。

/opt/hooks/hooks.json文件应包含以下信息:

/opt/hooks/hooks.json
[
  {
    "id": "redeploy-app",
    "execute-command": "/opt/scripts/redeploy.sh",
    "command-working-directory": "/opt/scripts",
    "pass-arguments-to-command":
    [
      {
        "source": "payload",
        "name": "head_commit.message"
      },
      {
        "source": "payload",
        "name": "pusher.name"
      },
      {
        "source": "payload",
        "name": "head_commit.id"
      }
    ],
    "trigger-rule": {}
  }
]

GitHub HTTP POST请求的负载包括head_commit.messagepusher.namehead_commit.id属性。 当一个配置好的事件(比如PUSH)发生在你的GitHub仓库中时,GitHub会发送一个POST请求和一个包含事件信息的JSON主体。 这些POST有效载荷的一些示例可以在GitHub Event Types文档中找到

配置文件中的最后一个属性是trigger-rule属性,它告诉webhook服务器在哪个条件下会触发该钩子。 如果留空,钩子将始终被触发。 在我们的例子中,我们将配置钩子,当GitHub发送POST请求到我们的webhook服务器时被触发。 具体来说,只有在HTTP请求中的GitHub秘密(在这里表示为your-github-secret )与规则中的your-github-secret匹配并且提交发生在master分支中时才会触发它。

添加以下代码来定义trigger-rule ,用您选择的密码替换your-github-secret

... 
    "trigger-rule":
    {
      "and":
      [
        {
          "match":
          {
            "type": "payload-hash-sha1",
            "secret": "your-github-secret", 
            "parameter":
            {
              "source": "header",
              "name": "X-Hub-Signature"
            }
          }
        },
        {
          "match":
          {
            "type": "value",
            "value": "refs/heads/master",
            "parameter":
            {
              "source": "payload",
              "name": "ref"
            }
          }
        }
      ]
    }
  }
]

完整地,/ /opt/hooks/hooks.json看起来像这样:

/opt/hooks/hooks.json
[
  {
    "id": "redeploy-app",
    "execute-command": "/opt/scripts/redeploy.sh",
    "command-working-directory": "/opt/scripts",
    "pass-arguments-to-command":
    [
      {
        "source": "payload",  
        "name": "head_commit.message"
      },
      {
        "source": "payload",
        "name": "pusher.name"
      },
      {
        "source": "payload",
        "name": "head_commit.id"
      }
    ],
    "trigger-rule":
    {
      "and":
      [
        {
          "match":
          {
            "type": "payload-hash-sha1",
            "secret": "your-github-secret", 
            "parameter":
            {
              "source": "header",
              "name": "X-Hub-Signature"
            }
          }
        },
        {
          "match":
          {
            "type": "value",
            "value": "refs/heads/master",
            "parameter":
            {
              "source": "payload",
              "name": "ref"
            }
          }
        }
      ]
    }
  }
]

最后一个要检查的配置项是服务器的防火墙设置。 webhook服务器将在端口9000上监听。 这意味着如果服务器上运行防火墙,则需要允许连接到该端口。 要查看当前防火墙规则的列表,请键入:

sudo ufw status

如果端口9000未包含在列表中,请启用它:

sudo ufw allow 9000

有关ufw更多信息,请参阅ufw essentials的介绍。

接下来,让我们设置我们的GitHub存储库来发送HTTP请求到这个端点。

第4步 - 配置GitHub通知

让我们配置我们的GitHub存储库,以便在发生主机提交时发送HTTP请求:

  • 1.转到您的存储库并单击设置
  • 2.然后转到Webhooks并单击位于右上角的添加Webhook
  • 3.对于Payload URL ,键入您的服务器地址,如下所示: http:// your_server_ip :9000/hooks/ redeploy-app 如果您有域名,则可以使用它来代替your_server_ip 请注意,端点名称与钩子定义中的id属性相匹配。 这是webhook实现的一个细节:在hooks.json定义的所有钩子hooks.json将以http:// your_server_ip :9000/hooks/ id出现在URL中,其中idhooks.json文件中的id
  • 4.对于内容类型 ,选择application / json
  • 5.对于Secret ,键入您在hooks.json定义中设置的秘密( your-github-secret )。
  • 6. 你想要触发这个webhook的事件? 选择“ 仅推送”事件
  • 7.点击添加webhook按钮。

现在,当有人向您的存储库推送提交时,GitHub将发送POST请求,其中包含有关提交事件信息的有效内容。 在其他有用的属性中,它将包含我们在触发器规则中定义的属性,所以我们的webhook服务器可以检查POST请求是否有效。 如果是,它将包含其他信息,如pusher.name

可以在GitHub Webhooks页面上找到有效负载发送的属性的完整列表。

第5步 - 编写部署/重新部署脚本

此时,我们已将webhook指向redeploy.sh脚本,但我们并未创建脚本。 它将完成从我们的存储库中提取最新的master分支,安装节点模块并执行build命令的工作。

创建脚本:

nano /opt/scripts/redeploy.sh

首先,让我们在脚本的顶部添加一个函数来清除它创建的所有文件。 如果重新部署未成功完成,我们也可以将此用作通知第三方软件如Slack的地方:

/opt/scripts/redeploy.sh
#!/bin/bash -e

function cleanup {
      echo "Error occoured"
      # !!Placeholder for Slack notification
}
trap cleanup ERR

这告诉bash解释器,如果脚本突然完成,它应该在cleanup函数中运行代码。

接下来,在执行时提取webhook传递给脚本的参数:

/opt/scripts/redeploy.sh
...

commit_message=$1 # head_commit.message
pusher_name=$2 # pusher.name
commit_id=$3 # head_commit.id


# !!Placeholder for Slack notification

请注意,参数的顺序与hooks.json文件中的pass-arguments-to-command属性相对hooks.json

最后,让我们调用重新部署应用程序所需的命令:

/opt/scripts/redeploy.sh
...

cd ~/do-react-example-app/
git pull origin master
yarn && yarn build

# !!Placeholder for Slack notification

完整的脚本将如下所示:

/opt/scripts/redeploy.sh
#!/bin/bash -e

function cleanup {
      echo "Error occoured"
      # !!Placeholder for Slack notification
}
trap cleanup ERR

commit_message=$1 # head_commit.message
pusher_name=$2 # pusher.name
commit_id=$3 # head_commit.id

# !!Placeholder for Slack notification

cd ~/do-react-example-app/
git pull origin master
yarn && yarn build

# !!Placeholder for Slack notification

该脚本将转到该文件夹​​,从最新的主分支中提取代码,安装新软件包,并构建应用程序的生产版本。

注意!!Placeholder for Slack notification 这是本教程最后一步的占位符。 没有通知,就没有真正的方法知道脚本是否正确执行。

使脚本可执行,以便挂钩可以执行它:

chmod +x /opt/scripts/redeploy.sh

由于Nginx配置为从/var/www/ do-react-example-app /build ,因此当此脚本执行时,构建目录将被更新,Nginx将自动提供新文件。

现在我们准备测试配置。 让我们运行webhook服务器:

webhook -hooks /opt/hooks/hooks.json -verbose

-hooks参数告诉webhook配置文件的位置。

你会看到这个输出:

[webhook] 2017/12/10 13:32:03 version 2.6.5 starting
[webhook] 2017/12/10 13:32:03 setting up os signal watcher
[webhook] 2017/12/10 13:32:03 attempting to load hooks from /opt/hooks/hooks.json
[webhook] 2017/12/10 13:32:03 os signal watcher ready
[webhook] 2017/12/10 13:32:03 found 1 hook(s) in file
[webhook] 2017/12/10 13:32:03   loaded: redeploy-app
[webhook] 2017/12/10 13:32:03 serving hooks on http://0.0.0.0:9000/hooks/{id}

这告诉我们一切都已正确加载,并且我们的服务器现在通过URL http://0.0.0.0:9000/hooks/ redeploy-app服务于hook http://0.0.0.0:9000/hooks/ redeploy-app 这暴露了可以执行的服务器上的路径或挂钩。 如果你现在用这个URL做一个简单的REST调用(比如GET),没有什么特别的事情会发生,因为钩子规则不被满足。 如果我们希望成功触发该钩子,则必须完成我们在hooks.json定义的trigger-rule

让我们用本地项目目录中的空提交进行测试。 离开webhook服务器运行,返回到本地机器并键入以下内容:

git commit --allow-empty -m "Trigger notification"

将提交推送到主分支:

git push origin master

您将在服务器上看到如下所示的输出:

[webhook] 2018/06/14 20:05:55 [af35f1] incoming HTTP request from 192.30.252.36:49554
[webhook] 2018/06/14 20:05:55 [af35f1] redeploy-app got matched
[webhook] 2018/06/14 20:05:55 [af35f1] redeploy-app hook triggered successfully
[webhook] 2018/06/14 20:05:55 200 | 726.412µs | 203.0.113.0:9000 | POST /hooks/redeploy-app
[webhook] 2018/06/14 20:05:55 [af35f1] executing /opt/scripts/redeploy.sh (/opt/scripts/redeploy.sh) with arguments ["/opt/scripts/redeploy.sh" "Trigger notification" "sammy" "82438acbf82f04d96c53cd684f8523231a1716d2"] and environment [] using /opt/scripts as cwd

现在让我们添加Slack通知,并查看挂钩通过通知触发成功构建时会发生什么。

第6步 - 添加Slack通知

要在重新部署应用程序时接收Slack通知,可以修改redeploy.sh脚本将HTTP请求发送到Slack。 通过在Slack配置面板中启用Webhook集成 ,还需要配置Slack以接收来自服务器的通知。 从Slack获得Webhook URL后,您可以将有关Slack webhook服务器的信息添加到脚本中。

要配置Slack,请执行以下步骤:

  • 1.在Slack应用程序的主屏幕上,单击位于左上角的下拉菜单并选择Customize Slack
  • 2.接下来,转到位于左侧边栏菜单中配置应用程序部分。
  • 3.在“ 管理”面板中,从左侧选项列表中选择“ 自定义集成 ”。
  • 4.搜索传入WebHooks集成。
  • 5.单击添加配置
  • 6.选择一个现有频道或创建一个新频道。
  • 7.单击添加传入WebHooks集成

之后,您将看到一个显示Slack webhook设置的屏幕。 记下Webhook URL ,它是由Slack webhook服务器生成的端点。 当您完成记录此URL并做出其他更改时,请务必按页面底部的保存设置按钮。

返回到您的服务器并打开redeploy.sh脚本:

nano /opt/scripts/redeploy.sh

在上一步中,我们在Slack通知的脚本中留下了占位符,表示为!!Placeholder for Slack notification 我们现在将用curl调用这些调用来将这些POST请求发送到Slack webhook服务器。 Slack钩子期望JSON正文,然后它将解析,在通道中显示适当的通知。

使用以下curl调用替换!!Placeholder for slack notification!!Placeholder for slack notification 请注意,您需要使用前面提到的Webhook URL替换your_slack_webhook_url

/opt/scripts/redeploy.sh
#!/bin/bash -e

function cleanup {
      echo "Error occoured"
      curl -X POST -H 'Content-type: application/json' --data "{
              \"text\": \"Error occoured while building app with changes from ${pusher_name} (${commit_id} -> ${commit_message})\",
              \"username\": \"buildbot\",
              \"icon_url\": \"https://www.howtoing.com/wp-content/uploads/JTq5At3.png\"
      }" your_slack_webhook_url
}
trap cleanup ERR

commit_message=$1 # head_commit.message
pusher_name=$2 # pusher.name
commit_id=$3 # head_commit.id

curl -X POST -H 'Content-type: application/json' --data "{
        \"text\": \"Started building app with changes from ${pusher_name} (${commit_id} -> ${commit_message})\",
        \"username\": \"buildbot\",
        \"icon_url\": \"https://www.howtoing.com/wp-content/uploads/JTq5At3.png\"
}" your_slack_webhook_url

cd ~/do-react-example-app/
git pull origin master
yarn && yarn build

curl -X POST -H 'Content-type: application/json' --data "{
        \"text\": \"Build and deploy finished with changes from ${pusher_name} (${commit_id} -> ${commit_message})\",
        \"username\": \"buildbot\",
        \"icon_url\": \"https://www.howtoing.com/wp-content/uploads/JTq5At3.png\"
}" your_slack_webhook_url

我们用一个稍微不同的curl调用替换了每个占位符:

  • 第一个确保我们收到执行脚本时发生的任何错误的通知。
  • 第二个发送应用程序的构建已经开始的通知。
  • 第三个发送构建已成功完成的通知。

有关Slack机器人和集成的更多信息,请参见Slack webhooks文档

再次,我们可以在本地项目目录中用空提交来测试我们的钩子。 离开webhook服务器运行,回到这个目录并创建空的提交:

git commit --allow-empty -m "Trigger notification"

将提交推送到主分支以触发构建:

git push origin master

输出(包括构建信息)将如下所示:

[webhook] 2018/06/14 20:09:55 [1a67a4] incoming HTTP request from 192.30.252.34:62900
[webhook] 2018/06/14 20:09:55 [1a67a4] redeploy-app got matched
[webhook] 2018/06/14 20:09:55 [1a67a4] redeploy-app hook triggered successfully
[webhook] 2018/06/14 20:09:55 200 | 462.533µs | 203.0.113.0:9000 | POST /hooks/redeploy-app
[webhook] 2018/06/14 20:09:55 [1a67a4] executing /opt/scripts/redeploy.sh (/opt/scripts/redeploy.sh) with arguments ["/opt/scripts/redeploy.sh" "Trigger notification" "sammy" "5415869a4f126ccf4bfcf2951bcded69230f85c2"] and environment [] using /opt/scripts as cwd
[webhook] 2018/06/14 20:10:05 [1a67a4] command output:   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   228    0     2  100   226     11   1324 --:--:-- --:--:-- --:--:--  1329
okFrom https://github.com/sammy/do-react-example-app
 * branch            master     -> FETCH_HEAD
   82438ac..5415869  master     -> origin/master
Updating 82438ac..5415869
Fast-forward
yarn install v1.7.0
[1/4] Resolving packages...
success Already up-to-date.
Done in 1.16s.
yarn run v1.7.0
$ react-scripts build
Creating an optimized production build...
Compiled successfully.

File sizes after gzip:

  36.94 KB  build/static/js/main.a0b7d8d3.js
  299 B     build/static/css/main.c17080f1.css

The project was built assuming it is hosted at the server root.
You can control this with the homepage field in your package.json.
For example, add this to build it for GitHub Pages:

  "homepage" : "http://myname.github.io/myapp",

The build folder is ready to be deployed.
You may serve it with a static server:

  yarn global add serve
  serve -s build

Find out more about deployment here:

  http://bit.ly/2vY88Kr

Done in 7.72s.
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   233    0     2  100   231     10   1165 --:--:-- --:--:-- --:--:--  1166
ok
[webhook] 2018/06/14 20:10:05 [1a67a4] finished handling redeploy-app

在Slack中,您将收到消息给您选择的频道,通知您应用程序构建已经开始以及何时完成。

结论

我们现在已经完成了使用webhooks,Nginx,shell脚本和Slack的部署系统。 你现在应该能够:

  • 配置Nginx以处理应用程序的动态构建。
  • 设置webhook服务器并写入在GitHub POST请求上触发的钩子。
  • 编写触发应用程序构建和通知的脚本。
  • 配置Slack以接收这些通知。

本教程中的系统可以扩展,因为webhook服务器是模块化的,可以配置为与其他应用程序(如GitLab)配合使用 如果通过JSON配置webhook服务器太多,可以使用Hookdoo构建类似的设置。 有关如何为webhook配置触发器规则的更多信息,请参阅webhook项目示例钩子页面