Jenkins

一、Jenkins安装

基础环境准备

#关闭防火墙和SELinux
#设置语言环境,防止后期Jenkins汉化出问题
[root@jenkins ~]# localectl set-locale LANG=en_US.UTF-8
# 准备java环境
https://www.jenkins.io/doc/book/platform-information/support-policy-java/
apt update && apt -y install openjdk-21-jdk
#新版jenkins_2.479.1后要求安装JDK-17版
[root@ubuntu2404 ~]#apt update && apt -y install openjdk-17-jdk
[root@rocky8 ~]#yum -y install java-17-openjdk

#要求安装JDK-11版的基础环境配置
[root@ubuntu2004 ~]#apt update && apt -y install openjdk-11-jdk
[root@rocky8 ~]#yum -y install java-11-openjdk

#旧版安装JDK-8版
[root@ubuntu1804 ~]#apt update
[root@ubuntu1804 ~]#apt -y install openjdk-8-jdk

#或者安装oracle的jdk
[root@ubuntu1804 /usr/local/src]# tar xvf jdk-8u192-linux-x64.tar.gz
[root@ubuntu1804 /usr/local/src]# ln -sv /usr/local/src/jdk1.8.0_192/
/usr/local/jdk
[root@ubuntu1804 /usr/local/src]# ln -sv /usr/local/jdk/bin/java /usr/bin/ #java
命令软连接
[root@ubuntu1804 /usr/local/src]# vim /etc/profile
export JAVA_HOME=/usr/local/jdk
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
[root@ubuntu1804 /usr/local/src]# source /etc/profile
[root@ubuntu1804 /usr/local/src]# java -version

包安装Jenkins

# 一、Ubuntu系统
apt -y install openjdk-11-jdk
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -
apt-get update
apt-get install jenkins
apt list jenkins -a
deb 包下载地址国内镜像站点
https://mirrors.aliyun.com/jenkins/debian-stable/
https://mirror.tuna.tsinghua.edu.cn/jenkins/debian-stable/

# 二进制包安装jenkins
apt update && apt -y install openjdk-17-jdk
wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/debian-stable/jenkins_2.492.1_all.deb
dpkg -i jenkins_2.492.1_all.deb
# ubuntu安装后默认会自启动
systemctl status jenkins.service
cat /var/lib/jenkins/secrets/initialAdminPassword

# 二、CentOS系统
wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
yum install jenkins

# rpm包国内镜像下载链接
https://mirrors.aliyun.com/jenkins/redhat-stable/
https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/

#CentOS二进制包安装jenkins
yum install java
wget https://mirrors.aliyun.com/jenkins/redhat-stable/jenkins-2.289.2-1.1.noarch.rpm
yum -y install jenkins-2.289.2-1.1.noarch.rpm
rpm -ql jenkins

systemctl start jenkins.service
grep -A2 password /var/log/jenkins/jenkins.log
#查看第一次的登录密码
cat /var/lib/jenkins/secrets/initialAdminPassword
#默认配置
[root@centos8 ~]#grep -v "#" /etc/sysconfig/jenkins | grep -v "^$"

基于war包安装Jenkins

下载链接
官网: https://get.jenkins.io/war-stable/
国内镜像代理站: https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/
安装

1、直接java -jar启动
wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/latest/jenkins.war
apt update && apt install openjdk-11-jdk -y
java -jar jenkins.war --httpPort=9090
2、基于tomcat启动
apt update && apt install openjdk-21-jre tomcat10
cp jenkins.war /var/lib/tomcat10/webapps/
vim /lib/systemd/system/tomcat10.service
# Security #修改为root启动,否则提示Caused by: java.nio.file.FileSystemException:
/var/lib/tomcat: Read-only file system
#User=tomcat
#Group=tomcat
systemctl daemon-reload && systemctl restart tomcat10

基于Docker安装Jenkins

# 方式1
docker run -d --name jenkins -p 8080:8080 -p 50000:50000 --restart=always -v jenkins_home:/var/jenkins_home  jenkins/jenkins:2.401.1-lts-jdk11
# 方式2
docker run -u root \
     -d -p 8080:8080 \
     -p 50000:50000 \
     -v jenkins-data:/var/jenkins_home \
     -v /etc/localtime:/etc/localtime:ro \
     -v /var/run/docker.sock:/var/run/docekr.sock \
     --restart=always \
     jenkinsci/blueocean
#镜像jenkinsci/jenkins 是没有blueocean插件的,需要自己装
#镜像jenkinsci/blueocean:内置bluecocean插件
#/var/run/docker.sock 表示Docker守护程序通过其监听的基于Unix的套接字。该映射允许jenkinsci/blueocean容器与Docker守护进程通信,如果jenkinsci/blueocean容器需要实例化其他Docker容器,则该守护进程是必需的。如果运行声明式管道,其语法包含agent部分用docker;例如,agent{ docker {... }}此选项是必需的。

