Jenkins CI/CD 流水线

环境说明:CentOS 7 / Rocky Linux 9 / Ubuntu 20.04+

软件版本:Jenkins 2.426+ | JDK 17 | Docker 24+ | Kubernetes 1.28+

目标读者:DevOps 工程师 / 后端开发 / 运维工程师


一、CI/CD 架构概览

1.1 经典 CI/CD 流程

┌─────────────────────────────────────────────────────────────────────────┐
│                          Jenkins Master Server                            │
│                    (任务调度 / Web UI / 配置管理)                          │
└─────────────────────────────────────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                        Jenkins Agent (Build Node)                        │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐            │
│  │  Checkout │ → │  Build   │ → │   Test   │ → │ Package  │            │
│  │  代码拉取  │   │  编译构建  │   │  单元测试  │   │  镜像打包  │            │
│  └──────────┘   └──────────┘   └──────────┘   └──────────┘            │
│        │                                                         │        │
│        └────────────── ▼ ────────────────────────────────┘             │
│                    ┌──────────┐                                       │
│                    │ Deploy   │                                        │
│                    │  部署发布  │                                        │
│                    └──────────┘                                       │
└─────────────────────────────────────────────────────────────────────────┘
                              │
                              ▼
                    ┌──────────────────┐
                    │   Kubernetes     │
                    │   / Docker Host  │
                    └──────────────────┘
                              │
                              ▼
                    ┌──────────────────┐
                    │   生产环境       │
                    │   Production     │
                    └──────────────────┘

1.2 Jenkins 核心组件说明

组件作用端口
Jenkins Master任务调度、API 服务、Web UI8080 / 443
Jenkins Agent执行流水线任务,可水平扩展随机
Plugin扩展 Jenkins 功能(Git/Docker/K8s 等)
Pipeline流水线即代码,定义构建流程
Credential安全存储密钥(密码/Token/SSH Key)

1.3 硬件推荐配置

环境Master 配置Agent 配置
小型团队(<10人)2核/4GB2核/4GB
中型团队(10-50人)4核/8GB4核/8GB × 2
大型团队(50+人)8核/16GB8核/16GB × N

二、安装 Jenkins

2.1 环境要求

