github webhooks 实现网站主动更新

打印 上一主题 下一主题

主题 758|帖子 758|积分 2274

本文目录



  • Github Webhooks 介绍
  • Webhooks 工作原理
  • 配置与验证
  • 应用
  • 云服务器通过 Webhook 主动摆设网站


    • 实现


      • 复制私钥
      • 编写 webhook 接口
      • Github 仓库配置 webhook
      • 以服务的情势运行 app.py


Github Webhooks 介绍

Webhooks是GitHub提供的一种关照方式,当GitHub上发生特定事件时,会向指定的外部Web服务器发送HTTP POST哀求,从而关照这些服务器有关事件的信息。
通过配置Webhooks,开辟者可以在GitHub上发生特定事件时(如代码推送、拉取哀求创建、评论等),主动接收事件数据,并在外部服务器上执行相应的操纵,如一连集成、代码审查、摆设等。
Webhooks 工作原理

事件触发:当GitHub上发生订阅的事件时(如代码推送到特定分支),GitHub会辨认这一事件并触发Webhook。
发送哀求:GitHub 将构造一个包含事件数据的 HTTP POST 哀求,并将该哀求发送到开辟者在 Webhook 配置中指定的 URL。
接收与处理处罚:外部 Web 服务器接收来自 GitHub 的 POST 哀求,并解析哀求体中的事件数据。根据事件数据的详细内容,服务器可以执行相应的操纵,如触发构建流程、发送关照、更新数据库等。
配置与验证

配置 Webhook:在GitHub上,开辟者可以为特定的仓库或构造配置Webhook。配置过程中,需要指定Webhook的URL(即外部Web服务器的接收地址)以及要订阅的事件类型。
安全验证:为了确保Webhook的安全性,GitHub提供了Secret密钥和署名验证机制。开辟者可以在配置Webhook时设置一个Secret密钥,GitHub在发送POST哀求时,会使用该密钥对哀求体进行哈希盘算,并将哈希值包含在哀求头中(如X-Hub-Signature-256)。外部Web服务器在接收哀求时,可以使用雷同的Secret密钥对哀求体进行哈希盘算,并将盘算得到的哈希值与哀求头中的哈希值进行比力,以验证哀求的真实性。
应用

应用场景


  • 一连集成:今世码推送到GitHub时,主动触发构建和测试流程。
  • 代码审查:当拉取哀求创建或更新时,主动关照审查者进行代码审查。
  • 摆设:当构建乐成或测试通逾期,主动将代码摆设到生产环境。
  • 关照与监控:当发生特定事件时,向指定的关照渠道(如Slack、Discord等)发送关照。
上风


  • 实时性:Webhook答应在事件发生时立即接收关照并执行操纵,无需轮询API。
  • 主动化:通过Webhook,可以实现主动化的工作流程,减少手动操纵。
  • 可扩展性:Webhook可以与各种外部服务和工具集成,扩展GitHub的功能。
  • 安全性:通过Secret密钥和署名验证机制,确保Webhook的安全性。
云服务器通过 Webhook 主动摆设网站

GitHub 用来存放代码等资源,使用第三方网站托管平台或者云服务器来摆设网站的静态资源。本地的电脑上存放网站的静态资源,每次网站更新,执行 git push 命令将网站的静态资源上传到 Github 之后,GitHub 会通过 webhook 来关照第三方网站托管平台或者云服务器执行 pull 操纵,从 GitHub 仓库中拉取网站的静态资源,主动摆设网站。
第三方网站托管平台有很多,自行上网搜索,且操纵流程都很简单,都是主动的,不需要执行什么操纵。这里就不做介绍。
下面介绍的是在云服务器上摆设网站,使其在仓库更新时主动从 GitHub 上拉取网站的静态资源摆设到云服务器的 Tomcat 上。
至于云服务器摆设 tomcat,请参见往期文章 Ubuntu 服务器摆设 Tomcat 并配置 SSL/TLS 证书 。