基于Kubernetes安装Jenkins

#Helm安装
https://www.jenkins.io/doc/book/installing/kubernetes/#install-jenkins-with-helm-v3
#YAML文件安装 
https://www.jenkins.io/doc/book/installing/kubernetes/#install-jenkins-with-yaml-files
#Operator安装
https://www.jenkins.io/doc/book/installing/kubernetes/#install-jenkins-with-jenkins-operator

示例基于Storage class 的部署yaml

cat jenkins-deployment-service-pvc-sc-rbac.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: jenkins
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-pvc
  namespace: jenkins
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: sc-nfs #需要提前准备名称为 sc-nfs的StorageClass
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-master
  namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: jenkins-master
rules:
  - apiGroups: ["extensions", "apps"]
    resources: ["deployments"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["create","delete","get","list","patch","update","watch"]
  - apiGroups: [""]
    resources: ["pods/exec"]
    verbs: ["create","delete","get","list","patch","update","watch"]
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get","list","watch"]
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins-master
roleRef:
  kind: ClusterRole
  name: jenkins-master
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: jenkins-master
  namespace: jenkins
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins
  namespace: jenkins
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      serviceAccountName: jenkins-master
      containers:
        - name: jenkins
          image: jenkins/jenkins:lts
          ports:
          - containerPort: 8080
            name: web
            protocol: TCP
          - containerPort: 50000
            name: agent
            protocol: TCP
          volumeMounts:
          - name: jenkins-volume
            mountPath: /var/jenkins_home
      volumes:
      - name: jenkins-volume
        persistentVolumeClaim:
          claimName: jenkins-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: jenkins
  namespace: jenkins
spec:
  type: LoadBalancer #需要提前准备名OpenELB服务
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  - name: agent
    port: 50000
    targetPort: 50000
  selector:
    app: jenkins

二、Jenkins插件管理

官网插件地址: https://plugins.jenkins.io/

# 插件安装目录
ls /var/lib/jenkins/plugins/
# 加速插件安装速度
# 方案一:更改 Jenkins 的镜像源为国内镜像站
# 注意:此修改只是临时性,服务重启后会自动还原
sed -i.bak 's#updates.jenkins.io/download#mirror.tuna.tsinghua.edu.cn/jenkins#g' /var/lib/jenkins/updates/default.json
sed -i 's#www.google.com#www.baidu.com#g' /var/lib/jenkins/updates/default.json
#注意:如果是tomcat运行war包方式需要下面路径
sed -i.bak
's#https://updates.jenkins.io/download#https://mirror.tuna.tsinghua.edu.cn/jenkins#g' /root/.jenkins/updates/default.json
# 将升级站点URL替换成下面国内镜像地址
Jenkins页面-->Manage Jeninks-->Plugins
将升级站点URL替换成下面国内镜像地址,提交后再次安装插件即可
#查看镜像源
http://mirrors.jenkins-ci.org/status.html
#默认镜像源
https://updates.jenkins.io/update-center.json
#国内镜像源
https://mirror.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
https://mirrors.aliyun.com/jenkins/updates/update-center.json
# 重启服务

# 方案二:加速插件更新和安装
# 参考项目
https://github.com/lework/jenkins-update-center

#测试各镜像站点的速度:
~# curl -sSL https://cdn.jsdelivr.net/gh/lework/jenkins-update-center/speed-test.sh | bash
#关闭数字证书签名认证:
~# sed -i 's#$JENKINS_JAVA_OPTIONS#$JENKINS_JAVA_OPTIONS -Dhudson.model.DownloadService.noSignatureCheck=true#g' /etc/init.d/jenkins
~# systemctl daemon-reload
#替换引用的更新配置文件:
~# sed -i 's#https://updates.jenkins.io/update-center.json#https://cdn.jsdelivr.net/gh/lework/jenkins-update-center@master/updates/ustc/update-center.json#gi' /var/lib/jenkins/hudson.model.UpdateCenter.xml
~# rm -f /var/lib/jenkins/updates/default.json
~# systemctl restart jenkins

# 方案三:Jenkins 官网或镜像网站下载想要的插件文件,再导入到 Jenkins 中
# 国内镜像站点插件下载地址:
http://updates.jenkins-ci.org/download/plugins/
https://updates.jenkins.io/download/plugins/
https://mirrors.aliyun.com/jenkins/plugins/
https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/

# 方案四: 离线插件包复制至插件安装目录
可以将其它主机的已安装好的插件打包后,再将之导入到安装插件目录即可
[root@jenkins ~]#systemctl stop jenkins
[root@jenkins ~]#tar jenkins_plugins.tar.gz -C /var/lib/jenkins/plugins/
[root@jenkins ~]#chown -R jenkins.jenkins /var/lib/jenkins/plugins/
[root@jenkins ~]#systemctl start jenkins

三、JenkinsCICD相关

一、Jenkins内置环境变量

# Jenkins内置的常用的环境变量
JENKINS_HOME:Jenkins的家目录
JENKINS_URL:Jenkins服务的URL
JOB_NAME:当前作业的名称
BUILD_NUMBER:构建号,递增的整数值;打包时,经常用作制品名称的一部分
BRANCH_NAME:在多分支pipeline中,需要根据不同的分支施加不同的操作时较为常用
BUILD_URL:当前构建页面的URL,常用于邮件通知中
GIT_BRANCH:基于git拉取的源码进行构建时使用该变量

注意:Jenkins的环境变量和root用户看到环境变量不完全相同
Jenkins的管理页面查看到内置变量
http://jenkins-server:8080/env-vars.html/
http://jenkins.wang.org:8080/systemInfo

二、Pipeline

Pipeline基本结构

pipeline
    流水线的最外层结构,代表整条pipeline,包含着pipeline的完整逻辑;是声明式流水线语法的关健特征
node和agent
    用于定义任务在哪里执行
    每个node都是一个 Jenkins 节点,可以是 Jenkins master也可以是 Jenkins agent,node是执行step的具体服务器。node 代码块也是脚本式pipeline语法的关健特性,声明式pipeline使用 agent 关健字
stages
    用于包含所有stage的定义
stage
    属于stages的子语句块
    指定 stage 的名称, 用于定义每个阶段 stage 的主要任务
    一个pipeline可以划分为若干个stage,每个stage都是一个完整的操作,比如: clone代码、代码编译、代码测试和代码部署,阶段是一个逻辑分组,可以跨多个node执行。
steps
    属于stage的子语句块
    每个阶段stage中定义完成该阶段功能所需要经历的一系列步骤
    步骤 steps 是jenkins pipeline最基本的操作单元,从在服务器创建目录到构建容器镜像,由各类Jenkins 插件提供实现,例如: sh “make”
    能够把这些步骤steps 同该stage中的其它定义(如环境的定义,Post 等)分隔开
post
    用在stage 代码块(和steps 同级)或整个pipeline执行完成后的附加步骤,此指令非必须项

脚本式流水线语法

node { 
    stage('Source') {
        //git clone
    }
    stage('Build') {
        //mvn
    }
    stage('Test') {
        //mvn test
    }
    stage('Deploy') {
        // scp
        // java -jar
    }
}
#特点:最外层是node {}

声明式流水线语法
声明式流水线是在”Pipeline plugin”的2.5版本添加到 Jenkins 流水线的 ,它在流水线子系统之上提供了一种更简单,更常见的语法。
所有有效的声明式流水线必须包含在一个 pipeline 块中, 比如:

pipeline {
 agent any
 stages {
   stage('Build') {
     steps {
       //
     }
   }
   stage('Test') {
     steps {
       //
     }
   }
   stage('Deploy') {
     steps {
       //
     }
   }
 }
}

Jenkins内置语法帮助,不会写的流水线可参考帮助文档

http://jenkins-server:8080/job/<job-name>/pipeline-syntax/
#注意:需要安装pipeline插件并且是pipeline风格的任务

Jenkinsfile
可以将pipeline的语句写到代码仓库中的 Jenkinsfile 文件,这样更加方便维护和版本控制
注意:使用Jenkinsfile后无需再执行git clone代码这一步骤,直接执行后面的mvn test即可
Pipeline部署Docker服务示例

pipeline {
    agent any
    environment {
        codeRepo="git@gitlab.wang.org:devops/spring-boot-helloworld.git"
        credential="gitlab-wang-sshkey"
        harborServer='harbor.wang.org'
        projectName='spring-boot-helloworld'
        imageUrl="${harborServer}/example/${projectName}"
        imageTag="${BUILD_ID}"
    }
    stages {
        stage('Source') {
            steps {
                git branch: 'main', credentialsId: "${credential}", url: "${codeRepo}"
            }
        }
        stage('Test') {
           steps {
                //注意:不要修改hello()函数,否则会导致下面失败
                sh 'mvn test'
            }
        }        
        stage('Build') {
            steps {
                //sh 'mvn -B -DskipTests clean package'
                 sh 'mvn clean package -Dmaven.test.skip=true'
            }
        }

        stage('Build Docker Image') {
            steps {
                sh 'docker build . -t "${imageUrl}:${imageTag}"'
            }           
        }
        stage('Push Docker Image') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'harbor-user-password', \
                        usernameVariable: 'harborUserName',passwordVariable: 'harborPassword')]) {
                    sh "echo ${harborPassword} | docker login -u ${env.harborUserName} --password-stdin ${harborServer}"
                    //sh "docker login -u ${env.harborUserName} -p ${harborPassword} ${harborServer}"
                    sh "docker push ${imageUrl}:${imageTag}"
                    echo "username=${env.harborUserName}"
                    echo "password=${harborPassword}"
                }
            }
        }
        stage('Run Docker ') {
            steps {
                sh 'ssh root@10.0.0.101 "docker rm -f ${projectName} ; docker run --name ${projectName} --restart always -p 80:8888 -d ${imageUrl}:${imageTag}"'
                sh 'ssh root@10.0.0.102 "docker rm -f ${projectName} ; docker run --name ${projectName} --restart always -p 80:8888 -d ${imageUrl}:${imageTag}"'
                //sh "docker -H 10.0.0.101 rm -f ${projectName} ; docker -H 10.0.0.101 run --name ${projectName} --restart always -p 80:8888 -d ${imageUrl}:${imageTag}"
                //sh "docker -H 10.0.0.102 rm -f ${projectName} ; docker -H 10.0.0.102 run --name ${projectName} --restart always -p 80:8888 -d ${imageUrl}:${imageTag}"

            }   
        }          
    }
}