项目要求
操作系统CentOS 7+ / Ubuntu 18+ / Rocky Linux 9
JDKJDK 11 / JDK 17(推荐 JDK 17
内存≥ 4 GB(生产环境建议 8 GB+)
磁盘≥ 50 GB(根据项目数量动态增长)
网络可访问外网(下载插件/依赖)

2.2 安装 JDK 17

# CentOS / Rocky Linux
sudo yum install -y java-17-openjdk java-17-openjdk-devel

# Ubuntu / Debian
sudo apt update
sudo apt install -y openjdk-17-jdk openjdk-17-jre

# 验证安装
java -version

# 设置 JAVA_HOME
echo "export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64" >> ~/.bashrc
source ~/.bashrc
echo $JAVA_HOME

2.3 安装 Jenkins(CentOS / Rocky Linux)

# 1. 添加 Jenkins 官方 yum 源
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key

# 2. 安装 Jenkins
sudo yum install -y jenkins

# 3. 配置 Jenkins 运行环境(JDK 17)
sudo sed -i 's/JENKINS_JAVA_CMD=/JENKINS_JAVA_CMD=\/usr\/lib\/jvm\/java-17-openjdk-amd64\/bin\/java/' /etc/sysconfig/jenkins

# 4. 启动并设置开机自启
sudo systemctl daemon-reload
sudo systemctl start jenkins
sudo systemctl enable jenkins

# 5. 检查状态
sudo systemctl status jenkins

# 6. 查看初始管理员密码
sudo cat /var/lib/jenkins/secrets/initialAdminPassword

2.4 安装 Jenkins(Ubuntu / Debian)

# 1. 添加 Jenkins 官方 GPG 密钥
curl -fsSL https://pkg.jenkins.io/debian/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null

# 2. 添加 apt 源
echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian binary/" | sudo tee /etc/apt/sources.list.d/jenkins.list

# 3. 安装 Jenkins
sudo apt update
sudo apt install -y jenkins

# 4. 启动并设置开机自启
sudo systemctl start jenkins
sudo systemctl enable jenkins

# 5. 查看初始管理员密码
sudo cat /var/lib/jenkins/secrets/initialAdminPassword

2.5 防火墙配置

# CentOS / Rocky
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --permanent --add-port=50000/tcp  # Agent 通信端口
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports

# Ubuntu
sudo ufw allow 8080/tcp
sudo ufw allow 50000/tcp
sudo ufw reload

2.6 访问 Jenkins Web UI

打开浏览器访问:http://<服务器IP>:8080

首次访问引导步骤

┌─────────────────────────────────────────────────────────────────────┐
│                     Welcome to Jenkins!                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  解锁 Jenkins                                                       │
│  ─────────────────                                                │
│                                                                     │
│  要完成设置,请将以下密码粘贴到管理员密码字段:                         │
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  a1b2c3d4e5f6...                                           │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  [继续]                                                            │
│                                                                     │
│  密码文件位置:/var/lib/jenkins/secrets/initialAdminPassword       │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

后续引导步骤

步骤 1  →  安装插件(选择"安装推荐插件")
步骤 2  →  创建第一个管理员用户
步骤 3  →  配置 Jenkins URL(保持默认即可)
步骤 4  →  开始使用 Jenkins!

⏱️ 耐心等待:插件安装可能需要 5-10 分钟,请勿刷新页面。


三、基础配置

3.1 安装必备插件

进入 Dashboard → Manage Jenkins → Manage Plugins

Available 标签中搜索并安装以下插件:

插件名称用途
Git代码仓库拉取
Pipeline流水线即代码(必装)
Docker PipelineDocker 构建与推送
Kubernetes CLIK8s 部署
Config File Provider配置文件管理
Role-based Authorization Strategy基于角色的权限管理
Email Extension Plugin邮件通知
钉钉通知插件钉钉群机器人告警

3.2 配置系统时间(时区)

# 设置时区为 Asia/Shanghai
sudo timedatectl set-timezone Asia/Shanghai
sudo timedatectl status

# 验证 Jenkins 时区
# Dashboard → Manage Jenkins → Script Console
println(new Date().format('yyyy-MM-dd HH:mm:ss', TimeZone.getTimeZone('Asia/Shanghai')))

3.3 配置邮件通知

进入 Dashboard → Manage Jenkins → System

找到 Jenkins LocationE-mail Notification 部分:

┌─────────────────────────────────────────────────────────────────┐
│  系统配置                                                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Jenkins URL:        http://192.168.1.100:8080/                 │
│  系统管理员邮件地址:   admin@example.com                          │
│                                                                  │
│  ── E-mail Notification ──────────────────────────────────────  │
│                                                                  │
│  SMTP 服务器:       smtp.exmail.qq.com                           │
│  SMTP 端口:        465                                           │
│  ☑ 使用 SSL        (QQ企业邮箱/163邮箱推荐 465端口)              │
│                                                                  │
│  用户名:           jenkins@example.com                          │
│  密码:             ******************                          │
│                                                                  │
│  [Test Configuration]  测试配置是否正确                          │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

3.4 配置钉钉告警(可选)

# 1. 在钉钉群 → 群设置 → 智能群助手 → 添加机器人
# 2. 选择"自定义机器人",获取 Webhook 地址
# 3. 在 Jenkins 中安装"钉钉通知插件"
# 4. 配置钉钉机器人安全设置(关键词或签名)

四、权限管理:配置用户与角色

4.1 安装角色管理插件

安装 Role-based Authorization Strategy 插件。

4.2 启用角色策略

进入 Dashboard → Manage Jenkins → Security

授权策略 → 选择 "Role-Based Strategy"

4.3 创建角色

进入 Dashboard → Manage Jenkins → Manage and Assign Roles

创建全局角色

角色名权限
global-admin全部权限
global-developerJob创建/构建/查看
global-viewer仅查看权限

创建项目角色(按项目隔离):

角色名Pattern说明
project-frontendfrontend-.*匹配所有 frontend- 开头的 Job
project-backendbackend-.*匹配所有 backend- 开头的 Job

4.4 分配角色

用户分配角色
adminglobal-admin
dev-zhangglobal-developer + project-frontend
dev-liglobal-developer + project-backend
tester-wangglobal-viewer

五、Agent 节点配置(分布式构建)

5.1 Agent 节点简介

当构建任务增多时,单个 Master 无法承载,通过添加 Agent 节点实现水平扩展

5.2 在 Master 上添加 Agent

方式一:通过 Web UI 添加

进入 Dashboard → Manage Jenkins → Nodes → New Node

┌─────────────────────────────────────────────────────────────────┐
│  新建节点                                                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  节点名称: build-agent-01                                         │
│  类型:      ☉ Permanent Agent                                   │
│                                                                  │
│  ── 配置 ─────────────────────────────────────────────────────  │
│                                                                  │
│  执行器数量:    2          (并发构建数)                           │
│  根目录:       /home/jenkins/agent                               │
│  标签:         java-builder linux                               │
│  用法:        尽可能使用此节点                                    │
│                                                                  │
│  启动方式:     ☉ 通过 Java Web Start 启动 Agent                   │
│               ○ 通过 SSH 启动现有 Agent                         │
│               ○ 通过相关 Java 程序启动 Agent                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

**方式二:通过 SSH 启动 Agent(推荐)

# 在 Agent 节点上安装 JDK
sudo yum install -y java-17-openjdk

# 在 Master 节点上生成 SSH 密钥
ssh-keygen -t rsa -C "jenkins-master"
ssh-copy-id jenkins@<agent-ip>

# 在 Master Jenkins UI 中配置 SSH 连接
# Manage Jenkins → Manage Nodes → New Node
# 启动方式选择 "通过 SSH 启动"
# Host: <agent-ip>
# Credentials: 添加 SSH 密钥凭据

5.3 配置 Agent 标签

// 在 Pipeline 中指定运行节点
pipeline {
    agent {
        label 'java-builder'  // 只在带此标签的节点运行
    }
    // ...
}

六、流水线语法:Declarative Pipeline

6.1 流水线基础结构

// Jenkinsfile(放在项目根目录)
pipeline {
    // 全局参数
    agent any  // 可指定: any / none / label 'xxx' / docker 'xxx'

    environment {
        APP_NAME = 'my-app'
        REGISTRY = 'registry.example.com'
    }

    options {
        timeout(time: 1, unit: 'HOURS')  // 超时设置
        timestamps()                       // 日志带时间戳
        buildDiscarder(logRotator(30))    // 保留30天构建历史
    }

    stages {
        stage('代码拉取') {
            steps {
                checkout scm
            }
        }

        stage('编译构建') {
            steps {
                sh './mvnw clean package'
            }
        }

        stage('单元测试') {
            steps {
                sh './mvnw test'
            }
            post {
                always {
                    junit 'target/surefire-reports/*.xml'
                }
            }
        }

        stage('代码扫描') {
            steps {
                sh 'sonar-scanner'
            }
        }

        stage('构建镜像') {
            steps {
                sh '''
                    docker build -t ${REGISTRY}/${APP_NAME}:${BUILD_NUMBER} .
                    docker build -t ${REGISTRY}/${APP_NAME}:latest .
                '''
            }
        }

        stage('推送到仓库') {
            steps {
                sh '''
                    docker login ${REGISTRY} -u ${DOCKER_USER} -p ${DOCKER_PASS}
                    docker push ${REGISTRY}/${APP_NAME}:${BUILD_NUMBER}
                    docker push ${REGISTRY}/${APP_NAME}:latest
                '''
            }
        }

        stage('部署到测试环境') {
            when {
                branch 'develop'
            }
            steps {
                sh "kubectl apply -f k8s/ -n test"
            }
        }

        stage('部署到生产环境') {
            when {
                branch 'main'
            }
            steps {
                input message: '确认部署到生产环境?', ok: '确认部署'
                sh "kubectl apply -f k8s/ -n prod"
            }
        }
    }

    post {
        always {
            echo '流水线执行完成'
            cleanWs()  // 清理工作空间
        }
        success {
            echo '✅ 构建成功!'
            dingTalk notify: 'success'
        }
        failure {
            echo '❌ 构建失败!'
            dingTalk notify: 'failure'
            mail to: 'dev-team@example.com',
                 subject: "Jenkins构建失败: ${APP_NAME} #${BUILD_NUMBER}",
                 body: "构建失败,请检查日志: ${BUILD_URL}"
        }
    }
}

6.2 常用语法速查

参数化构建

pipeline {
    agent any

    parameters {
        string(name: 'BRANCH', defaultValue: 'main', description: '代码分支')
        choice(name: 'ENV', choices: ['dev', 'test', 'prod'], description: '部署环境')
        booleanParam(name: 'SKIP_TEST', defaultValue: false, description: '跳过测试?')
        password(name: 'DEPLOY_TOKEN', description: '部署密钥')
    }

    stages {
        stage('构建') {
            steps {
                echo "分支: ${params.BRANCH}, 环境: ${params.ENV}"
                sh "mvn clean package -DskipTests=${params.SKIP_TEST}"
            }
        }
    }
}

并行执行

stages {
    stage('并行构建') {
        parallel {
            stage('构建前端') {
                steps {
                    sh 'cd frontend && npm install && npm run build'
                }
            }
            stage('构建后端') {
                steps {
                    sh 'cd backend && ./mvnw clean package'
                }
            }
        }
    }
}

条件执行

stage('部署生产') {
    when {
        allOf {
            branch 'main'
            environment name: 'DEPLOY_ENABLED', value: 'true'
        }
    }
    steps {
        sh 'kubectl apply -f k8s/'
    }
}

矩阵式构建(Matrix)

pipeline {
    agent none
    stages {
        stage('矩阵构建') {
            matrix {
                axes {
                    axis {
                        name 'PLATFORM'
                        values 'linux', 'windows', 'macos'
                    }
                    axis {
                        name 'ARCH'
                        values 'amd64', 'arm64'
                    }
                }
                stages {
                    stage('构建') {
                        steps {
                            echo "构建平台: ${PLATFORM}, 架构: ${ARCH}"
                            sh "make build PLATFORM=${PLATFORM} ARCH=${ARCH}"
                        }
                    }
                }
            }
        }
    }
}

七、实战场景一:Java Maven 项目

7.1 项目结构

my-springboot-app/
├── src/
├── pom.xml
├── Jenkinsfile
├── Dockerfile
└── k8s/
    ├── deployment.yaml
    └── service.yaml

7.2 Jenkinsfile

pipeline {
    agent {
        docker {
            image 'maven:3.9-eclipse-temurin-17'
            args '-v /root/.m2:/root/.m2'
        }
    }

    environment {
        APP_NAME = 'my-springboot-app'
        REGISTRY = 'harbor.example.com'
    }

    stages {
        stage('代码拉取') {
            steps {
                checkout scm
            }
        }

        stage('编译') {
            steps {
                sh 'mvn clean compile -DskipTests'
            }
        }

        stage('单元测试') {
            steps {
                sh 'mvn test'
            }
            post {
                always {
                    junit 'target/surefire-reports/*.xml'
                    publishHTML target: [
                        reportDir: 'target/site/jacoco',
                        reportFiles: 'index.html',
                        reportName: 'Jacoco Report'
                    ]
                }
            }
        }

        stage('打包') {
            steps {
                sh 'mvn package -DskipTests'
            }
        }

        stage('构建 Docker 镜像') {
            steps {
                script {
                    def imageTag = "${env.BUILD_NUMBER}"
                    docker.build("${APP_NAME}:${imageTag}", "-f Dockerfile .")
                }
            }
        }

        stage('推送镜像') {
            steps {
                script {
                    docker.withRegistry('https://harbor.example.com', 'harbor-credential') {
                        def imageTag = "${env.BUILD_NUMBER}"
                        docker.image("${APP_NAME}:${imageTag}").push()
                        docker.image("${APP_NAME}:${imageTag}").push('latest')
                    }
                }
            }
        }

        stage('部署到 K8s') {
            when {
                branch 'main'
            }
            steps {
                script {
                    sh """
                        kubectl set image deployment/${APP_NAME} \
                        ${APP_NAME}=harbor.example.com/${APP_NAME}:${env.BUILD_NUMBER} \
                        -n production
                    """
                }
            }
        }
    }

    post {
        success {
            echo '🎉 构建并部署成功!'
        }
        failure {
            echo '❌ 构建失败,请检查日志'
        }
    }
}

7.3 Dockerfile

FROM eclipse-temurin:17-jre-alpine
LABEL maintainer="devops@example.com"

WORKDIR /app

COPY target/my-springboot-app-*.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "/app/app.jar"]

