使用自定义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脚本启动部署过程来自动化部署。
先决条件
在开始之前,请确保您的服务器上已安装以下内容:
- Node.js(版本16或更新):您可以使用vim下载或直接从包管理器安装
- PM2:为了有效管理Node.js应用程序,可以全局安装PM2:
- Git:需要用于拉取最新代码。通过以下方式安装:
1
|
sudo dnf install git -y
|
- NGINX或Apache(可选):如果您想通过域公开CI/CD服务器
- 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."
|
使其可执行:
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流水线。这个解决方案轻量级、成本效益高,并且可以轻松扩展以适应多个项目。