pipeline选项参数示例

pipeline {
    agent any
    parameters {
        string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')

        text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some information about the person')

        booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value')

        choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')

        password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password')
    }
    stages {
        stage('Example') {
            steps {
                echo "Hello ${params.PERSON}"

                echo "Biography: ${params.BIOGRAPHY}"

                echo "Toggle: ${params.TOGGLE}"

                echo "Choice: ${params.CHOICE}"

                echo "Password: ${params.PASSWORD}"
            }
        }
    }
}

综合示例:

pipeline {
    agent any
    environment {
        codeRepo="http://gitlab.wang.org/devops/spring-boot-helloworld.git"
        credential="gitlab-wang-password"
        harborServer='harbor.wang.org'
        projectName='spring-boot-helloworld'
        imageUrl="${harborServer}/example/${projectName}"
        imageTag="${BUILD_ID}"
    }
    triggers {
        gitlab(triggerOnPush: true,
            acceptMergeRequestOnSuccess: true,
            triggerOnMergeRequest: true,
            branchFilterType: 'All',
            addVoteOnMergeRequest: true,
            secretToken: '62dad2cd1d9ae62686ada8dc4cdOaabb')
    }    
    stages {
        stage('Source') {
            steps {
                git branch: 'main', credentialsId: "${credential}", url: "${codeRepo}"
            }
        }
        stage('Build') {
            steps {
                sh 'mvn -B -DskipTests clean package'
            }
        }
        stage('Test') {
           steps {
                  //注意:不要修改hello()函数,否则会导致下面失败
                sh 'mvn test'
            }
        }
        stage('Build Docker Image') {
            steps {
                sh 'docker build . -t "${imageUrl}:${imageTag}"'
            }           
        }
        stage('Push Docker Image') {
            agent any 
            steps {
                withCredentials([usernamePassword(credentialsId: 'harbor-user-password', \
                        passwordVariable: 'harborPassword', usernameVariable: 'harborUserName')]) {
                    sh "echo ${harborPassword} | docker login -u ${env.harborUserName} --password-stdin ${harborServer}"
                    //sh "docker login -u ${env.harborUserName} -p ${harborPassword} ${harborServer}"
                    sh "docker push ${imageUrl}:${imageTag}"
                    echo "username=${env.harborUserName}"
                    echo "password=${harborPassword}"
                }
            }   
        }
        stage('Run Docker ') {
            steps {
                sh 'ssh root@10.0.0.101 "docker rm -f ${projectName} ; docker run --name ${projectName} -p 80:8888 -d ${imageUrl}:${imageTag}"'
                sh 'ssh root@10.0.0.102 "docker rm -f ${projectName} ; docker run --name ${projectName} -p 80:8888 -d ${imageUrl}:${imageTag}"'

            }   
        }          
    }
     post {
         failure {
            mail to: 'root@wangxiaochun.com',
            subject: "Status of pipeline: ${currentBuild.fullDisplayName}",
            body: "${env.BUILD_URL} has result ${currentBuild.result}"
        }
        success{
            qyWechatNotification failNotify: true, webhookUrl: 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=29d3caa7-340e-410d-8599-56e031234567'
        } 
    } 
}
作者:于浩  创建时间:2026-06-11 17:00
最后编辑:于浩  更新时间:2026-07-12 22:32