八、实战场景二:Node.js 前端项目

8.1 Jenkinsfile

pipeline {
    agent {
        docker {
            image 'node:20-alpine'
        }
    }

    environment {
        APP_NAME = 'my-vue-app'
        REGISTRY = 'registry.example.com'
    }

    stages {
        stage('安装依赖') {
            steps {
                sh 'npm config set registry https://registry.npmmirror.com'
                sh 'npm install'
            }
        }

        stage('代码检查') {
            steps {
                sh 'npm run lint'
            }
        }

        stage('单元测试') {
            steps {
                sh 'npm run test:unit'
            }
            post {
                always {
                    junit 'coverage/junit.xml'
                }
            }
        }

        stage('构建生产包') {
            steps {
                sh 'npm run build'
            }
        }

        stage('SonarQube 扫描') {
            environment {
                SONAR_TOKEN = credentials('sonar-token')
            }
            steps {
                sh '''
                    sonar-scanner \
                        -Dsonar.host.url=http://sonarqube:9000 \
                        -Dsonar.projectKey=${APP_NAME} \
                        -Dsonar.sources=src \
                        -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info
                '''
            }
        }

        stage('部署到 Nginx') {
            when {
                branch 'main'
            }
            steps {
                sh '''
                    rsync -avz --delete dist/ user@web-server:/var/www/html/
                '''
            }
        }
    }

    post {
        cleanup {
            sh 'npm cache clean --force'
        }
    }
}

