从零实现一个轻量级 CI/CD:Git Hooks 自动部署 Node.js 应用(含 Nginx + systemd 生产级配置)
作者:粟本偲
项目地址:https://gitcode.com/SUBENCAI/myapp-cicd-demo
适用场景:CentOS 7 / Node.js / 运维开发学习 /
本文记录了我如何仅用 Shell 脚本 + Git Hooks 实现一套轻量级 CI/CD 系统,并完成 Node.js 应用的 生产级部署(Nginx 反向代理 + systemd 托管)。全程无需 Jenkins/GitLab CI,适合学习原理与面试展示。
一、为什么不用 Jenkins?—— 我们要理解 CI/CD 的本质
- CI/CD 的核心是:代码变更 → 自动构建 → 自动部署
- 大多数人只会点图形界面,但不知道背后是 Shell 脚本在执行
- 本文通过
post-receive钩子,亲手实现这一流程
二、环境准备
- 操作系统:CentOS 7(阿里云 ECS)
- 已安装软件:Git、Nginx、Node.js(通过 EPEL + 阿里源)
- 用户权限:root 或 sudo 权限
node -v # ≥ v14
nginx -v
git --version
三、创建裸仓库(Bare Repository)
- 在服务器创建
/var/git/myapp.git - 初始化为 bare 仓库:
git init --bare - 设置目录权限,确保部署用户可写
在服务器上创建接收推送的裸仓库:
mkdir -p /var/repo/myapp.git
cd /var/repo/myapp.git
git init --bare
[root@python myapp]# mkdir -p /var/repo/myapp.git
[root@python myapp]# cd /var/repo/myapp.git
[root@python myapp.git]# git init --bare
初始化空的 Git 版本库于 /var/repo/myapp.git/
四、编写 post-receive 钩子脚本
- 路径:
/var/git/myapp.git/hooks/post-receive - 功能:
- 拉取最新代码到
/var/www/myapp/releases/v{timestamp} - 创建软链接
/var/www/myapp/current指向最新版本 - 自动清理超过 3 个历史版本
- 重启 systemd 服务
- 拉取最新代码到
- 关键技巧:使用
flock避免并发冲突
#!/bin/bash
GIT_WORK_TREE=/root/myapp git --git-dir=/var/repo/myapp.git checkout -f
systemctl restart myapp
echo "$(date): Deployed" >> /var/log/myapp-deploy.log
五、Node.js 应用示例(app.js)
- 简单 HTTP 服务,返回 “Hello from CI/CD!”
- 包含
package.json(定义 start 脚本) - 日志输出到 stdout(便于 systemd 收集)
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from CI/CD!\n');
});
server.listen(3000, '0.0.0.0', () => {
console.log('Server running at http://0.0.0.0:3000/');
});
六、配置 systemd 托管服务
- 创建
/etc/systemd/system/myapp.service - 设置 User、WorkingDirectory、ExecStart
- 启用开机自启:
systemctl enable myapp - 查看日志:
journalctl -u myapp -f
/etc/systemd/system/myapp.service
[Unit]
Description=MyApp Node.js Service
After=network.target
[Service]
ExecStart=/usr/bin/node /root/myapp/app.js
WorkingDirectory=/root/myapp
Restart=always
User=root
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target
启用服务:
systemctl daemon-reload
systemctl start myapp
systemctl enable myapp
七、Nginx 反向代理配置
- 配置文件:
/etc/nginx/conf.d/myapp.conf - 将 80 端口请求代理到
http://127.0.0.1:3000 - 添加健康检查路径
/healthz - 重载 Nginx:
nginx -s reload
/etc/nginx/conf.d/myapp.conf
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
八、本地开发与推送测试
- 本地添加远程仓库:
git remote add prod root@server:/var/git/myapp.git - 推送触发部署:
git push prod main - 验证:curl http://192.168.126.50
# 初始化本地仓库
git init
git add .
git commit -m "First deploy"
# 添加远程仓库
git remote add prod root@192.168.126.50:/var/repo/myapp.git
# 推送触发自动部署
git push prod master
九、效果展示与性能对比
- 部署耗时:<5 秒
- 回滚操作:手动切换软链接即可
- 对比 Jenkins:资源占用更低,逻辑透明可控
十、总结与延伸思考
优势
轻量:仅依赖系统自带工具
可控:无隐藏逻辑,适合调试
教学友好:清晰展示 CI/CD 本质
不足
无 Web UI
无并行流水线
无权限管理
下一步优化方向
增加版本回滚(软链接切换)
集成健康检查(/healthz)
添加邮件/企业微信告警
使用非 root 用户部署(安全加固)
💡 项目已开源,欢迎 Star:https://gitcode.com/SUBENCAI/myapp-cicd-demo
技术栈:Shell / Git / Node.js / Nginx / systemd / CentOS

143

被折叠的 条评论
为什么被折叠?



