无需第三方应用程序即可从 Github 自动部署到您的服务器

2025-06-07

无需第三方应用程序即可从 Github 自动部署到您的服务器

说到设置部署管道,我相信市面上有无数的解决方案。如果我们使用 AWS,我们可以使用 Code Deploy,Heroku、Zeit Now 和 Netlify 也提供了各自的解决方案,当然,其中一种流行的方法是将任务委托给 CI/CD 服务器(Travis、Circle CI 等)来处理。如果您使用的是 Docker 容器,那么最好的编排工具是 AWS ECS、Swarm 和 Kubernetes。如果您与一个更大的团队合作,您很可能会有 Dev-Ops 团队成员来处理,您可能会认为您的基础设施是理所当然的!😐 但是,如果像我一样,您加入了一家初创公司,并且部署过程是手动的(SSH 到服务器、git pull 等),并且您编写了一些 bash 脚本来为他们​​完成这些操作,那么您可能需要拥抱内心的书呆子精神🤓,并升级您的部署游戏。在这种情况下,在 GitHub 上合并 Pull 请求时自动运行您的 bash 脚本会让每个人都很高兴,而且这不是什么高深的科学,所以让我们开始吧!

目标

将拉取请求合并到分支 dev 和 master 后自动部署代码。

我们使用的东西

  • 节点 JS
  • Bash 脚本
  • Github Webhooks
  • SSH 命令行

入门

假设我们需要自动部署两个版本的网站。其中一个版本名为“prod” stage,代表最新的合并提交。这些更改通常存在错误且不可靠,因此我们希望只有内部团队才能访问。“stage”代表我们dev在 Github 上的分支。网站的第二个版本名为“prod”,代表masterGithub 上的分支。这个分支(希望)比较稳定,并且已经通过了 QA 团队的测试,被认为对最终用户来说是安全的。这个版本就是公司外部所有人所知的网站 URL。

步骤 1:克隆你的 Git 存储库

如果您尚未在服务器中克隆 github 存储库,则必须执行此操作。

创建两个目录,分别名为:prodstage

mkdir live stage
git clone git@github.com:p0o/your_repo.git
cp -a your_repo/. ./prod/your_repo
cp -a your_repo/. ./stage/your_repo
rm -rf ./your_repo
Enter fullscreen mode Exit fullscreen mode

确保.在 your_repo 后添加 extra,这是一种特殊cp语法,允许复制文件夹内的隐藏文件和文件夹(我们也需要它来复制 .git 文件夹)。

大胆假设:我假设您熟悉管理服务器的基础知识,并且可以使用合适的 SSL 证书在所需的 URL 中运行您的网站。我使用 Nginx 来实现此目的,但我不会在文章中解释这些步骤。如果您不确定,可以自行搜索。

第 2 步:编写 bash 脚本

我们需要两个 Bash 脚本来处理每种情况的部署。如果您需要构建文件,那么让我们在服务器的主目录中创建一个目录,并从那里开始。我将此目录命名为scripts

cd ~/
mkdir scripts
cd scripts
Enter fullscreen mode Exit fullscreen mode

好的,让我们继续制作 bash 文件:

touch ./deploy_stage
touch ./deploy_prod
Enter fullscreen mode Exit fullscreen mode

授予他们执行权限:

chmod +x ./deploy_stage
chmod +x ./deploy_prod
Enter fullscreen mode Exit fullscreen mode

(感谢darksmile92指出这一点)

我将为其中一个放置示例代码,另一个只是一个不同的文件夹,并且根据您的项目依赖关系可能具有不同的环境变量。

#!/bin/bash
echo "Deploying stage your_repo"

cd ~/stage/your_repo \
&& git checkout dev \
&& git pull \
&& npm i \
&& npm run build \
&& (pm2 stop your_repo_stage || true) \
&& echo 'Installing:  done.' \
&& (pm2 delete your_repo_stage || true) \
&& NODE_ENV=development pm2 --name your_repo_stage start npm -- start \
&& echo "your_repo deployed successfully"
Enter fullscreen mode Exit fullscreen mode

这个 bash 脚本基本上会从 GitHub 获取最新代码,安装依赖项,构建脚本(如果需要)并使用PM2运行它。如果您不熟悉,PM2 是一个非常有用的进程管理工具,您可以使用 NPM 轻松安装它。

另外值得一提的是,我用逻辑 AND (&&) 链接了整个过程,因为如果其中一个过程失败,我想退出执行。

步骤 3:编写代码来处理 webhook 事件

为了在 Github 发生任何事件时都能收到通知,我们必须订阅他们的 Webhook API,这实际上意味着需要向 Github 提供一些 URL,以便他们向 Github 发送一些信息。这些 URL 必须是公开的,并且 Github 可以运行脚本来部署你的代码,因此,如果 Github 服务器以外的任何人可以访问这些 URL,将会带来严重的安全隐患(例如,拒绝服务攻击)。