九、实战场景三:Docker 多阶段构建

9.1 项目结构

my-golang-app/
├── cmd/
│   └── server/
│       └── main.go
├── Dockerfile
├── Jenkinsfile
└── docker-compose.yml

9.2 多阶段构建 Dockerfile

# 第一阶段:构建
FROM golang:1.21-alpine AS builder

WORKDIR /build

COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o app ./cmd/server

# 第二阶段:运行
FROM alpine:latest

RUN apk --no-cache add ca-certificates tzdata

WORKDIR /app

COPY --from=builder /build/app .
COPY --from=builder /build/configs ./configs

EXPOSE 8080

USER nobody
ENTRYPOINT ["./app"]
CMD ["--config", "./configs/config.yml"]

9.3 Jenkinsfile(使用 BuildKit)

pipeline {
    agent any

    environment {
        REGISTRY = 'harbor.example.com'
        IMAGE_NAME = 'my-golang-app'
    }

    stages {
        stage('构建镜像') {
            steps {
                script {
                    def imageTag = "${env.BUILD_NUMBER}"
                    def fullImage = "${REGISTRY}/${IMAGE_NAME}:${imageTag}"

                    sh """
                        export DOCKER_BUILDKIT=1
                        docker build -t ${fullImage} .
                        docker tag ${fullImage} ${REGISTRY}/${IMAGE_NAME}:latest
                    """
                }
            }
        }

        stage('安全扫描') {
            steps {
                sh '''
                    docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
                        aquasec/trivy image --severity HIGH,CRITICAL \
                        ${REGISTRY}/${IMAGE_NAME}:${BUILD_NUMBER}
                '''
            }
        }

        stage('推送镜像') {
            steps {
                script {
                    docker.withRegistry("https://${REGISTRY}", 'harbor-credential') {
                        docker.image("${REGISTRY}/${IMAGE_NAME}:${env.BUILD_NUMBER}").push()
                        docker.image("${REGISTRY}/${IMAGE_NAME}:latest").push()
                    }
                }
            }
        }
    }
}

