# Jenkins CI/CD迁移实施计划 > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** 将novalon-website项目从Woodpecker CI迁移到Jenkins,实现稳定可靠的CI/CD流程。 **Architecture:** 在生产服务器(139.155.109.62)上使用Docker部署Jenkins Master,通过Shell模式直接在宿主机执行构建和部署,避免创建临时Docker容器,实现零网络传输的高效构建流程。 **Tech Stack:** Jenkins LTS, Docker, Nginx, Node.js 20, npm, Git, Shell Script --- ## 前置条件 - 生产服务器:139.155.109.62 - 域名:ci.f.novalon.cn - 项目路径:/home/novalon/docker-app/novalon-website - SSH访问权限:root用户 - Docker已安装并运行 --- ## Phase 1: 环境准备(第1天) ### Task 1: 创建Jenkins部署目录结构 **Files:** - Create: `/home/novalon/docker-app/jenkins/docker-compose.yml` - Create: `/home/novalon/docker-app/jenkins/.env` - Create: `/home/novalon/docker-app/jenkins/backup.sh` **Step 1: SSH连接到生产服务器** ```bash ssh root@139.155.109.62 ``` Expected: 成功登录到服务器 **Step 2: 创建Jenkins目录** ```bash mkdir -p /home/novalon/docker-app/jenkins cd /home/novalon/docker-app/jenkins ``` Expected: 目录创建成功 **Step 3: 创建docker-compose.yml文件** ```yaml version: '3.8' services: jenkins: image: jenkins/jenkins:lts container_name: jenkins restart: unless-stopped ports: - "8080:8080" - "50000:50000" volumes: - jenkins_home:/var/jenkins_home - /var/run/docker.sock:/var/run/docker.sock - /home/novalon/docker-app:/home/novalon/docker-app - /root/.ssh:/root/.ssh:ro environment: - JENKINS_OPTS=--prefix=/jenkins - JAVA_OPTS=-Xmx2g -Xms512m -Duser.timezone=Asia/Shanghai user: root healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/jenkins/login"] interval: 30s timeout: 10s retries: 5 volumes: jenkins_home: driver: local ``` **Step 4: 创建环境变量文件** ```bash cat > .env << 'EOF' JENKINS_VERSION=lts JAVA_OPTS=-Xmx2g -Xms512m -Duser.timezone=Asia/Shanghai EOF ``` **Step 5: 创建备份脚本** ```bash cat > backup.sh << 'EOF' #!/bin/bash BACKUP_DIR="/home/novalon/backups/jenkins" DATE=$(date +%Y%m%d_%H%M%S) mkdir -p $BACKUP_DIR docker exec jenkins tar czf - /var/jenkins_home > $BACKUP_DIR/jenkins_backup_$DATE.tar.gz find $BACKUP_DIR -name "jenkins_backup_*.tar.gz" -mtime +7 -delete echo "Backup completed: jenkins_backup_$DATE.tar.gz" EOF chmod +x backup.sh ``` **Step 6: 提交配置** ```bash git add /home/novalon/docker-app/jenkins/ git commit -m "feat: add Jenkins deployment configuration" ``` --- ### Task 2: 启动Jenkins容器 **Files:** - Modify: `/home/novalon/docker-app/jenkins/docker-compose.yml` **Step 1: 启动Jenkins容器** ```bash cd /home/novalon/docker-app/jenkins docker-compose up -d ``` Expected: ``` Creating jenkins ... done ``` **Step 2: 检查容器状态** ```bash docker ps | grep jenkins ``` Expected: ``` CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES jenkins/jenkins:lts "/usr/local/bin/jenk…" 1 minute ago Up 1 minute 0.0.0.0:8080->8080/tcp, 0.0.0.0:50000->50000/tcp jenkins ``` **Step 3: 查看Jenkins初始密码** ```bash docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword ``` Expected: 输出一个32位的初始管理员密码 **Step 4: 保存初始密码** ```bash INITIAL_PASSWORD=$(docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword) echo "Jenkins Initial Password: $INITIAL_PASSWORD" > /home/novalon/docker-app/jenkins/initial_password.txt ``` **Step 5: 验证Jenkins启动** ```bash curl -I http://localhost:8080/jenkins/ ``` Expected: ``` HTTP/1.1 302 Found Location: http://localhost:8080/jenkins/login ``` --- ### Task 3: 配置Nginx反向代理 **Files:** - Create: `/etc/nginx/sites-available/ci.f.novalon.cn.conf` - Modify: `/etc/nginx/sites-enabled/` (创建软链接) **Step 1: 创建Nginx配置文件** ```bash cat > /etc/nginx/sites-available/ci.f.novalon.cn.conf << 'EOF' upstream jenkins { server localhost:8080; } server { listen 80; server_name ci.f.novalon.cn; # Redirect HTTP to HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name ci.f.novalon.cn; # SSL证书配置(假设已有证书) ssl_certificate /etc/nginx/ssl/novalon.cn.crt; ssl_certificate_key /etc/nginx/ssl/novalon.cn.key; # SSL优化配置 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # 安全头 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; # Jenkins反向代理 location / { proxy_pass http://jenkins; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; # 增大上传限制 client_max_body_size 100m; # 超时配置 proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; # WebSocket支持 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } # 访问日志 access_log /var/log/nginx/jenkins-access.log; error_log /var/log/nginx/jenkins-error.log; } EOF ``` **Step 2: 测试Nginx配置** ```bash nginx -t ``` Expected: ``` nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` **Step 3: 启用站点配置** ```bash ln -sf /etc/nginx/sites-available/ci.f.novalon.cn.conf /etc/nginx/sites-enabled/ ``` **Step 4: 重载Nginx** ```bash systemctl reload nginx ``` Expected: ``` Job completed successfully ``` **Step 5: 验证HTTPS访问** ```bash curl -I https://ci.f.novalon.cn/jenkins/ ``` Expected: ``` HTTP/2 302 location: https://ci.f.novalon.cn/jenkins/login ``` --- ### Task 4: 初始化Jenkins **Files:** - None (通过Web界面操作) **Step 1: 访问Jenkins Web界面** 打开浏览器访问:https://ci.f.novalon.cn/jenkins/ Expected: 显示Jenkins解锁页面 **Step 2: 输入初始密码** ```bash cat /home/novalon/docker-app/jenkins/initial_password.txt ``` 复制密码并粘贴到Web界面 **Step 3: 安装推荐插件** 在Web界面选择"Install suggested plugins" Expected: 自动安装以下插件: - Git Plugin - Pipeline - Workspace Cleanup - Timestamper - Credentials Binding - SSH Build Agents - Docker Pipeline **Step 4: 创建管理员账户** 在Web界面填写: - Username: admin - Password: <设置强密码> - Full name: Jenkins Admin - E-mail address: admin@novalon.cn **Step 5: 配置Jenkins URL** 确认Jenkins URL为:https://ci.f.novalon.cn/jenkins/ **Step 6: 保存配置** 点击"Save and Finish",然后点击"Start using Jenkins" Expected: 进入Jenkins主界面 --- ### Task 5: 安装必要插件 **Files:** - None (通过Web界面操作) **Step 1: 进入插件管理** 导航到:Manage Jenkins → Manage Plugins → Available **Step 2: 搜索并安装以下插件** 勾选以下插件: - NodeJS Plugin - Pipeline Utility Steps - Git Parameter - Build Timeout - Email Extension - AnsiColor **Step 3: 点击"Install without restart"** Expected: 插件安装完成 **Step 4: 验证插件安装** 导航到:Manage Jenkins → Manage Plugins → Installed 确认所有插件都已安装 --- ### Task 6: 配置全局工具 **Files:** - None (通过Web界面操作) **Step 1: 配置Node.js** 导航到:Manage Jenkins → Global Tool Configuration 找到"NodeJS"部分,点击"Add NodeJS": - Name: NodeJS-20 - Install automatically: 勾选 - Version: NodeJS 20.x (选择最新的20.x版本) **Step 2: 配置Git** 找到"Git"部分: - Name: Default - Path to Git executable: git (使用系统Git) **Step 3: 配置Maven(可选)** 如果需要Java项目支持: - Name: Maven-3.9 - Install automatically: 勾选 - Version: 3.9.x **Step 4: 保存配置** 点击"Save" --- ## Phase 2: 配置CI/CD流水线(第2天) ### Task 7: 创建Jenkins凭据 **Files:** - None (通过Web界面操作) **Step 1: 进入凭据管理** 导航到:Manage Jenkins → Credentials → System → Global credentials **Step 2: 添加Git凭据** 点击"Add Credentials": - Kind: Username with password - Scope: Global - Username: - Password: - ID: git-credentials - Description: Git Repository Credentials **Step 3: 添加SSH凭据** 点击"Add Credentials": - Kind: SSH Username with private key - Scope: Global - Username: root - Private Key: Enter directly - Key: <粘贴SSH私钥内容> - ID: ssh-credentials - Description: SSH Key for Deployment **Step 4: 验证凭据** 确认两个凭据都已出现在列表中 --- ### Task 8: 创建Jenkinsfile **Files:** - Create: `/home/novalon/docker-app/novalon-website/Jenkinsfile` **Step 1: 切换到项目目录** ```bash cd /home/novalon/docker-app/novalon-website ``` **Step 2: 创建Jenkinsfile** ```groovy pipeline { agent any environment { NODE_ENV = 'production' PROJECT_PATH = '/home/novalon/docker-app/novalon-website' BACKUP_PATH = '/home/novalon/backups/novalon-website' } tools { nodejs 'NodeJS-20' } options { timeout(time: 30, unit: 'MINUTES') timestamps() ansiColor('xterm') buildDiscarder(logRotator(numToKeepStr: '10')) } stages { stage('Checkout') { steps { echo '📥 Checking out code...' checkout scm sh 'git log -1 --pretty=format:"%h - %an, %ar : %s"' } } stage('Install Dependencies') { steps { echo '📦 Installing dependencies...' sh ''' npm ci --legacy-peer-deps --prefer-offline || \ npm install --legacy-peer-deps ''' } } stage('Quality Gates') { parallel { stage('Lint') { steps { echo '🔍 Running linter...' sh 'npm run lint' } } stage('Type Check') { steps { echo '🔍 Running type checker...' sh 'npm run type-check' } } } } stage('Build') { steps { echo '🏗️ Building production artifacts...' sh ''' npm run build ls -la dist/ ''' } } stage('Backup Current Version') { steps { echo '💾 Backing up current version...' sh ''' mkdir -p ${BACKUP_PATH} if [ -d "${PROJECT_PATH}/dist" ]; then tar czf ${BACKUP_PATH}/backup_$(date +%Y%m%d_%H%M%S).tar.gz \ -C ${PROJECT_PATH} dist/ public/ package.json echo "✅ Backup created" else echo "⚠️ No existing dist to backup" fi ''' } } stage('Deploy') { steps { echo '🚀 Deploying to production...' sh ''' cd ${PROJECT_PATH} # 停止现有容器 docker-compose down || true # 启动新容器 docker-compose -f docker-compose.server.yml up -d --build # 等待容器启动 sleep 10 # 检查容器状态 docker-compose -f docker-compose.server.yml ps ''' } } stage('Health Check') { steps { echo '🏥 Checking application health...' sh ''' # 等待应用启动 sleep 5 # 检查HTTP响应 for i in {1..10}; do if curl -f http://localhost:3000 > /dev/null 2>&1; then echo "✅ Application is healthy" exit 0 fi echo "Waiting for application to start... ($i/10)" sleep 3 done echo "❌ Application health check failed" exit 1 ''' } } } post { success { echo ''' ✅ ======================================== ✅ Deployment Successful! ✅ ======================================== ✅ Project: novalon-website ✅ Branch: ${GIT_BRANCH} ✅ Commit: ${GIT_COMMIT} ✅ Build: #${BUILD_NUMBER} ✅ ======================================== ''' } failure { echo ''' ❌ ======================================== ❌ Deployment Failed! ❌ ======================================== ❌ Project: novalon-website ❌ Branch: ${GIT_BRANCH} ❌ Commit: ${GIT_COMMIT} ❌ Build: #${BUILD_NUMBER} ❌ ======================================== ❌ Check the logs for details ❌ ======================================== ''' } always { cleanWs() } } } ``` **Step 3: 提交Jenkinsfile** ```bash git add Jenkinsfile git commit -m "feat: add Jenkinsfile for CI/CD pipeline" git push origin main ``` --- ### Task 9: 创建Jenkins Pipeline Job **Files:** - None (通过Web界面操作) **Step 1: 创建新Job** 在Jenkins主界面点击"New Item" **Step 2: 配置Job** - Enter an item name: novalon-website - Select: Pipeline - Click: OK **Step 3: 配置General** - Description: Novalon Website CI/CD Pipeline - Discard old builds: 勾选 - Max # of builds to keep: 10 **Step 4: 配置Build Triggers** - Poll SCM: 勾选 - Schedule: `H/5 * * * *` (每5分钟检查一次) **Step 5: 配置Pipeline** - Definition: Pipeline script from SCM - SCM: Git - Repository URL: https://git.f.novalon.cn/novalon/novalon-website.git - Credentials: 选择之前创建的git-credentials - Branch Specifier: `*/main` - Script Path: Jenkinsfile **Step 6: 保存配置** 点击"Save" --- ### Task 10: 配置Git Webhook **Files:** - None (通过Web界面操作) **Step 1: 获取Jenkins Webhook URL** ``` https://ci.f.novalon.cn/jenkins/git/notifyCommit?url=https://git.f.novalon.cn/novalon/novalon-website.git ``` **Step 2: 在Git仓库配置Webhook** 访问Git仓库设置页面: - Webhook URL: `https://ci.f.novalon.cn/jenkins/git/notifyCommit?url=https://git.f.novalon.cn/novalon/novalon-website.git` - Content type: application/json - Trigger: Push events - Active: 勾选 **Step 3: 测试Webhook** 在Git仓库页面点击"Test Webhook" → "Push" Expected: Jenkins触发新的构建 --- ## Phase 3: 测试和优化(第3天) ### Task 11: 执行完整构建测试 **Files:** - None (通过Web界面操作) **Step 1: 手动触发构建** 在Jenkins Job页面点击"Build Now" **Step 2: 观察构建过程** 点击构建编号,然后点击"Console Output" Expected: - 所有阶段依次执行 - 没有错误信息 - 最终显示"Deployment Successful!" **Step 3: 验证部署** 访问生产网站:https://novalon.cn Expected: 网站正常运行,显示最新内容 **Step 4: 检查容器状态** ```bash ssh root@139.155.109.62 cd /home/novalon/docker-app/novalon-website docker-compose -f docker-compose.server.yml ps ``` Expected: ``` NAME COMMAND SERVICE STATUS PORTS novalon-website "node dist/server" app running 0.0.0.0:3000->3000/tcp ``` --- ### Task 12: 性能优化 **Files:** - Modify: `/home/novalon/docker-app/novalon-website/Jenkinsfile` **Step 1: 添加npm缓存配置** 在Jenkinsfile的"Install Dependencies"阶段添加: ```groovy stage('Install Dependencies') { steps { echo '📦 Installing dependencies...' sh ''' npm config set cache /tmp/npm-cache --global npm ci --legacy-peer-deps --prefer-offline --cache /tmp/npm-cache || \ npm install --legacy-peer-deps --cache /tmp/npm-cache ''' } } ``` **Step 2: 配置构建缓存** 在Jenkinsfile的options部分添加: ```groovy options { timeout(time: 30, unit: 'MINUTES') timestamps() ansiColor('xterm') buildDiscarder(logRotator(numToKeepStr: '10')) // 添加缓存配置 skipDefaultCheckout(false) disableConcurrentBuilds() } ``` **Step 3: 提交优化** ```bash git add Jenkinsfile git commit -m "perf: optimize Jenkins pipeline with caching" git push origin main ``` **Step 4: 测试优化效果** 再次触发构建,观察构建时间 Expected: 构建时间缩短20-30% --- ### Task 13: 配置邮件通知 **Files:** - None (通过Web界面操作) **Step 1: 配置邮件服务器** 导航到:Manage Jenkins → Configure System 找到"Extended E-mail Notification": - SMTP server: smtp.novalon.cn - Default Content Type: HTML - Default Recipients: team@novalon.cn **Step 2: 在Jenkinsfile添加邮件通知** ```groovy post { success { emailext ( subject: "✅ Jenkins Build Success: ${env.JOB_NAME} #${env.BUILD_NUMBER}", body: """

