1.拉取镜像

docker pull jenkins/jenkins:2.387.3

2.创建容器

cd /docker
mkdir jenkins
cd jenkins
mkdir home
chmod -R +777 /docker/jenkins/*

docker run -d \
-p 332:8080 \
-p 333:50000 \
-v /docker/jenkins/home:/var/jenkins_home \
--name jenkins \
--restart always \
jenkins/jenkins:2.387.3

# 如果是使用 https 命令如下   
docker run -d \
-p 332:8443 \
-p 333:50000 \
-v /docker/jenkins/home:/var/jenkins_home \
--name jenkins \
 --network yyy \
 --restart always \
-e JENKINS_OPTS="--httpPort=-1 --httpsPort=8443 --httpsKeyStore=/var/jenkins_home/itzaj.com.jks --httpsKeyStorePassword=y4mrm7pss1q4a"  \
jenkins/jenkins:2.387.3

3.配置镜像

#vim /docker/jenkins/home/hudson.model.UpdateCenter.xml
# 将URL 改为 https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
#或者直接执行下面命令
sed -i 's#https://updates.jenkins.io/update-center.json#https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json#g' /docker/jenkins/home/hudson.model.UpdateCenter.xml

4.查看密码 创建账号

docker exec -it jenkins bash
#打开浏览器  ip:332
#cat 复制浏览器那个文件地址
 # 然后创建账号 
 # 插件不全选

5.安装插件

#安装的插件有  
Git  |
Localization: Chinese (Simplified)  |
Maven Integration  |
Credentials Binding|
pipeline|
Email Extension Template|
SonarQube Scanner|
Publish Over SSH|
Extended Choice Parameter|

6.下载maven java1.8 并配置等

6.1 java 8 下载

弹出的连接 复制下载地址

https://download.oracle.com/otn/java/jdk/8u371-b11/ce59cff5c23f4e2eaf4e778a117d4c5b/jdk-8u371-linux-x64.tar.gz?AuthParam=1683785201_703a0950fb60ee8acd8120965a706f4c

他带authparam 所以尽快操作 如果报错就重新搞个

创建一个普通工程 让jdk下载一下

先去添加凭据

回到项目

下面的分支名一定要对 当年卡我半天 gitee 主分支可能是main 换成/*main就ok

如果这里用的是gitee 使用邮箱 要去官网配置登录邮箱 提交邮箱 别用手机号或者名,如果还爆红 先不管( gitee我也爆红 不影响后面拉代码)

安装完成了

可别直接复制 去docker容器看看吧

具体去 docker容器看看安装目录

配置完成后 去删掉下载连接

具体去 docker容器看看安装目录

Java 就ok啦

可以看到我们的仓库内容已经拉取啦

6.2Maven

maven就简单点了

保存即可 我们去创建一个 JDK8 的maven项目

一样的设置 注意分支名

这是我的结构 下面的 需要设置pom位置

一个是 pom位置需要设置 另一个是 命令需要设置 别写mvn 只写 clean package

自动在下载maven了

maven 安装完成了 但是 项目报错 先配置maven

去看看路径

/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/maven3.9.0

上图一样的配置

后来发现

这里 Root POM 不能写 / 应该直接写 jenkins/pom.xml

看到在下载了 这就是好啦!

配置了 jenkins/pom.xml 就oK啦

6.3配置邮件:

7.流水线参考

Pipeline 支持两种语法:Declarative(声明式)和 Scripted Pipeline(脚本式)语法

简单声明式Pipeline:

pipeline {
    agent any
    stages {
        stage('拉取代码') {
            steps {
                echo '拉取代码'
            }
        }
        stage('编译构建') {
            steps {
                echo '编译构建'
            }
        }
        stage('项目部署') {
            steps {
                echo '项目部署'
            }
        }
    }
}
```bash
node {
    def mvnHome
    stage('拉取代码') { // for display purposes
        echo '===========拉取代码开始==========='
        checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: '9185eb11-2ba2-4a0e-a26c-86680858351a', url: 'https://gitee.com/yyystudio/jenkins-demo-1.git']])
         echo '===========拉取代码完成==========='
    }
    stage('编译构建') {
        echo '===========编译构建开始==========='
        sh """
        cd ./jenkins
        pwd

        mvn clean package
        """
        echo '===========编译构建结束==========='


    }
    stage('项目部署') {
        echo '项目部署---------模拟部署-----------OK!'

    }
}

Pipeline Script from SCM

刚才我们都是直接在JenkinsUI界面编写Pipeline代码,这样不方便脚本维护,建议把Pipeline脚本放

在项目中(一起进行版本控制) Jenkinsfile

Jenkins项目构建细节(1)-常用的构建触发器

Jenkins内置4种构建触发器:

1.触发远程构建

http://192.168.1.4:332/job/test06_%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E6%94%BE%E5%85%A5%E4%BB%93%E5%BA%93/build?token=6666

2.其他工程构建后触发(Build after other projects are build)

3.定时构建(Build periodically)

30分钟构建一次:H代表形参 H/30 * * * * 10:02 10:32

2个小时构建一次: H H/2 * * *

每天的8点,12点,22点,一天构建3次: (多个时间点中间用逗号隔开) 0 8,12,22 * * *

每天中午12点定时构建一次 H 12 * * *

每天下午18点定时构建一次 H 18 * * *

在每个小时的前半个小时内的每10分钟 H(0-29)/10 * * * *

每两小时一次,每个工作日上午9点到下午5(也许是上午10:38,下午12:38,下午2:38,下午

4:38) H H(9-16)/2 * * 1-5

4.轮询SCM(Poll SCM)

轮询SCM,是指定时扫描本地代码仓库的代码是否有变更,如果代码有变更就触发项目构建

5.git操作后

先去配置里面设置

6.Jenkins的参数化构建

7.邮件配置
    post {
        always {
            emailext(
            subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -
            ${BUILD_STATUS}!',
            body: '${FILE,path="emailTemplate.html"}',
            to: '1900540070@qq.com'
            )
        }
    }

加上这一块

8.代码审查

dockerfile

def git_auth = "f3e0058a-9d8f-41c9-bae8-1e70f8c5b895"  // 认证ID
def harbor_auth = "519f6543-7c49-47cc-af26-88703ae0e93a"  // 认证ID
def tag = "latest"  //构建版本的名称
def git_url = "https://www.itzaj.com:325/wangchuan/ddns.git"  // 项目地址
def harbor_url = "www.itzaj.com:338" //Harbor私服地址
def harbor_project_name = "yyy"  //Harbor的项目名称
def project_name = "network-ddns" // 项目名称(目录)
def export_port = "80"  // 项目端口


node {

    try {
        stage('拉取代码') {
            checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
        }


         stage('SonarQube代码审查') {
          def  scannerHome = tool 'SonarQubeScanner' //引入工具Dashboard => Manage Jenkins =>   Global Tool Configuration 下的 SonarQube Scanner 的NAME
                     withSonarQubeEnv('sonarqube9.9') {  // 引入环境   Dashboard=>    Manage Jenkins  =>Configure System      SonarQube servers 中的NAME
                     sh """
                     cd ${project_name}
                     ${scannerHome}/bin/sonar-scanner
                     """
                     }
        }


         stage('发送邮件') {
                emailext( subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -    ${BUILD_STATUS}!', body: '${FILE,path="email.html"}', to: '1900540070@qq.com' )
            }


    } catch (Exception e) {
     emailext( subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -    ${BUILD_STATUS}!', body: '${FILE,path="email.html"}', to: '1900540070@qq.com' )
    }



}
9.自动构建镜像

由于无法在docker里构建 所以我们在宿主机部署一个 构建镜像的java程序

现在修改 dockerfile 文件

def git_auth = "f3e0058a-9d8f-41c9-bae8-1e70f8c5b895"  // 认证ID
def harbor_auth = "519f6543-7c49-47cc-af26-88703ae0e93a"  // 认证ID
def tag = "latest"  //构建版本的名称
def git_url = "https://www.itzaj.com:325/wangchuan/ddns.git"  // 项目地址
def harbor_url = "www.itzaj.com:338" //Harbor私服地址
def harbor_project_name = "yyy"  //Harbor的项目名称
def project_name = "network-ddns" // 项目名称(目录)
def export_port = "80"  // 项目端口


node {

    try {
        stage('拉取代码') {
            checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
        }


         stage('SonarQube代码审查') {
          def  scannerHome = tool 'SonarQubeScanner' //引入工具Dashboard => Manage Jenkins =>   Global Tool Configuration 下的 SonarQube Scanner 的NAME
                     withSonarQubeEnv('sonarqube9.9') {  // 引入环境   Dashboard=>    Manage Jenkins  =>Configure System      SonarQube servers 中的NAME
                     sh """
                     cd ${project_name}
                     ${scannerHome}/bin/sonar-scanner
                     """
                     }
        }

         stage('编译构建镜像') {
           def imageName = "${project_name}:${BUILD_NUMBER}"             //定义镜像名称
            //sh "mvn -f  公共项目名  clean install"              //编译,安装公共工程
            sh "mvn -f ${project_name}  clean package"              //清理 打包
            def curlExitCode = sh(returnStatus: true, script: """
                    #清理 打包
                    mvn -f ${project_name}  clean package
                    # 发送请求 构建镜像
                    curl --location --request POST 'http://1.1.1.200:341/acceptJar/upload' \
                    --form 'imageName="${project_name}"' \
                    --form 'file=@"./${project_name}/target/app.jar"' \
                    --form 'imageVersion="${BUILD_NUMBER}"' \
                    --form 'port="${export_port}"'
                """)
               if (curlExitCode == 0) {
                     println "请求成功,返回值为$curlExitCode"

                 } else {
                     println "请求失败,返回值为: $curlExitCode"
                     error("请求失败,返回值为: $curlExitCode")
                 }
         }

         stage('发送邮件') {
                emailext( subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -    ${BUILD_STATUS}!', body: '${FILE,path="email.html"}', to: '1900540070@qq.com' )
            }


    } catch (Exception e) {
     emailext( subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -    ${BUILD_STATUS}!', body: '${FILE,path="email.html"}', to: '1900540070@qq.com' )
    }



}
10.远程发布

首先我们进入jenkins 容器 root 进入! docker exec -it -uroot jenkins bash

# 生成 key
ssh-keygen
# 拷贝到 我们需要部署的服务器
ssh-copy-id www.itzaj.com   #需要输入密码 就输入密码 

去添加服务器

这里我们是容器部署的jenkins 我们直接 cat /root/.ssh/id_rsa

然后 一点不差的复制到下面的key 上面的 path 就不填了 注意 一点不差 包括 ——–xxx———-的开始 和结束

编辑 脚本文件

测试用的

def git_auth = "f3e0058a-9d8f-41c9-bae8-1e70f8c5b895"  // 认证ID
def harbor_auth = "519f6543-7c49-47cc-af26-88703ae0e93a"  // 认证ID
def tag = "latest"  //构建版本的名称
def git_url = "https://www.itzaj.com:325/wangchuan/ddns.git"  // 项目地址
def harbor_url = "www.itzaj.com:338" //Harbor私服地址
def harbor_project_name = "yyy"  //Harbor的项目名称
def project_name = "network-ddns" // 项目名称(目录)
def export_port = "80"  // 项目端口


node {

    try {
   //     stage('拉取代码') {
   //         checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
   //     }


   //      stage('SonarQube代码审查') {
   //       def  scannerHome = tool 'SonarQubeScanner' //引入工具Dashboard => Manage Jenkins =>   Global Tool Configuration 下的 SonarQube Scanner 的NAME
   //                  withSonarQubeEnv('sonarqube9.9') {  // 引入环境   Dashboard=>    Manage Jenkins  =>Configure System      SonarQube servers 中的NAME
   //                  sh """
   //                  cd ${project_name}
   //                  ${scannerHome}/bin/sonar-scanner
   //                  """
   //                  }
   //     }

   //      stage('编译构建镜像') {
   //        def imageName = "${project_name}:${BUILD_NUMBER}"             //定义镜像名称
   //         //sh "mvn -f  公共项目名  clean install"              //编译,安装公共工程
   //         sh "mvn -f ${project_name}  clean package"              //清理 打包
   //         def curlExitCode = sh(returnStatus: true, script: """
   //                 #清理 打包
   //                 mvn -f ${project_name}  clean package
   //                 # 发送请求 构建镜像
   //                 curl --location --request POST 'http://1.1.1.200:341/acceptJar/upload' \
   //                 --form 'imageName="${project_name}"' \
   //                 --form 'file=@"./${project_name}/target/app.jar"' \
   //                 --form 'imageVersion="${BUILD_NUMBER}"' \
   //                 --form 'port="${export_port}"'
   //             """)
   //            if (curlExitCode == 0) {
   //                  println "请求成功,返回值为$curlExitCode"

   //              } else {
   //                  println "请求失败,返回值为: $curlExitCode"
   //                  error("请求失败,返回值为: $curlExitCode")
   //              }
   //      }


   //

   //      stage('发送邮件') {
   //             emailext( subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -    ${BUILD_STATUS}!', body: '${FILE,path="email.html"}', to: '1900540070@qq.com' )
   //         }


         stage('部署') {
              sshPublisher(publishers: [sshPublisherDesc(configName: 's1',  transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand:"/volumes1/jenkinsSH/shell1.sh $project_name", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }


    } catch (Exception e) {
     emailext( subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -    ${BUILD_STATUS}!', body: '${FILE,path="email.html"}', to: '1900540070@qq.com' )
    }



}

shell1.sh

imageName=$1
echo "$imageName" > /root/a.txt

运行后 发现 我们/root 目录下生成了 一个a.txt 里面是 镜像名

实际我们需要真正的运行的脚本

def git_auth = "f3e0058a-9d8f-41c9-bae8-1e70f8c5b895"  // 认证ID
def harbor_auth = "519f6543-7c49-47cc-af26-88703ae0e93a"  // 认证ID
def tag = "latest"  //构建版本的名称
def git_url = "https://www.itzaj.com:325/wangchuan/ddns.git"  // 项目地址
def harbor_url = "www.itzaj.com:338" //Harbor私服地址
def harbor_project_name = "yyy"  //Harbor的项目名称
def project_name = "network-ddns" // 项目名称(目录)
def export_port = "80"  // 项目端口


node {

    try {
        stage('拉取代码') {
            checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
        }


         stage('SonarQube代码审查') {
          def  scannerHome = tool 'SonarQubeScanner' //引入工具Dashboard => Manage Jenkins =>   Global Tool Configuration 下的 SonarQube Scanner 的NAME
                     withSonarQubeEnv('sonarqube9.9') {  // 引入环境   Dashboard=>    Manage Jenkins  =>Configure System      SonarQube servers 中的NAME
                     sh """
                     cd ${project_name}
                     ${scannerHome}/bin/sonar-scanner
                     """
                     }
        }

         stage('编译构建镜像') {
           def imageName = "${project_name}:${BUILD_NUMBER}"             //定义镜像名称
            //sh "mvn -f  公共项目名  clean install"              //编译,安装公共工程
            sh "mvn -f ${project_name}  clean package"              //清理 打包
            def curlExitCode = sh(returnStatus: true, script: """
                    #清理 打包
                    mvn -f ${project_name}  clean package
                    # 发送请求 构建镜像
                    curl --location --request POST 'http://1.1.1.200:341/acceptJar/upload' \
                    --form 'imageName="${project_name}"' \
                    --form 'file=@"./${project_name}/target/app.jar"' \
                    --form 'imageVersion="${BUILD_NUMBER}"' \
                    --form 'port="${export_port}"'
                """)
               if (curlExitCode == 0) {
                     println "请求成功,返回值为$curlExitCode"

                 } else {
                     println "请求失败,返回值为: $curlExitCode"
                     error("请求失败,返回值为: $curlExitCode")
                 }
         }


         stage('部署') {
         echo "$harbor_url $harbor_project_name $project_name $BUILD_NUMBER $port $docker_name"
              sshPublisher(publishers: [sshPublisherDesc(configName: 's1',  transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand:"/volumes1/jenkinsSH/shell2.sh $harbor_url $harbor_project_name $project_name $BUILD_NUMBER $port $docker_name", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }


         stage('发送邮件') {
                emailext( subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -    ${BUILD_STATUS}!', body: '${FILE,path="email.html"}', to: '1900540070@qq.com' )
            }




    } catch (Exception e) {
     emailext( subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -    ${BUILD_STATUS}!', body: '${FILE,path="email.html"}', to: '1900540070@qq.com' )
    }



}
```bash
#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
docker_name=$6
imageName=$harbor_url/$harbor_project_name/$project_name:$tag
echo "$imageName"
#查询容器是否存在,存在则删除
docker ps -a | awk -v name="$project_name" '$2 ~ name {print $1}' | xargs docker stop
docker ps -a | awk -v name="$project_name" '$2 ~ name {print $1}' | xargs docker rm
#查询镜像是否存在,存在则删除
imageId=`docker images | grep -w $project_name | awk '{print $3}'`
if [ "$imageId" != "" ] ; then
#删除镜像
docker rmi -f $imageId
echo "成功删除镜像$imageId"
fi
# 登录Harbor私服
docker login -u root -p DFgo1234.... $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
echo "docker run -di  --name="${docker_name}""_"$tag -p $port:$port $imageName"
docker run -di  --name="${docker_name}""_"$tag -p $port:$port $imageName
echo "容器启动成功"
11.多选框 一次性部署到多台服务器

Extended Choice Parameter 使用:

我们添加一个 Extended Choice Parameter 类型的

这里可以写成 调用接口返回 后期再加吧

如果出现 警告 , 就 进去都点允许就ok啦

这样脚本我们要改为循环

参考:

def git_auth = "f3e0058a-9d8f-41c9-bae8-1e70f8c5b895"  // 认证ID
def harbor_auth = "519f6543-7c49-47cc-af26-88703ae0e93a"  // 认证ID
def tag = "latest"  //构建版本的名称
def git_url = "https://www.itzaj.com:325/wangchuan/ddns.git"  // 项目地址
def harbor_url = "www.itzaj.com:338" //Harbor私服地址
def harbor_project_name = "yyy"  //Harbor的项目名称
def project_name = "network-ddns" // 项目名称(目录)
def export_port = "80"  // 项目端口
def serverArray = "${server}".split(',')

node {

    try {
        stage('拉取代码') {
            checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
        }


         stage('SonarQube代码审查') {
          def  scannerHome = tool 'SonarQubeScanner' //引入工具Dashboard => Manage Jenkins =>   Global Tool Configuration 下的 SonarQube Scanner 的NAME
                     withSonarQubeEnv('sonarqube9.9') {  // 引入环境   Dashboard=>    Manage Jenkins  =>Configure System      SonarQube servers 中的NAME
                     sh """
                     cd ${project_name}
                     ${scannerHome}/bin/sonar-scanner
                     """
                     }
        }

         stage('编译构建镜像') {
           def imageName = "${project_name}:${BUILD_NUMBER}"             //定义镜像名称
            //sh "mvn -f  公共项目名  clean install"              //编译,安装公共工程
            sh "mvn -f ${project_name}  clean package"              //清理 打包
            def curlExitCode = sh(returnStatus: true, script: """
                    #清理 打包
                    mvn -f ${project_name}  clean package
                    # 发送请求 构建镜像
                    curl --location --request POST 'http://1.1.1.200:341/acceptJar/upload' \
                    --form 'imageName="${project_name}"' \
                    --form 'file=@"./${project_name}/target/app.jar"' \
                    --form 'imageVersion="${BUILD_NUMBER}"' \
                    --form 'port="${export_port}"'
                """)
               if (curlExitCode == 0) {
                     println "请求成功,返回值为$curlExitCode"

                 } else {
                     println "请求失败,返回值为: $curlExitCode"
                     error("请求失败,返回值为: $curlExitCode")
                 }
         }


         stage('部署') {
         echo "serverArray"
         echo "${server}"
         for(int i=0;i<serverArray.size();i++){
         def currentServer = serverArray[i]
                 echo "${currentServer}"
                 echo "$harbor_url $harbor_project_name $project_name $BUILD_NUMBER $port $docker_name"
                      sshPublisher(publishers: [sshPublisherDesc(configName: "${currentServer}",  transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand:"/volumes1/jenkinsSH/shell2.sh $harbor_url $harbor_project_name $project_name $BUILD_NUMBER $port $docker_name", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                 }
            }


         stage('发送邮件') {
                emailext( subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -    ${BUILD_STATUS}!', body: '${FILE,path="email.html"}', to: '1900540070@qq.com' )
            }




    } catch (Exception e) {
     emailext( subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} -    ${BUILD_STATUS}!', body: '${FILE,path="email.html"}', to: '1900540070@qq.com' )
    }



}