十、实战场景四:Kubernetes 持续部署

10.1 Kubernetes 部署清单

k8s/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: my-app
        version: v1
    spec:
      containers:
        - name: my-app
          image: harbor.example.com/my-app:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
          resources:
            requests:
              memory: "256Mi"
              cpu: "100m"
            limits:
              memory: "512Mi"
              cpu: "500m"
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5

k8s/service.yaml

apiVersion: v1
kind: Service
metadata:
  name: my-app-svc
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
    - port: 80
      targetPort: 8080

k8s/ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: myapp.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-app-svc
                port:
                  number: 80

10.2 Jenkins K8s 部署流水线

pipeline {
    agent any

    environment {
        KUBECONFIG = credentials('kubeconfig-prod')
        REGISTRY = 'harbor.example.com'
        APP_NAME = 'my-app'
    }

    stages {
        stage('拉取代码') {
            steps {
                checkout scm
            }
        }

        stage('构建镜像') {
            steps {
                script {
                    def version = "${env.BUILD_NUMBER}"
                    def image = "${REGISTRY}/${APP_NAME}:${version}"

                    sh """
                        docker build -t ${image} .
                        docker push ${image}
                    """
                }
            }
        }

        stage('更新 K8s 镜像') {
            steps {
                script {
                    def version = "${env.BUILD_NUMBER}"
                    def image = "${REGISTRY}/${APP_NAME}:${version}"

                    sh """
                        kubectl set image deployment/${APP_NAME} ${APP_NAME}=${image} -n production
                        kubectl rollout status deployment/${APP_NAME} -n production
                        kubectl rollout history deployment/${APP_NAME} -n production
                    """
                }
            }
        }

        stage('健康检查') {
            steps {
                sh '''
                    sleep 10
                    kubectl exec -n production deployment/${APP_NAME} -- wget -qO- http://localhost:8080/health
                '''
            }
        }
    }

    post {
        success {
            echo '✅ 部署成功!'
        }
        failure {
            echo '❌ 部署失败,执行回滚!'
            sh '''
                kubectl rollout undo deployment/${APP_NAME} -n production
            '''
        }
    }
}