Build Successful

Project: ${env.JOB_NAME}

Build Number: ${env.BUILD_NUMBER}

Branch: ${env.GIT_BRANCH}

Commit: ${env.GIT_COMMIT}

View Build Details

""", to: 'team@novalon.cn' ) } failure { emailext ( subject: "❌ Jenkins Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}", body: """

Build Failed

Project: ${env.JOB_NAME}

Build Number: ${env.BUILD_NUMBER}

Branch: ${env.GIT_BRANCH}

Commit: ${env.GIT_COMMIT}

View Console Output

""", to: 'team@novalon.cn' ) } } ``` **Step 3: 测试邮件通知** 触发一次构建,检查邮件是否正常发送 --- ### Task 14: 编写操作文档 **Files:** - Create: `/home/novalon/docker-app/novalon-website/docs/jenkins/JENKINS_GUIDE.md` **Step 1: 创建文档目录** ```bash mkdir -p docs/jenkins ``` **Step 2: 编写操作指南** ```markdown # Jenkins CI/CD 操作指南 ## 访问Jenkins - URL: https://ci.f.novalon.cn/jenkins/ - 用户名: admin - 密码: <存储在安全位置> ## 触发构建 ### 方式1: 自动触发 - 代码推送到main分支时自动触发 - Webhook配置在Git仓库设置中 ### 方式2: 手动触发 1. 登录Jenkins 2. 选择Job: novalon-website 3. 点击"Build Now" ## 查看构建日志 1. 点击构建编号 2. 点击"Console Output" ## 回滚操作 如果部署失败,可以回滚到上一个版本: \`\`\`bash cd /home/novalon/docker-app/novalon-website # 查看备份列表 ls -lt /home/novalon/backups/novalon-website/ # 恢复备份 tar xzf /home/novalon/backups/novalon-website/backup_YYYYMMDD_HHMMSS.tar.gz -C ./ # 重启容器 docker-compose -f docker-compose.server.yml restart \`\`\` ## 故障排查 ### 构建失败 1. 检查Console Output查看错误信息 2. 检查依赖是否正确安装 3. 检查代码是否有语法错误 ### 部署失败 1. 检查容器日志: `docker-compose logs` 2. 检查端口占用: `netstat -tlnp | grep 3000` 3. 检查磁盘空间: `df -h` ### Webhook不触发 1. 检查Git仓库Webhook配置 2. 检查Jenkins是否可达 3. 查看Jenkins系统日志 ## 维护操作 ### 备份Jenkins数据 \`\`\`bash cd /home/novalon/docker-app/jenkins ./backup.sh \`\`\` ### 更新Jenkins \`\`\`bash cd /home/novalon/docker-app/jenkins docker-compose pull docker-compose up -d \`\`\` ### 查看Jenkins日志 \`\`\`bash docker logs jenkins -f \`\`\` ``` **Step 3: 提交文档** ```bash git add docs/jenkins/ git commit -m "docs: add Jenkins operation guide" git push origin main ``` --- ## Phase 4: 清理和收尾 ### Task 15: 停用Woodpecker CI **Files:** - Modify: `/home/novalon/docker-app/novalon-website/.woodpecker.yml` **Step 1: 备份Woodpecker配置** ```bash cp .woodpecker.yml .woodpecker.yml.backup ``` **Step 2: 重命名Woodpecker配置** ```bash mv .woodpecker.yml .woodpecker.yml.disabled ``` **Step 3: 提交更改** ```bash git add .woodpecker.yml.disabled git rm .woodpecker.yml git commit -m "chore: disable Woodpecker CI, switch to Jenkins" git push origin main ``` **Step 4: 验证Woodpecker不再触发** 推送代码后,确认Woodpecker不再创建新的Pipeline --- ### Task 16: 最终验证 **Files:** - None **Step 1: 执行完整构建流程** ```bash # 在本地修改代码 echo "" >> src/app/layout.tsx # 提交并推送 git add . git commit -m "test: verify Jenkins CI/CD pipeline" git push origin main ``` **Step 2: 验证自动触发** - 检查Jenkins是否自动触发构建 - 检查构建是否成功 - 检查网站是否更新 **Step 3: 验证邮件通知** 检查是否收到构建成功邮件 **Step 4: 验证回滚功能** ```bash # 恢复之前的代码 git reset --hard HEAD~1 git push -f origin main ``` 确认Jenkins触发构建并成功回滚 --- ## 风险评估和缓解措施 ### 风险1: Jenkins容器故障 **缓解措施:** - 定期备份Jenkins数据(每天自动备份) - 使用Docker Volume持久化数据 - 监控容器健康状态 ### 风险2: 构建失败 **缓解措施:** - 自动备份当前版本 - 提供快速回滚机制 - 详细的错误日志和通知 ### 风险3: 网络问题 **缓解措施:** - Jenkins部署在同一台服务器,避免网络传输 - 配置超时和重试机制 - 使用本地缓存加速构建 ### 风险4: 安全问题 **缓解措施:** - 使用HTTPS加密通信 - 配置强密码和访问控制 - 定期更新Jenkins和插件 - 限制网络访问(仅允许必要IP) --- ## 成功标准 1. ✅ Jenkins成功部署并运行 2. ✅ CI/CD流水线正常工作 3. ✅ 代码推送自动触发构建 4. ✅ 构建成功率 > 95% 5. ✅ 平均构建时间 < 10分钟 6. ✅ 部署成功率 = 100% 7. ✅ 回滚功能正常 8. ✅ 邮件通知正常 9. ✅ 文档完善 10. ✅ 团队成员培训完成 --- ## 后续优化建议 1. **性能优化** - 配置npm缓存加速依赖安装 - 使用并行构建减少总时间 - 优化Docker镜像构建 2. **功能增强** - 添加单元测试和集成测试 - 配置代码质量扫描 - 添加性能测试 3. **监控告警** - 集成Prometheus监控 - 配置Grafana可视化 - 设置告警规则 4. **安全加固** - 配置RBAC权限控制 - 启用审计日志 - 定期安全扫描 --- ## 参考资源 - [Jenkins官方文档](https://www.jenkins.io/doc/) - [Jenkins Pipeline语法](https://www.jenkins.io/doc/book/pipeline/syntax/) - [Jenkins最佳实践](https://www.jenkins.io/doc/book/pipeline/best-practices/) - [Node.js Plugin文档](https://plugins.jenkins.io/nodejs/)