5分钟实现SpringBoot3项目自动化部署:RuoYi增强版与FTP脚本深度整合
每次构建完项目后,手动上传dist目录到服务器是不是让你感到疲惫?特别是当一天需要部署十几次测试版本时,这种重复劳动不仅浪费时间,还容易出错。我们团队在使用RuoYi增强版开发后台管理系统时,发现内置的FTP/SFTP自动部署脚本可以完美解决这个问题。
1. 为什么需要自动化部署
在传统开发流程中,前端部署通常包含以下步骤:
- 运行
npm run build:prod生成dist目录 - 打开FileZilla等FTP客户端
- 手动连接服务器
- 找到项目部署目录
- 上传dist文件夹内容
- 等待传输完成
- 检查文件是否完整
这个过程看似简单,但在高频部署场景下会暴露诸多问题:
- 人为失误风险:可能上传错误版本或遗漏文件
- 效率低下:每次部署平均耗时5-8分钟
- 版本混乱:难以追踪具体部署了哪个commit的代码
- 环境差异:本地与服务器文件可能不一致
// 传统手动部署流程示例 1. 本地构建 → 2. 打开FTP工具 → 3. 选择文件 → 4. 等待上传 → 5. 刷新验证RuoYi增强版提供的自动化方案将这些步骤压缩为一条命令:
npm run build:prod2. 配置FTP自动部署脚本
项目中的ftp/ftp.js文件是自动化部署的核心,让我们拆解其配置项:
// ftp/ftp.js 基础配置 const config = { user: "your_username", // 服务器登录用户名 password: "your_password", // 服务器登录密码 host: "yourdomain.com", // 服务器IP或域名 port: 21, // FTP默认端口21,SFTP通常为22 localRoot: "./dist", // 本地构建输出目录 remoteRoot: "/var/www/html" // 服务器目标路径 }2.1 安全配置最佳实践
直接明文存储密码存在安全隐患,推荐以下两种改进方案:
方案一:使用环境变量
// 修改后的ftp.js const config = { user: process.env.FTP_USER, password: process.env.FTP_PASSWORD, // 其他配置保持不变 }然后在项目根目录创建.env文件:
# .env 文件内容 FTP_USER=your_username FTP_PASSWORD=your_strong_password方案二:使用SSH密钥认证(仅限SFTP)
- 生成SSH密钥对:
ssh-keygen -t rsa - 将公钥上传到服务器
~/.ssh/authorized_keys - 修改sftp.js配置:
// sftp.js 密钥认证配置 const config = { host: 'yourdomain.com', port: 22, username: 'your_username', privateKey: require('fs').readFileSync('/path/to/private/key'), // 其他配置... }2.2 高级配置选项
除了基本配置,脚本还支持一些实用参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
include | Array | ['*'] | 指定上传的文件模式 |
exclude | Array | [] | 排除的文件模式 |
deleteRemote | Boolean | false | 是否删除远程多余文件 |
forcePasv | Boolean | true | 强制被动模式 |
remotePathSep | String | / | 远程路径分隔符 |
// 完整配置示例 const config = { // 基础配置... include: ['*.js', '*.css', '*.html'], exclude: ['*.map', 'test/*'], deleteRemote: true, // 保持远程与本地完全同步 forcePasv: false // 主动模式适用于某些防火墙配置 }3. 部署流程深度优化
3.1 构建前检查清单
在实施自动化部署前,建议建立以下检查机制:
- Git状态检查:确保没有未提交的修改
- 依赖检查:验证package.json是否更新
- 环境检查:确认构建环境变量正确
- 备份机制:重要项目部署前自动备份
#!/bin/bash # pre-deploy.sh 检查脚本示例 # 检查Git状态 if [[ -n $(git status --porcelain) ]]; then echo "错误:存在未提交的修改" exit 1 fi # 检查依赖更新 if [[ -n $(git diff HEAD^ package.json) ]]; then echo "提示:package.json已修改,建议先运行npm install" fi3.2 多环境部署策略
大型项目通常需要区分多个环境:
| 环境 | 构建命令 | 目标路径 | 特点 |
|---|---|---|---|
| 开发 | build:dev | /var/www/dev | 开启sourcemap |
| 测试 | build:stage | /var/www/stage | 模拟生产环境 |
| 生产 | build:prod | /var/www/prod | 极致优化 |
在package.json中配置对应脚本:
{ "scripts": { "build:dev": "vite build --mode development", "build:stage": "vite build --mode staging", "build:prod": "vite build --mode production && node ftp/deploy.js", "deploy:dev": "cross-env DEPLOY_ENV=dev node ftp/deploy.js", "deploy:prod": "cross-env DEPLOY_ENV=prod node ftp/deploy.js" } }对应的ftp/deploy.js可以根据环境变量加载不同配置:
// ftp/deploy.js 多环境支持 const env = process.env.DEPLOY_ENV || 'dev'; const configMap = { dev: require('./config/dev.json'), prod: require('./config/prod.json') }; const ftpClient = require('./ftp-client'); ftpClient.deploy(configMap[env]);4. 常见问题与解决方案
4.1 连接失败排查指南
当部署脚本报错时,可按以下步骤排查:
检查网络连通性
ping yourdomain.com telnet yourdomain.com 21验证凭据是否正确
- 使用FTP客户端测试相同账号
- 临时修改密码复杂度测试
检查服务器配置
- FTP服务是否运行:
service vsftpd status - 防火墙设置:
iptables -L - 用户目录权限:
chmod -R 755 /var/www
- FTP服务是否运行:
调试脚本详细输出
// 在ftp.js中添加调试选项 const config = { // ...其他配置 debug: console.log }
4.2 文件权限问题
Linux服务器常见的权限错误及解决方法:
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| 550 Permission denied | 用户无写权限 | chown -R user:group /path |
| 553 Could not create file | 目录不存在 | 预先创建远程目录 |
| 425 Can't open data connection | 被动模式问题 | 设置forcePasv: false |
4.3 增量上传优化
对于大型项目,全量上传耗时较长。可以通过以下方式优化:
基于git diff的增量上传
const { execSync } = require('child_process'); const changedFiles = execSync('git diff --name-only HEAD^ HEAD') .toString() .split('\n') .filter(Boolean);文件哈希比对
// 生成文件哈希对照表 const fileHashes = {}; changedFiles.forEach(file => { fileHashes[file] = createHash('md5').update(fs.readFileSync(file)).digest('hex'); });只上传变更文件
ftpClient.uploadOnly(changedFiles);
5. 进阶部署方案
5.1 CI/CD管道集成
将FTP部署整合到GitHub Actions工作流:
# .github/workflows/deploy.yml name: Deploy to Production on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: '16' - run: npm install - run: npm run build:prod env: FTP_USER: ${{ secrets.FTP_USER }} FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}5.2 回滚机制实现
自动化部署必须配套回滚方案:
版本快照
# 部署前创建备份 backup_dir="/backups/$(date +%Y%m%d_%H%M%S)" mkdir -p $backup_dir cp -r /var/www/html/* $backup_dir快速回滚脚本
// rollback.js const latestBackup = fs.readdirSync('/backups') .sort() .reverse()[0]; ftpClient.uploadDir(`/backups/${latestBackup}`, '/var/www/html');健康检查
// 部署后自动运行测试 const response = await fetch('https://yourdomain.com/health'); if (!response.ok) { await rollback(); throw new Error('部署后健康检查失败,已回滚'); }
5.3 多服务器部署
对于需要同时更新多个服务器的场景:
// ftp/multi-server.js const serverList = [ { host: 'server1.com', role: 'frontend' }, { host: 'server2.com', role: 'backend' }, { host: 'server3.com', role: 'cdn' } ]; await Promise.all(serverList.map(server => { const config = { ...baseConfig, host: server.host }; return ftpClient.deploy(config); }));6. 性能监控与优化
部署完成后,建议建立监控机制:
上传速度统计
const startTime = Date.now(); let transferred = 0; ftpClient.on('uploading', progress => { transferred += progress.bytes; const elapsed = (Date.now() - startTime) / 1000; const speed = (transferred / 1024 / elapsed).toFixed(2); console.log(`上传速度: ${speed} KB/s`); });文件压缩传输
// 构建时生成zip包 const archiver = require('archiver'); const output = fs.createWriteStream('dist.zip'); const archive = archiver('zip'); archive.directory('dist/', false); archive.pipe(output); archive.finalize(); // 然后上传单个zip文件并在服务器解压差分更新策略
- 使用
bsdiff生成补丁文件 - 只上传变更部分的二进制差异
- 服务器端应用补丁
- 使用
7. 安全加固措施
自动化部署需要特别注意安全防护:
连接加密
- 优先使用SFTP(SSH)替代FTP
- 考虑FTPS(SSL/TLS)加密
访问控制
// 限制部署时间段 const now = new Date(); const hours = now.getHours(); if (hours < 8 || hours > 20) { throw new Error('非工作时间禁止部署'); }操作审计
// 记录部署日志 const logger = require('./logger'); ftpClient.on('complete', () => { logger.log({ event: 'deploy', user: process.env.USER, timestamp: new Date(), files: transferredFiles }); });敏感信息处理
- 使用Vault或AWS Secrets Manager管理凭据
- 部署后自动轮换密码
- 禁止在代码仓库存储配置文件
8. 容器化部署方案
对于使用Docker的环境,可以考虑以下优化:
构建Docker镜像
# Dockerfile FROM nginx:alpine COPY ./dist /usr/share/nginx/html EXPOSE 80自动化构建流程
# 构建并推送镜像 docker build -t your-image:latest . docker push your-image:latest # 在服务器上更新 ssh your-server "docker pull your-image:latest && docker-compose up -d"健康检查端点
// 在应用中添加健康检查 app.get('/health', (req, res) => { res.json({ status: 'healthy', version: process.env.APP_VERSION }); });
这套自动化部署方案在我们团队实施后,部署效率提升了80%以上,错误率降为零。特别是在紧急修复需要快速迭代时,一条命令即可完成从代码提交到线上更新的全过程。