十一、凭据管理

11.1 添加凭据类型

进入 Dashboard → Manage Jenkins → Credentials → System → Global credentials

凭据类型用途
用户名 + 密码Git 仓库、Docker Registry
SSH 用户名 + 私钥Git SSH 拉取、SSH 部署
Secret 文件kubeconfig、证书文件
Secret 文本API Token、密钥字符串
证书TLS 证书

11.2 在 Pipeline 中使用凭据

pipeline {
    agent any

    stages {
        stage('Git 拉取') {
            steps {
                git credentialsId: 'git-ssh-key',  // SSH 私钥凭据
                     url: 'git@github.com:org/repo.git'
            }
        }

        stage('推送镜像') {
            steps {
                script {
                    docker.withRegistry('https://harbor.example.com', 'harbor-credential') {
                        docker.image('my-app').push()
                    }
                }
            }
        }

        stage('K8s 部署') {
            steps {
                withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
                    sh 'kubectl apply -f k8s/'
                }
            }
        }

        stage('SonarQube') {
            environment {
                SONAR_TOKEN = credentials('sonar-token-secret')
            }
            steps {
                sh 'sonar-scanner -Dsonar.token=$SONAR_TOKEN'
            }
        }
    }
}

十二、Blue Ocean 可视化流水线

Blue Ocean 是 Jenkins 原生的可视化流水线编辑器,适合不熟悉代码的同学。