思绪:创建一个可以接收 webhook HTTP POST 的历程,使用 Tomcat 用户的权限并以系统服务的情势将该历程一直运行在后台,以接收 Github webhook HTTP POST。使用 ssh 协议从 Github 拉取网站代码并进行网站摆设。

实现

ssl 长途云服务器:ssl -i "/path/to/id_rsa" user@server_IP
提升管理员权限 sudo -i 。
复制私钥

创建文件夹:mkdir /opt/tomcat/.ssh 用来存放 ssh 私钥 (我这里的 /opt/tomcat 路径是 tomcat 用户的主目录)。将私钥文件通过 scp 命令复制到服务器上。因为云服务器要通过私钥(ssh 协议)来访问 Github 的仓库。(Github 已经配置了和私钥对应的公钥。)
scp -i "/path/to/id_rsa" /path/to/id_rsa_corresponding_to_Github_publicKey user@server_IP:/path/to/store/id_rsa
复制到服务器后,将私钥复制到 /opt/tomcat/.ssh 目录下: cp /home/ubuntu/id_rsa /opt/tomcat/.ssh/
修改 .ssh/* 文件的权限,chown -R tomcat:tomcat /opt/tomcat/.ssh + chmod 700 /opt/tomcat/.ssh + chmod 700 /opt/tomcat/.ssh/id_rsa
编写 webhook 接口

编写 webhook 接口用什么语言都可以,C/C++ 、Java、Python、node.js 等都可以。
我这里使用 Python 来写,因为 Ubuntu 一样平常自带 Python3 且 Python 语法简单。python3 --version if python3 is not installed, execute command sudo apt install python3 to install it.
Examine that you have installed pip and venv.
  1. root@VM-0-17-ubuntu:/opt/webhooks/example# pip
  2. Command 'pip' not found, but can be installed with:
  3. apt install python3-pip
  4. root@VM-0-17-ubuntu:/opt/webhooks/example# dpkg -s python3-venv
  5. dpkg-query: package 'python3-venv' is not installed and no information is available
  6. Use dpkg --info (= dpkg-deb --info) to examine archive files.
复制代码
从上面的执行结果来看我的这台 Ubuntu 的云服务器上没有安装 Python 的包管理工具 pip 和 假造环境工具 venv。执行命令安装:sudo apt install python3-pip python3-venv 。
创建文件夹 mkdir -p /opt/webhooks/example 用来编写 webhook 接口。
cd /opt/webhooks/example,创建 Python 的假造环境,python3 -m venv myenv 。这将会在当前目录下创建一个名为 myenv 的文件夹,里面包含了 Python 解释器和假造环境所需的所有文件。创建假造环境后,激活假造环境,使用 pip 安装的所有第三方包都将会安装在 当前 /opt/webhooks/example/ 目录下,而不是安装在全局环境下。安装在全局环境下的话,会导致第三方包的版本紊乱,好比你的机子上有很多 Python 项目,每个项目都使用了指定版本的第三方包,假如都安装在全局环境就会导致紊乱,或者执行代码时报包的版本错误,所以创建假造环境用来隔离差别的项目的环境。
  1. root@VM-0-17-ubuntu:/opt/webhooks/example# python3 -m venv myenv
  2. root@VM-0-17-ubuntu:/opt/webhooks/example# ls
  3. myenv
复制代码
创建了假造环境后,需要激活当前环境,Linux 系统使用命令 source myenv/bin/activate :
  1. root@VM-0-17-ubuntu:/opt/webhooks/example# ls
  2. myenv
  3. root@VM-0-17-ubuntu:/opt/webhooks/example# source myenv/bin/activate
  4. (myenv) root@VM-0-17-ubuntu:/opt/webhooks/example#
复制代码
(Windows 上激活假造环境,在 Command Prompt(CMD) 下使用 myenvScriptsactivate.bat 激活。在 PowerShell 下激活,先设置 PowerShell 有执行脚本的权限:Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser,然后执行 myenvScriptsActivate.ps1 激活,关闭 PowerShell 执行脚本权限 Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope CurrentUser 。答应 PowerShell 执行脚本通常不安全,不发起使用 PowerShell 激活 Python 假造环境。无论 Windows 还是 Linux,取消假造环境的激活使用命令 deactivate 。)
激活了假造环境后,安装 Flask pip install Flask 。What’s Flask Read Below:
(Flask is a popular, lightweight web framework for Python, used for building web applications and APIs. It’s classified as a micro-framework because it provides the essential tools and features for building web apps, but it doesn’t come with some of the heavier components that larger frameworks like Django provide (e.g., built-in ORM, form handling, etc.).
Flask is designed to be simple, flexible, and easy to extend, which makes it a great choice for both beginners and advanced developers. It allows you to build anything from small, simple websites to large, complex applications.
Key Features of Flask
Minimalistic and Lightweight: Flask doesn’t force you to use any specific tools or libraries. It’s designed to be flexible and allows you to use only what you need for your project.
Routing: Flask provides an easy-to-use routing system, which means you can map URLs to specific Python functions (known as views). For example, you can easily set up routes for different pages of your web application.
Template Engine: Flask uses the Jinja2 template engine, which allows you to separate the HTML structure from the Python code. It lets you embed dynamic content into HTML templates with the power of Python code.
Development Server and Debugger: Flask includes a built-in development server with an interactive debugger that makes it easy to test and debug your application.
RESTful Support: Flask is widely used for building REST APIs, thanks to its simplicity and the ability to integrate with tools like Flask-RESTful, Flask-SQLAlchemy, etc.
Extensibility: You can extend Flask with a wide variety of third-party libraries or plugins to add more features, such as database integration, authentication, and form validation.
Flexibility: Unlike Django, Flask gives you full control over how you structure your application. You can choose your own database, authentication methods, and other components.
WSGI Compliance: Flask is WSGI-compliant, meaning it’s compatible with any WSGI-compliant server, like Gunicorn or uWSGI, for production environments.)
编写 webhook 接口的 python 代码
vim app.py:
  1. import os
  2. import shutil
  3. import subprocess
  4. from flask import Flask, request, jsonify
  5. app = Flask(__name__)
  6. @app.route('/webhook', methods=['POST'])
  7. def webhook():
  8.     # 验证 GitHub Webhook 是否发送的正确请求(可以添加 GitHub Secret 密钥验证)
  9.     if request.method == 'POST':
  10.         payload = request.json
  11.         print(f"Received payload: {payload}")
  12.         # 拉取最新代码
  13.         pull_code()
  14.         return jsonify({"message": "Webhook received and deployment triggered!"}), 200
  15. def pull_code():
  16.     """
  17.     拉取 GitHub 仓库的最新代码并部署到 Tomcat 的 webapps/blog 目录
  18.     """
  19.     repo_dir = '/opt/webhooks/example'
  20.     os.chdir(repo_dir)
  21.     blog_dir = os.path.join(repo_dir, 'blog')
  22.     # 如果 blog 目录不存在,则从 GitHub 克隆仓库
  23.     if not os.path.exists(blog_dir):
  24.         print(f"Cloning the repository into {blog_dir}...")
  25.         mkdir_result = subprocess.run(['mkdir', 'blog'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  26.         if mkdir_result.returncode != 0:
  27.             print(f"Error mkdir dir blog: {mkdir_result.stderr.decode()}")
  28.             return
  29.         result = subprocess.run(['git', 'clone', '--depth', '1', 'git@github.com:User-Name/Repository-Name.git', blog_dir], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  30.         if result.returncode != 0:
  31.             print(f"Error cloning repository: {result.stderr.decode()}")
  32.             return
  33.     else:
  34.         # 如果 blog 目录已经存在,拉取最新代码
  35.         print("Pulling the latest code from GitHub...")
  36.         result = subprocess.run(['git', '-C', blog_dir, 'pull', 'origin', 'main'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  37.         if result.returncode != 0:
  38.             print(f"Error pulling code: {result.stderr.decode()}")
  39.             return
  40.     # 复制代码到 Tomcat webapps/example 目录
  41.     tomcat_blog_dir = '/opt/tomcat/webapps/example'  # Tomcat 下的 blog 目录
  42.     if os.path.exists(tomcat_blog_dir):
  43.         shutil.rmtree(tomcat_blog_dir)  # 清除旧的 blog 目录
  44.     shutil.copytree(blog_dir, tomcat_blog_dir)  # 复制新代码
  45.     print("Code deployed to Tomcat webapps/blog")
  46. if __name__ == '__main__':
  47.     app.run(host='127.0.0.1', port=12345, debug=False)  # 启动 Flask 应用
复制代码
代码中,步调监听了本机 127.0.0.1 的 12345 端口,一旦接收了 Github webhook 发出的 HTTP HOST,就使用子历程 subprocess 执行从仓库拉代替码以及资源文件的操纵,将仓库中所有的子文件保存到 /opt/webhooks/example/blog 下面,然后清除 /opt/tomcat/webapps/example 里面旧的代码和资源,将新的代码以及资源复制进去。(根据需求自行修改代码。)
由于我的服务器中运行了 apache2,它监听了 443 端口,并反向代理到 tomcat,所以也要将 webhook 反向代理到本机的 12345 端口。
编辑 apache2 的配置文件,我这里的是 /etc/apache2/sites-available/my_conf.conf
  1.         # 反向代理配置
  2.         ProxyPreserveHost On
  3.         # 反向代理到 webhook 的接口
  4.         ProxyPass /webhook http://127.0.0.1:12345/webhook
  5.         ProxyPassReverse /webhook http://127.0.0.1:12345/webhook
  6.         # 反向代理到 Tomcat
  7.         ProxyPass / http://127.0.0.1:8080/
  8.         ProxyPassReverse / http://127.0.0.1:8080/
复制代码
留意 webhook 接口的反向代理要放在 tomcat 的反向代理前面,因为反向代理的序次是配置文件中的从上往下,假如 tomcat 的反向代理放在前面,那么路径为 /webhook 的 HTTPS 哀求将会被反向代理到 tomcat,而 tomcat 中我并没有写 webhook 的接口。
编辑完成 apache2 的配置文件后,systemctl restart apache2 重启 apache2 。
先以 root 身份运行 app.py,测试反向代理是否配置乐成:
  1. (myenv) root@VM-0-17-ubuntu:/opt/webhooks/example# ls
  2. app.py  myenv
  3. (myenv) root@VM-0-17-ubuntu:/opt/webhooks/example# python3 app.py
  4. * Serving Flask app 'app'
  5. * Debug mode: off
  6. WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
  7. * Running on http://127.0.0.1:12345
  8. Press CTRL+C to quit
复制代码
然后在本地使用 curl 命令验证:
  1. $ curl -X POST https://example.jackey-song.com/webhook -H "Content-Type: application/json" -d '{"event": "user_signup", "data": {"username": "john_doe", "email": "john@example.com"}}'
  2. {"message":"Webhook received and deployment triggered!"}
复制代码
curl :


  • -X 指定方法 POST
  • -H 设置哀求头,指定发送的数据是 JSON 格式。
  • -d 哀求体中的 JSON 数据。确保数据格式正确。
curl 指令执行后,可以看到服务器端输出说明反向代理配置乐成:
  1. (myenv) root@VM-0-17-ubuntu:/opt/webhooks/example# python3 app.py
  2. * Serving Flask app 'app'
  3. * Debug mode: off
  4. WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
  5. * Running on http://127.0.0.1:12345
  6. Press CTRL+C to quit
  7. Received payload: {'event': 'user_signup', 'data': {'username': 'john_doe', 'email': 'john@example.com'}}
  8. Cloning the repository into /opt/webhooks/example/blog...
  9. The authenticity of host 'github.com (xxx.xxx.xxx.xxx)' can't be established.
  10. ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU.
  11. This key is not known by any other names.
  12. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
  13. Error cloning repository: Cloning into '/opt/webhooks/example/blog'...
  14. Warning: Permanently added 'github.com' (ED25519) to the list of known hosts.
  15. git@github.com: Permission denied (publickey).
  16. fatal: Could not read from remote repository.
  17. Please make sure you have the correct access rights
  18. and the repository exists.
  19. 127.0.0.1 - - [29/Nov/2024 17:19:00] "POST /webhook HTTP/1.1" 200 -
复制代码
从输出的结果来看,从 github 上克隆仓库内容并没有乐成,因为 root 用户没有权限,之前配置的 id_rsa 私钥文件是放在 tomcat 用户的主目录下的 /opt/tomcat/.ssh/id_rsa。后文会以 tomcat 的权限来运行 app.py。下面配置 Github 仓库那边的 webhook 。
Github 仓库配置 webhook

Github —> 对应的 repository —> settings —> Webhooks —> add webhook :

Payload URL:https://你的服务器域名/webhook
启用 SSL 验证,push 事件触发 webhook。

以服务的情势运行 app.py

创建一个 flask-app.service 文件用来保存配置,vim /etc/systemd/system/flask-app.service :
  1. [Unit]
  2. Description=Flask Webhook API
  3. After=network.target
  4. [Service]
  5. # 使用 tomcat 用户来运行
  6. User=tomcat
  7. # Flask 应用所在的目录
  8. WorkingDirectory=/opt/webhooks/example
  9. # 执行 Flask 应用的命令
  10. ExecStart=/opt/webhooks/example/myenv/bin/python3 /opt/webhooks/example/app.py
  11. # 虚拟环境的路径以及 git 的路径
  12. Environment="PATH=/opt/webhooks/example/myenv/bin:/usr/bin"
  13. Environment="FLASK_APP=app.py"
  14. Restart=always
  15. RestartSec=3
  16. [Install]
  17. WantedBy=multi-user.target
复制代码
保存并退出 vim :wq 。
将 /opt/webhooks/example/ 中所有文件的权限修改为 tomcat:-R 递归修改 sudo chown -R tomcat:tomcat /opt/webhooks/example + sudo chmod -R 700 /opt/webhooks/example
  1. (myenv) root@VM-0-17-ubuntu:/opt/webhooks# chown -R tomcat:tomcat /opt/webhooks/example
  2. (myenv) root@VM-0-17-ubuntu:/opt/webhooks# chmod -R 700 /opt/webhooks/example
  3. (myenv) root@VM-0-17-ubuntu:/opt/webhooks# ls -l
  4. total 4
  5. drwx------ 5 tomcat tomcat 4096 Nov 29 17:41 example
  6. (myenv) root@VM-0-17-ubuntu:/opt/webhooks# ls -l example
  7. total 16
  8. -rwx------ 1 tomcat tomcat 2289 Nov 29 16:51 app.py
  9. drwx------ 2 tomcat tomcat 4096 Nov 29 17:19 blog
  10. drwx------ 5 tomcat tomcat 4096 Nov 29 16:03 myenv
  11. drwx------ 2 tomcat tomcat 4096 Nov 29 17:41 __pycache__
复制代码
sudo systemctl daemon-reload 重新加载服务的配置文件。
sudo systemctl start flask-app 启动 flask-app 服务。
sudo systemctl enable flask-app 开机主动启动 flask-app。
  1. (myenv) root@VM-0-17-ubuntu:/opt/webhooks# systemctl daemon-reload
  2. (myenv) root@VM-0-17-ubuntu:/opt/webhooks# systemctl start flask-app
  3. (myenv) root@VM-0-17-ubuntu:/opt/webhooks# systemctl status flask-app
  4. ● flask-app.service - Flask Webhook API
  5.      Loaded: loaded (/etc/systemd/system/flask-app.service; disabled; preset: enabled)
  6.      Active: activating (auto-restart) (Result: exit-code) since Fri 2024-11-29 17:57:21 CST; 2s ago
  7.     Process: 1523039 ExecStart=/opt/webhooks/example/myenv/bin/python3 /opt/webhooks/example/app.py # 执行 Fla>
  8.    Main PID: 1523039 (code=exited, status=217/USER)
  9.         CPU: 1ms
  10. (myenv) root@VM-0-17-ubuntu:/opt/webhooks# systemctl enable flask-app
  11. Created symlink /etc/systemd/system/multi-user.target.wants/flask-app.service → /etc/systemd/system/flask-app.service.
  12. (myenv) root@VM-0-17-ubuntu:/opt/webhooks# systemctl status flask-app
  13. ● flask-app.service - Flask Webhook API
  14.      Loaded: loaded (/etc/systemd/system/flask-app.service; enabled; preset: enabled)
  15.      Active: activating (auto-restart) (Result: exit-code) since Fri 2024-11-29 17:57:37 CST; 2s ago
  16.     Process: 1523189 ExecStart=/opt/webhooks/example/myenv/bin/python3 /opt/webhooks/example/app.py # 执行 Fla>
  17.    Main PID: 1523189 (code=exited, status=217/USER)
  18.         CPU: 1ms
复制代码
有一点需要留意,修改 app.py 后,假如不重新启动 flask-app 服务,修改后的 app.py 代码不会被执行。
确保 /opt/tomcat/webapps/example 的权限为 tomcat 。(因为这个 example 我之前创建的时候以 root 权限进行创建的,所以这里要修改它的权限为 tomcat 。真不愧是 Linux 系统,安全系数这么高,各种权限的限制,难怪很多服务器都跑 Linux ,安全稳固。)
在执行 push 之前,先使用 root 权限 git clone 一次你的仓库(先 cp /opt/tomcat/.ssh/id_rsa /root/.ssh 再 git clone ...),确保能够拉代替码。然后将 /root/.ssh/known_hosts 文件复制到 /opt/tomcat/.ssh/ 下,并修改权限,让 tomcat 可以读写执行。(说了半天,假如你嫌麻烦,那么就直接以 root 权限运行 app.py 就直接省去了各种权限题目)。
本地网站的静态资源项目里,创建一个 a.txt 文件,然后使用 命令 git add . + git commit -m "test webhook" + git push 到 github 仓库。

可以看到 webhook 乐成了!!!查抄服务器上的文件,也乐成从 github 上 clone 或者 pull 拉代替码并摆设到 tomcat 下了!!!



flask-app.service 文件也有其他的配置方法:
  1. [Unit]
  2. Description=Flask Application
  3. After=network.target
  4. [Service]
  5. User=root
  6. WorkingDirectory=/opt/webhooks/example
  7. ExecStart=/opt/webhooks/example/myenv/bin/gunicorn -w 1 -b 127.0.0.1:12345 app:app
  8. Restart=always
  9. [Install]
  10. WantedBy=multi-user.target
复制代码
使用 gunicorn 来运行 app.py。需要在假造的 python 环境中安装 pip install gunicorn 。
Gunicorn 是一个 Python WSGI UNIX HTTP 服务器,用于 UNIX 系统上运行 Python web 应用。它通常用作生产环境中的 Flask、Django 等应用的服务器。



OK 简单总结一下,github 配置公钥文件,将私钥文件复制到服务器的 /opt/tomcat/.ssh/ 下,并修改权限,留意 id_rsa 文件 tomcat 要有读写和执行的权限(chomd 700),否则是无法使用该密钥建立 ssh 连接到 github 服务器的。然后使用 python 的 Flask 库 编写 webhook 接口,apache2 反向代理到 webhook 接口,github 仓库配置 webhook,push 测试一下,乐成!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

铁佛

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表