作者选择技术教育基金作为Write for DOnations计划的一部分接受捐赠。
介绍
当开发人员对应用程序进行连续更改时,具有webhook的部署系统可以简化开发,特别是对于团队。 如果团队的一部分依赖像API这样的后端软件,那么将用于代码更改的Slack通知集成到团队的工作流程中也会很有帮助。
在本教程中,您将使用create-react-app
npm
包构建一个React应用程序 。 该软件包简化了通过语法转换引导React项目并使用依赖项和先决条件工具简化工作的工作。 将您的应用程序代码添加到GitHub存储库后,您将配置Nginx以提供更新的项目文件。 然后,您将下载并设置webhook服务器,并配置GitHub以在代码修改时与其通信。 最后,您将配置Slack作为另一个webhook服务器,当成功部署被触发时,它将接收通知。
最终,您在本文中构建的部署系统将如下所示:
这个简短的视频显示了一个空的提交并推送到GitHub存储库,这会触发Slack中的应用程序构建和通知。
先决条件
要完成本教程,您需要:
- Ubuntu 16.04服务器,您可以通过使用Ubuntu 16.04教程遵循初始服务器设置来设置服务器 。 遵循本指南后,您应该拥有一个具有sudo权限的非root用户帐户。
- 通过遵循Ubuntu 16.04上的如何安装Nginx的前两步,Nginx安装在您的服务器上 。
- 在本地机器和服务器上配置Git。 您可以在本教程中找到关于安装和配置Git的说明,了解如何开始使用Git 。
- Node.js和
npm
安装在本地机器和服务器上。 对于您的服务器,请遵循关于如何在Ubuntu 16.04上安装Node.js的PPA中安装Node.js的说明 。 在本地机器上,您可以按照项目的安装说明进行操作 。 - 按照安装纱线的官方指南,在您的服务器上安装纱线 。
- 权限配置Slack和个别通道的通知。 您可以在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
该文件应该看起来像这样:
{
"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或域(如果适用):
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.html
,index.htm
,index.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
版本:
Outputwebhook version 2.6.5
接下来,让我们在/opt
目录中设置hooks
和scripts
文件夹,第三方应用程序的文件通常位于该文件夹中。 由于/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.sh
的redeploy.sh
脚本。 -
command-working-directory
:执行该命令时将使用的工作目录。 我们将使用/opt/scripts
因为这是redeploy.sh
所在的位置。 -
pass-arguments-to-command
:从HTTP请求传递给脚本的参数。 我们将传递一个提交消息,推送者名称,以及来自HTTP请求负载的提交ID。 这些相同的信息也将包含在你的Slack消息中。
/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.message
, pusher.name
和head_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
看起来像这样:
[
{
"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中,其中id
是hooks.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的地方:
#!/bin/bash -e
function cleanup {
echo "Error occoured"
# !!Placeholder for Slack notification
}
trap cleanup ERR
这告诉bash
解释器,如果脚本突然完成,它应该在cleanup
函数中运行代码。
接下来,在执行时提取webhook
传递给脚本的参数:
...
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
。
最后,让我们调用重新部署应用程序所需的命令:
...
cd ~/do-react-example-app/
git pull origin master
yarn && yarn build
# !!Placeholder for Slack notification
完整的脚本将如下所示:
#!/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
配置文件的位置。
你会看到这个输出:
Output[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
您将在服务器上看到如下所示的输出:
Output[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
:
#!/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.youcl.com/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.youcl.com/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.youcl.com/uploads/JTq5At3.png\"
}" your_slack_webhook_url
我们用一个稍微不同的curl
调用替换了每个占位符:
- 第一个确保我们收到执行脚本时发生的任何错误的通知。
- 第二个发送应用程序的构建已经开始的通知。
- 第三个发送构建已成功完成的通知。
有关Slack机器人和集成的更多信息,请参见Slack webhooks文档 。
再次,我们可以在本地项目目录中用空提交来测试我们的钩子。 离开webhook服务器运行,回到这个目录并创建空的提交:
git commit --allow-empty -m "Trigger notification"
将提交推送到主分支以触发构建:
git push origin master
输出(包括构建信息)将如下所示:
Output[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项目示例钩子页面 。