12.1 安装 Blue Ocean

Dashboard → Manage Jenkins → Manage Plugins → Available

搜索并安装 Blue Ocean 插件。

12.2 访问 Blue Ocean

安装后,点击顶部菜单 Open Blue Ocean

┌─────────────────────────────────────────────────────────────────┐
│  Blue Ocean                                                     │
│                                                                  │
│  Activity  Pipeline   Favorites   Settings                      │
│  ────────────────────────────────────────────────────────────    │
│                                                                  │
│  Run in Personal Folder                                         │
│  ─────────────────────────────────────────────────────────────  │
│                                                                  │
│  ● my-springboot-app  #42  Success   2m ago                    │
│  ● my-springboot-app  #41  Success   5m ago                    │
│  ● my-springboot-app  #40  Failed    12m ago                   │
│  ○ my-vue-app         #88  Running   正在执行                   │
│                                                                  │
│  流水线执行可视化(节点+阶段+步骤 树状图)                          │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

十三、常见问题排错

❌ 问题 1:Jenkins 启动失败,端口被占用

# 排查
sudo ss -tlnp | grep 8080

# 解决方案:杀死占用进程或修改 Jenkins 端口
sudo vi /etc/sysconfig/jenkins
# 修改 JENKINS_PORT="8081"

sudo systemctl restart jenkins

❌ 问题 2:插件安装失败(网络原因)

# 检查外网连接
curl -I https://updates.jenkins.io

# 如果在内网环境,配置国内镜像
# Dashboard → Manage Jenkins → Plugin Manager → Advanced
# Update Site URL 改为: https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

# 重启 Jenkins
sudo systemctl restart jenkins

❌ 问题 3:Git 拉取失败(Permission denied)

# 排查 1:检查 SSH 密钥
ssh -T git@github.com

# 排查 2:检查凭据
# Dashboard → Manage Jenkins → Credentials
# 确认 Git SSH 凭据已正确配置

# 排查 3:检查 Known Hosts
ssh-keyscan github.com >> ~/.ssh/known_hosts

❌ 问题 4:Docker 构建失败(BuildKit 问题)

# 解决方案 1:关闭 BuildKit
export DOCKER_BUILDKIT=0
docker build ...

# 解决方案 2:在 Pipeline 中显式关闭
sh 'export DOCKER_BUILDKIT=0 && docker build ...'

# 解决方案 3:修改 daemon.json
sudo vi /etc/docker/daemon.json
# 添加 "features": {"buildkit": false}
sudo systemctl restart docker

❌ 问题 5:K8s 部署失败(ImagePullBackOff)

# 排查 1:确认镜像存在
docker images | grep my-app

# 排查 2:检查 K8s secret
kubectl get secret -n production
kubectl describe secret <secret-name> -n production

# 排查 3:重新创建 docker registry secret
kubectl create secret docker-registry harbor-credential \
    --docker-server=harbor.example.com \
    --docker-username=admin \
    --docker-password=Harbor12345 \
    -n production

# 排查 4:手动拉取测试
docker pull harbor.example.com/my-app:latest

❌ 问题 6:Pipeline 卡在 Waiting for executor

# 排查 1:检查节点是否在线
# Dashboard → Manage Jenkins → Nodes

# 排查 2:检查并发数限制
# Dashboard → Manage Jenkins → System
# "最大并发构建数" 设置过高可能导致资源耗尽

# 排查 3:增加 Agent 节点

❌ 问题 7:邮件通知发送失败

# 排查 1:测试 SMTP 连接
telnet smtp.exmail.qq.com 465

# 排查 2:检查 Jenkins 系统日志
# Dashboard → Manage Jenkins → System Log