Github 使用 SH1 HMAC 签名来验证发送给您的 JSON 对象。我们会将此签名哈希值保存在X-Hub-Signatureheader 的值中。由于处理这些操作比较复杂,我们可以使用github-webhook-handler 包,该包就是为此目的而创建的。

我们还需要从 Node 运行我们的 Bash 脚本文件。我们可以使用原生函数来实现,但为了简单起见,我更喜欢使用ShellJs 。

好了,废话不多说,下面是您需要的代码:

const http = require('http');
const createHandler = require('github-webhook-handler');
const shell = require('shelljs');

// We avoid to hardcode the secret in the code, you should provide it with an ENV variable before running this script
const { MY_SECRET } = process.env;
// You might use the same script for multiple repositories, this is only one of them
const REPO_NAME = 'my_repo';
// port is default on 6767
const PORT = process.env.PORT || 6767;

var handler = createHandler({ path: '/', secret: MY_SECRET })

http.createServer(function (req, res) {
  handler(req, res, function (err) {
    res.statusCode = 404
    res.end('no such location')
  })
}).listen(PORT);

handler.on('error', function (err) {
  console.error('Error:', err.message)
})

handler.on('pull_request', function (event) {
  const repository = event.payload.repository.name;
  const action = event.payload.action;

  console.log('Received a Pull Request for %s to %s', repository, action);
  // the action of closed on pull_request event means either it is merged or declined
  if (repository === REPO_NAME && action === 'closed') {
    // we should deploy now
    shell.cd('..');
    shell.exec('~/scripts/deploy_stage');
  }
});

Enter fullscreen mode Exit fullscreen mode

将其保存在服务器的某个文件夹中并安装依赖项:

npm init
npm i github-webhook-handler shelljs --save
Enter fullscreen mode Exit fullscreen mode

然后使用 PM2 永远使用环境变量运行它:

MY_SECRET=MyGithubWebhookSecret pm2 --name github-deployer start node -- ./index.js
Enter fullscreen mode Exit fullscreen mode

就这样!

步骤4:配置github webhook

现在我们只需要访问 Github 并将我们的 webhook 引入到 GitHub 即可。但请注意,上一步中我们在 6767 端口上运行了 webhook,并且没有启用 HTTPS。因此,您需要设置 nginx 并为其指定一个启用 HTTPS 的域名。您可以直接将其放在主域名的路径下,但本文不打算详细解释这个过程。幸运的是,网络上有很多文章可供您查找。

前往你的代码库的“设置”选项卡,点击“Webhook”。在页面右侧,点击“添加 Webhook”按钮。

在 Github 中添加 Webhook 页面

输入你在 Nginx 中为运行的 Node.js 应用引入的 URL。假设它是https://yourdomain.com/webhook

选择application/json内容类型 (content-type),并输入我们运行服务时使用的密钥。在我的示例中,它是“MyGithubWebhookSecret”。

在 Github 中添加 Webhook 页面

在“您希望哪些事件触发此 webhook?”部分中,单击“让我选择单个事件”,找到 Pull 请求并检查:

Github Webhook 配置中的 Pull Request 事件

确保其他所有选项都未勾选,然后点击“添加 Webhook”保存。现在一切就绪🦸

步骤 5:测试并验证

使用 PM2 监控我们刚刚创建的 Node.js 应用的日志。输入:

pm2 log github_deployer
Enter fullscreen mode Exit fullscreen mode

现在您可以查看是否有任何更改!前往您的代码库,在新分支中进行一些更改。提交拉取请求并合并。您应该在日志中看到您的 Bash 脚本将执行部署,之后您的更改应该会反映到网站上。如果您遇到任何错误,您可以在日志中看到它,然后……采取一些措施 😂

结论

虽然我认为本文提出的解决方案相当简单,但它并非解决此特定问题的最佳方案。就连我的个人博客也使用 Zeit Now Github Integration 进行部署!然而,其他解决方案依赖于第三方应用程序,有时某些团队根据其资源限制无法访问。就我而言,部署脚本已经存在,代码库没有使用 Docker,而且我处理这个问题的时间非常有限。如果你也遇到同样的情况,不妨继续学习!

本文最初发布在我的博客上,标题为《从 Github 自动部署到你的服务器》,欢迎查看更多文章!👀
你也可以在 Twitter 上找到我 => @p0oker

文章来源:https://dev.to/opshack/automatic-deployment-from-github-to-your-server-with-no-third-party-app-3f5j
PREV
⚡️Reactend“后端 React.js 的故事”
NEXT
开源 100 天的意外力量