1103 lines
24 KiB
Markdown
1103 lines
24 KiB
Markdown
# 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
|
||
<container_id> 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: <Git用户名>
|
||
- Password: <Git密码或Token>
|
||
- 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: """
|
||
<h2>Build Successful</h2>
|
||
<p><strong>Project:</strong> ${env.JOB_NAME}</p>
|
||
<p><strong>Build Number:</strong> ${env.BUILD_NUMBER}</p>
|
||
<p><strong>Branch:</strong> ${env.GIT_BRANCH}</p>
|
||
<p><strong>Commit:</strong> ${env.GIT_COMMIT}</p>
|
||
<p><a href="${env.BUILD_URL}">View Build Details</a></p>
|
||
""",
|
||
to: 'team@novalon.cn'
|
||
)
|
||
}
|
||
|
||
failure {
|
||
emailext (
|
||
subject: "❌ Jenkins Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
|
||
body: """
|
||
<h2>Build Failed</h2>
|
||
<p><strong>Project:</strong> ${env.JOB_NAME}</p>
|
||
<p><strong>Build Number:</strong> ${env.BUILD_NUMBER}</p>
|
||
<p><strong>Branch:</strong> ${env.GIT_BRANCH}</p>
|
||
<p><strong>Commit:</strong> ${env.GIT_COMMIT}</p>
|
||
<p><a href="${env.BUILD_URL}console">View Console Output</a></p>
|
||
""",
|
||
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 "<!-- Test Jenkins CI/CD -->" >> 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/)
|