在 CentOS 上落地 Node.js 项目的持续集成
一、方案总览与选型
- 自建 CI 服务器:使用 Jenkins 在 CentOS 上运行构建与部署任务,适合需要复杂流程、多环境、细粒度权限与审计的团队。
- 代码托管内置 CI:使用 GitLab CI/CD,在服务器安装 GitLab Runner,通过 .gitlab-ci.yml 编排流水线,轻量、与仓库深度集成。
- 极简自动化:使用 Git Hooks + systemd + Nginx,无需额外 CI 平台,适合单机或演示环境,理解 CI/CD 本质的低成本方案。
二、方案一 Jenkins 在 CentOS 上的落地步骤
- 准备环境
- 安装 Java 11+(Jenkins 运行依赖),安装 Jenkins(CentOS 7/8 可用官方 YUM 源),启动并设置开机自启。
- 安装 Node.js/npm:优先使用 NVM 为 jenkins 用户安装所需版本(如 v16.20.2),或二进制解压到 /opt/nodejs 并软链到 /usr/local/bin。
- 让 Jenkins 找到 Node.js
- 方式 A:修改 systemd 服务,在 /usr/lib/systemd/system/jenkins.service 的 [Service] 段加入
- Environment=“NVM_DIR=/var/lib/jenkins/.nvm”
- Environment=“PATH=/var/lib/jenkins/.nvm/versions/node/v16.20.2/bin:${env.PATH}”
- 执行:systemctl daemon-reload && systemctl restart jenkins
- 方式 B:在 Pipeline 中显式设置 PATH
- environment { PATH = “/var/lib/jenkins/.nvm/versions/node/v16.20.2/bin:${env.PATH}” }
- 安装插件与全局工具
- 插件:NodeJS(管理 Node 版本)、Publish Over SSH(部署到目标机)。
- 全局工具配置:新增 NodeJS 安装(选择 LTS 版本),供 Job 使用。
- 创建 Job 与流水线示例
- Freestyle:源码管理选 Git;构建环境勾选 Provide Node & npm bin/ folder to PATH;构建步骤执行
- npm ci
- npm test – --ci
- npm run build(如有)
- Pipeline(Declarative):
- pipeline {
agent any
environment {
PATH = “/var/lib/jenkins/.nvm/versions/node/v16.20.2/bin:${env.PATH}”
NODE_ENV = ‘test’
}
stages {
stage(‘Install’) { steps { sh ‘npm ci’ } }
stage(‘Test’) { steps { sh ‘npm test – --ci’ } }
stage(‘Build’) { steps { sh ‘npm run build --if-present’ } }
stage(‘Deploy’) { steps { sh ‘rsync -avz dist/ user@target:/var/www/myapp/’ } }
}
}
- 常见问题速解
- “npm: command not found”:确认 jenkins 用户能访问 Node/npm(NVM 初始化、PATH 正确、软链或 systemd 环境变量生效)。
- 版本不匹配:在 NVM 为 jenkins 用户安装项目所需 Node 版本,并设为 default。
三、方案二 GitLab CI/CD 在 CentOS 上的落地步骤
- 准备环境
- 安装 Git、Node.js(可用 nvm 或二进制包)、GitLab Runner(注册到项目,选择合适的 Executor:shell/docker)。
- 注册 Runner 与标签
- 在项目 Settings → CI/CD → Runners 获取 URL/Token,执行 gitlab-runner register,填写 tags(如:deploy),后续 .gitlab-ci.yml 用 tags 匹配 Runner。
- 编写 .gitlab-ci.yml 示例
- stages:
- cache:
- install:
- stage: install
- tags: [deploy]
- script:
- build:
- stage: build
- tags: [deploy]
- script:
- npm run build --if-present
- artifacts:
- deploy:
- stage: deploy
- tags: [deploy]
- script:
- rsync -avz --delete ${CI_PROJECT_DIR}/dist/ user@target:/var/www/myapp/
- 运行与排错
- 推送代码自动触发;在 CI/CD → Pipelines 查看日志。
- “command not found”:若用 shell 执行器,确保 gitlab-runner 用户环境包含 node/npm;若用 docker,在 job 中指定 image: node:16.17.0 等镜像。
四、方案三 Git Hooks 极简自动化
- 在服务器创建裸仓库
- mkdir -p /var/repo/myapp.git && cd $_
- git init --bare
- 配置 post-receive 钩子
- 路径:/var/repo/myapp.git/hooks/post-receive
- 示例(使用 flock 防并发,部署到 /var/www/myapp/current,重启服务):
- #!/usr/bin/env bash
set -e
WORK_TREE=/var/www/myapp/releases/$(date +%Y%m%d%H%M%S)
mkdir -p “$WORK_TREE”
flock -n /tmp/myapp.lock bash -c "
git --git-dir=/var/repo/myapp.git --work-tree="$WORK_TREE" checkout -f
ln -sfn "$WORK_TREE" /var/www/myapp/current
chown -R appuser:appuser /var/www/myapp/releases
systemctl restart myapp
"
echo "$(date): Deployed $WORK_TREE" >> /var/log/myapp-deploy.log
- 生产托管与反向代理
- systemd 服务(/etc/systemd/system/myapp.service):
- [Unit] Description=MyApp Node.js Service; After=network.target
- [Service] ExecStart=/usr/bin/node /var/www/myapp/current/app.js
WorkingDirectory=/var/www/myapp/current
Restart=always
User=appuser
Environment=NODE_ENV=production
- [Install] WantedBy=multi-user.target
- Nginx 反向代理(/etc/nginx/conf.d/myapp.conf):
- server { listen 80; 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@your-server:/var/repo/myapp.git
- git push prod main
五、通用实践与注意事项
- 版本与缓存
- 固定 Node 版本(如 .nvmrc 或在 CI 指定镜像/版本),使用 npm ci 替代 npm install 提升一致性与速度;合理使用 cache 加速安装。
- 质量门禁
- 在流水线中加入 lint、test、coverage 阶段,必要时设置 only/except 或 rules 控制触发分支;产物(如 dist/)使用 artifacts 传递。
- 安全与合规
- 禁止在 Job 中明文写密钥;使用 SSH 私钥 或 CI/CD Variables 管理凭据;为生产环境单独配置 secrets 与最小权限的部署账号。
- 部署策略
- 采用 蓝绿/金丝雀 或 滚动 发布;先部署到 staging 再 production;保留最近 N 个版本以便快速回滚。
- 进程与日志
- 使用 PM2 或 systemd 托管 Node 进程,集中日志(journald 或文件),并配置 健康检查 与 自动重启 策略。