使用自定义CI/CD服务器自动化Node.js部署

本文详细介绍了如何构建自定义CI/CD服务器来自动化Node.js应用部署,包括GitHub Webhooks监听、PM2进程管理和shell脚本编写,实现代码自动更新和依赖管理。

使用自定义CI/CD服务器自动化Node.js部署

随着项目规模的增长,Node.js应用程序的管理和部署可能成为瓶颈。设计良好的持续集成和持续部署(CI/CD)流水线可以帮助减轻频繁更新的负担,简化依赖管理,并消除手动重启过程的需要,从而避免这些瓶颈。

在本教程中,我们将创建一个自定义CI/CD服务器,监听GitHub webhook事件,并使用GitHub Actions、PM2和shell脚本执行部署。这使我们能够:

  • 在更新时从GitHub仓库获取最新更改
  • 识别依赖项的变化,仅在发生变化时安装npm
  • 在有更新时使用PM2停止和重启应用程序
  • 从单个CI/CD服务器方便地管理不同项目

完成本教程后,您将拥有一个功能齐全的自托管部署流水线,可用于AlmaLinux(或任何Linux服务器)上的不同项目。这种方法特别适合那些希望对部署过程有更多控制的开发人员,而不是使用GitHub Actions或类似的第三方CI/CD服务。

构建目标

我们的目标是开发一个轻量级的Node.js CI/CD服务器,该服务器:

  • 监听基于提交推送到特定分支的GitHub webhook事件
  • 验证有效负载以确认请求来自GitHub
  • 执行shell脚本(deploy.sh),该脚本:
    • 切换到正确的项目目录
    • 拉取仓库
    • 检查并安装任何缺失的依赖项
    • 使用PM2重启项目
  • 将部署状态发送到GitHub进行日志记录

本教程将介绍Node.js、GitHub Actions和Linux shell脚本的基础知识。如果您是PM2或GitHub webhooks的新手,不用担心,我们将详细解释每个部分。

设置CI/CD服务器

让我们配置一个基于Node.js的CI/CD服务器,通过监控GitHub webhooks并使用PM2和shell脚本启动部署过程来自动化部署。

先决条件

在开始之前,请确保您的服务器上已安装以下内容:

  1. Node.js(版本16或更新):您可以使用vim下载或直接从包管理器安装
  2. PM2:为了有效管理Node.js应用程序,可以全局安装PM2:
    1
    
    npm install -g pm2
    
  3. Git:需要用于拉取最新代码。通过以下方式安装:
    1
    
    sudo dnf install git -y
    
  4. NGINX或Apache(可选):如果您想通过域公开CI/CD服务器
  5. GitHub设置:确保您的项目托管在GitHub上,并且您有配置webhooks的必要权限

创建CI/CD服务器

步骤1:初始化Node.js项目

首先,为CI/CD服务器创建一个新目录并初始化Node.js项目:

1
2
mkdir ~/cicd-server && cd ~/cicd-server 
npm init -y

安装所需的依赖项:

1
npm install express body-parser crypto

步骤2:构建webhook监听器

创建名为index.js的文件并填入以下代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const express = require("express");
const bodyParser = require("body-parser");
const crypto = require("crypto");
const { exec } = require("child_process");

const app = express();
const PORT = 4000;
const GITHUB_SECRET = process.env.GITHUB_SECRET || "your-secret-key";

app.use(bodyParser.json());

app.post("/webhook", (req, res) => {
  const signature = `sha256=${crypto
    .createHmac("sha256", GITHUB_SECRET)
    .update(JSON.stringify(req.body))
    .digest("hex")}`;

  if (req.headers["x-hub-signature-256"] !== signature) {
    return res.status(401).json({ message: "Invalid signature" });
  }

  const repoName = req.body.repository.name;
  console.log(`Received update for: ${repoName}`);

  exec(`bash ./deploy.sh ${repoName}`, (error, stdout, stderr) => {
    if (error) {
      console.error(`Deployment failed: ${stderr}`);
      return res.status(500).json({ message: "Deployment failed", error: stderr });
    }
    console.log(`Deployment successful: ${stdout}`);
    res.json({ message: "Deployment successful", output: stdout });
  });
});

app.listen(PORT, () => console.log(`CI/CD server running on port ${PORT}`));

步骤3:编写部署脚本

在同一目录中创建deploy.sh文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
REPO_NAME=$1

BASE_DIR="/var/www/projects"
PROJECT_DIR="$BASE_DIR/$REPO_NAME"

echo "Starting deployment for $REPO_NAME..."

if [ ! -d "$PROJECT_DIR" ]; then
  echo "Error: Directory $PROJECT_DIR does not exist."
  exit 1
fi

cd "$PROJECT_DIR"

echo "Pulling latest changes..."
git pull origin main

CHANGES=$(git diff --name-only HEAD@{1} HEAD)

if [[ $CHANGES == *"package.json"* ]]; then
  echo "Detected dependency changes. Running npm install..."
  npm install
fi

echo "Restarting application..."
pm2 restart $REPO_NAME

echo "Deployment completed."

使其可执行:

1
chmod +x deploy.sh

3. 配置GitHub webhooks

转到GitHub → 您的仓库 → 设置 → Webhooks 点击"Add webhook" 设置Payload URL为:http://server-ip:4000/webhook(如果使用NGINX或Apache,请替换为您的域名,例如example.com) 设置Content type为"application/json" 添加一个密钥,其值与index.js文件中使用的GITHUB_SECRET相同 选择push事件并点击"Add webhook"

4. 运行CI/CD服务器

使用PM2启动CI/CD服务器:

1
2
pm2 start index.js --name cicd-server 
pm2 save

5. 添加NGINX或Apache反向代理

如果您想通过域公开CI/CD服务器,请设置NGINX或Apache反向代理。

NGINX配置

创建NGINX配置文件:

1
sudo nano /etc/nginx/conf.d/cicd.conf

内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://localhost:4000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

重新加载NGINX:

1
2
sudo nginx -t 
sudo systemctl reload nginx

Apache配置

创建虚拟主机配置:

1
sudo nano /etc/httpd/conf.d/cicd.conf

内容:

1
2
3
4
5
6
7
<VirtualHost *:80>
    ServerName example.com
    ProxyPass / http://localhost:4000/
    ProxyPassReverse / http://localhost:4000/
    ErrorLog /var/log/httpd/cicd-error.log
    CustomLog /var/log/httpd/cicd-access.log combined
</VirtualHost>

重启Apache:

1
sudo systemctl restart httpd

6. 测试部署

推送更新到您的仓库并检查:

  • webhook是否触发CI/CD服务器
  • 脚本是否拉取更改并在需要时安装依赖项
  • PM2是否重启应用程序

总结

我们已成功使用GitHub Actions、PM2和shell脚本为Node.js部署创建了一个自托管的CI/CD流水线。这个解决方案轻量级、成本效益高,并且可以轻松扩展以适应多个项目。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计