# 排查 3:确认发件人邮箱与 Jenkins 配置一致

❌ 问题 8:流水线脚本语法报错

// 错误示例:使用了 Groovy 关键字作为变量名
def stage = "build"  // ❌ stage 是关键字

// 正确写法
def stageName = "build"  // ✅

// 使用 Declarative Validator 检查
// https://jenkins.io/doc/book/pipeline/syntax/#declarative-steps

十四、安全加固建议

14.1 启用 HTTPS

# 使用 Let's Encrypt 免费证书
sudo yum install -y certbot python3-certbot-nginx

# 获取证书
sudo certbot --nginx -d jenkins.example.com

# 修改 Jenkins 启动参数
sudo vi /etc/sysconfig/jenkins
# JENKINS_HTTPS_PORT=443
# JENKINS_HTTPS_KEYSTORE=/etc/letsencrypt/live/jenkins.example.com/keystore.jks
# JENKINS_HTTPS_KEYSTORE_PASSWORD=yourpassword

14.2 禁止用户注册

进入 Dashboard → Manage Jenkins → Security

☑ 允许用户注册:  ❌ 取消勾选
安全矩阵:         配置 admin 权限

14.3 流水线安全

// 在 Jenkinsfile 中禁止不安全的功能
pipeline {
    options {
        // 禁止使用 script{} 块(Scripted Pipeline)
        disableBuiltinIngestPipeline()
    }
}

14.4 定期备份

# 创建备份脚本
vi /opt/backup-jenkins.sh
#!/bin/bash
BACKUP_DIR=/opt/jenkins-backup
JENKINS_HOME=/var/lib/jenkins

mkdir -p $BACKUP_DIR/$(date +%Y%m%d)

# 备份配置
tar -czf $BACKUP_DIR/$(date +%Y%m%d)/jenkins-config.tar.gz $JENKINS_HOME/*.xml
tar -czf $BACKUP_DIR/$(date +%Y%m%d)/jenkins-plugins.tar.gz $JENKINS_HOME/plugins
tar -czf $BACKUP_DIR/$(date +%Y%m%d)/jenkins-users.tar.gz $JENKINS_HOME/users

# 保留 30 天
find $BACKUP_DIR -type d -mtime +30 -exec rm -rf {} \;

echo "备份完成: $(date)"
# 添加定时任务
crontab -e
# 每天凌晨 3 点备份
0 3 * * * /opt/backup-jenkins.sh >> /var/log/jenkins-backup.log 2>&1

十五、总结

部署完成检查清单

✅ Jenkins 安装成功(:8080 可访问)
✅ 插件安装完成(Git / Pipeline / Docker / K8s)
✅ 邮件通知配置成功(测试邮件发送成功)
✅ 凭据配置完成(Git / Harbor / K8s)
✅ 角色权限配置完成(admin / developer / viewer)
✅ Agent 节点配置完成(如需分布式构建)
✅ 第一个流水线运行成功
✅ 钉钉/邮件告警通知正常

进阶学习路径

阶段学习内容
入门基础流水线语法、参数化构建、邮件通知
进阶Blue Ocean、分布式构建、权限管理
熟练K8s 部署、SonarQube 集成、Helm Chart
精通Jenkins X / Tekton、GitOps、多集群管理

附录:快速命令速查

# Jenkins 服务管理
sudo systemctl start jenkins
sudo systemctl stop jenkins
sudo systemctl restart jenkins
sudo systemctl status jenkins

# 重置管理员密码
sudo cat /var/lib/jenkins/secrets/initialAdminPassword

# 手动安装插件
sudo cp plugin.hpi /var/lib/jenkins/plugins/
sudo chown jenkins:jenkins /var/lib/jenkins/plugins/*.hpi

# 查看构建日志
tail -f /var/log/jenkins/jenkins.log

# Groovy 脚本控制台(重置密码等)
# http://jenkins:8080/script

# 重载配置(无需重启)
curl -X POST http://localhost:8080/reload
© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容