Linux-Manual

Jenkins 安装和配置

Jenkins 介绍

Docker 下安装 Jenkins

touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?

首次使用 Jenkins / Jenkins 插件推荐

Docker 的 Jenkins 与 Docker 结合使用


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.key

sudo yum install -y jenkins
/etc/init.d/jenkins
/etc/logrotate.d/jenkins
/etc/sysconfig/jenkins
/usr/lib/jenkins
/usr/lib/jenkins/jenkins.war
/usr/sbin/rcjenkins
/var/cache/jenkins
/var/lib/jenkins
/var/log/jenkins
/usr/lib/jenkins/:jenkins安装目录,war 包会放在这里。
/etc/sysconfig/jenkins:jenkins配置文件,“端口”,“JENKINS_HOME” 等都可以在这里配置。
/var/lib/jenkins/:默认的 JENKINS_HOME。
/var/log/jenkins/jenkins.log:jenkins 日志文件。
Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:

daacc724767640a29ddc99d159a80cf8

This may also be found at: /root/.jenkins/secrets/initialAdminPassword

忘记 admin 密码进行重置

<useSecurity>true</useSecurity>
<authorizationStrategy class="hudson.security.FullControlOnceLoggedInAuthorizationStrategy">
  <denyAnonymousReadAccess>true</denyAnonymousReadAccess>
</authorizationStrategy>
<securityRealm class="hudson.security.HudsonPrivateSecurityRealm">
  <disableSignup>true</disableSignup>
  <enableCaptcha>false</enableCaptcha>
</securityRealm>

pipeline 语法

内置的参数

BUILD_NUMBER = ${env.BUILD_NUMBER}"
BUILD_ID = ${env.BUILD_ID}"
BUILD_DISPLAY_NAME = ${env.BUILD_DISPLAY_NAME}"
JOB_NAME = ${env.JOB_NAME}"
JOB_BASE_NAME = ${env.JOB_BASE_NAME}"
WORKSPACE = ${env.WORKSPACE}"
JENKINS_HOME = ${env.JENKINS_HOME}"
JENKINS_URL = ${env.JENKINS_URL}"
BUILD_URL = ${env.BUILD_URL}"
JOB_URL = ${env.JOB_URL}"
BUILD_NUMBER = 21
BUILD_ID = 21
BUILD_DISPLAY_NAME = #21
JOB_NAME = react
JOB_BASE_NAME = react
WORKSPACE = /root/.jenkins/workspace/react
JENKINS_HOME = /root/.jenkins
JENKINS_URL = http://192.168.0.105:18080/
BUILD_URL = http://192.168.0.105:18080/job/react/21/
JOB_URL = http://192.168.0.105:18080/job/react/

构建时指定参数

pipeline {
  agent any

  parameters {
    string(name: 'assignVersionValue', defaultValue: '1.1.3', description: '构建之前请先指定版本号')
  }
  
  tools {
    jdk 'JDK8'
    maven 'MAVEN3'
  }

  options {
    timestamps()
    disableConcurrentBuilds()
    buildDiscarder(logRotator(
      numToKeepStr: '20',
      daysToKeepStr: '30',
    ))
  }


  environment {
    gitUrl = "https://gitee.com/youmeek/springboot-jenkins-demo.git"
    branchName = "master"
    giteeCredentialsId = "Gitee"
    projectWorkSpacePath = "${env.WORKSPACE}"
  }
  
  
  stages {
    
    stage('Check Env') {
    
      /*当指定的参数版本号等于空字符的时候进入 steps。这里的 when 对 当前 stage 有效,对其他 stage 无效*/
      when {
        environment name: 'assignVersionValue', value: ''
      }
    
      /*结束整个任务。如果不想结束整个任务,就不要用:exit 1*/
      steps {
        sh "exit 1"
      }
    }
    
    stage('Pre Env') {
    
      steps {
        echo "======================================项目名称 = ${env.JOB_NAME}"
        echo "======================================项目 URL = ${gitUrl}"
        echo "======================================项目分支 = ${branchName}"
        echo "======================================当前编译版本号 = ${env.BUILD_NUMBER}"
        echo "======================================项目空间文件夹路径 = ${projectWorkSpacePath}"
        echo "======================================构建时自己指定的版本号值 = ${params.assignVersionValue}"
      }
    }
        
  }
}

定时构建

pipeline {
  agent any
  
  /*采用 linux cron 语法即可*/
  triggers {
    cron('*/1 * * * *')
  }
  
  tools {
    jdk 'JDK8'
    maven 'MAVEN3'
  }

  options {
    timestamps()
    disableConcurrentBuilds()
    buildDiscarder(logRotator(
      numToKeepStr: '20',
      daysToKeepStr: '30',
    ))
  }


  environment {
    gitUrl = "https://gitee.com/youmeek/springboot-jenkins-demo.git"
    branchName = "master"
    giteeCredentialsId = "Gitee"
    projectWorkSpacePath = "${env.WORKSPACE}"
  }
  
  
  stages {
    
    stage('Pre Env') {
      steps {
         echo "======================================项目名称 = ${env.JOB_NAME}"
         echo "======================================项目 URL = ${gitUrl}"
         echo "======================================项目分支 = ${branchName}"
         echo "======================================当前编译版本号 = ${env.BUILD_NUMBER}"
         echo "======================================项目空间文件夹路径 = ${projectWorkSpacePath}"
      }
    }
    
  }
}

同时构建其他 Job

stage('运行其他任务') {
  steps {
      build job: '任务名称'
  }
}

Jenkins 前端 React 项目构建

简单的 pipeline 写法(开源项目)

pipeline {
  agent any

  options {
    timestamps()
    disableConcurrentBuilds()
    buildDiscarder(logRotator(
      numToKeepStr: '20',
      daysToKeepStr: '30',
    ))
  }

  /*=======================================常修改变量-start=======================================*/

  environment {
    gitUrl = "https://github.com/satan31415/heh_umi_template.git"
    branchName = "master"
    projectBuildPath = "${env.WORKSPACE}/dist"
    nginxHtmlRoot = "/usr/share/nginx/react"
  }
  
  /*=======================================常修改变量-end=======================================*/
  
  stages {
    
    stage('Pre Env') {
      steps {
         echo "======================================项目名称 = ${env.JOB_NAME}"
         echo "======================================项目 URL = ${gitUrl}"
         echo "======================================项目分支 = ${branchName}"
         echo "======================================当前编译版本号 = ${env.BUILD_NUMBER}"
         echo "======================================项目 Build 文件夹路径 = ${projectBuildPath}"
         echo "======================================项目 Nginx 的 ROOT 路径 = ${nginxHtmlRoot}"
      }
    }
    
    stage('Git Clone'){
      steps {
          git branch: "${branchName}", url: "${gitUrl}"
      }
    }

    stage('NPM Install') {
      steps {
        sh "npm install"
      }
    }

    stage('NPM Build') {
      steps {
        sh "npm run build"
      }
    }

    stage('Nginx Deploy') {
      steps {
        sh "rm -rf ${nginxHtmlRoot}/"
        sh "cp -r ${projectBuildPath}/ ${nginxHtmlRoot}/"
      }
    }


  }
}

简单的 pipeline 写法(闭源项目 – 码云为例)

pipeline {
  agent any

  options {
    timestamps()
    disableConcurrentBuilds()
    buildDiscarder(logRotator(
      numToKeepStr: '20',
      daysToKeepStr: '30',
    ))
  }

  /*=======================================常修改变量-start=======================================*/

  environment {
    gitUrl = "https://gitee.com/youmeek/react-demo.git"
    branchName = "master"
    giteeCredentialsId = "上面全局凭据填写的 ID"
    projectBuildPath = "${env.WORKSPACE}/dist"
    nginxHtmlRoot = "/usr/share/nginx/react"
  }
  
  /*=======================================常修改变量-end=======================================*/
  
  stages {
    
    stage('Pre Env') {
      steps {
         echo "======================================项目名称 = ${env.JOB_NAME}"
         echo "======================================项目 URL = ${gitUrl}"
         echo "======================================项目分支 = ${branchName}"
         echo "======================================当前编译版本号 = ${env.BUILD_NUMBER}"
         echo "======================================项目 Build 文件夹路径 = ${projectBuildPath}"
         echo "======================================项目 Nginx 的 ROOT 路径 = ${nginxHtmlRoot}"
      }
    }
    
    stage('Git Clone'){
      steps {
          git branch: "${branchName}",
          credentialsId: "${giteeCredentialsId}",
          url: "${gitUrl}"
      }
    }

    stage('NPM Install') {
      steps {
        sh "npm install"
      }
    }

    stage('NPM Build') {
      steps {
        sh "npm run build"
      }
    }

    stage('Nginx Deploy') {
      steps {
        sh "rm -rf ${nginxHtmlRoot}/"
        sh "cp -r ${projectBuildPath}/ ${nginxHtmlRoot}/"
      }
    }


  }
}

Jenkins 后端 Spring Boot 项目构建

安装 Maven

配置工具

简单的 pipeline 写法(Jar 方式运行)(闭源项目 – 码云为例)

用 supervisord 做进程控制
配置 Jenkins
pipeline {
  agent any

  /*=======================================工具环境修改-start=======================================*/
  tools {
    jdk 'JDK8'
    maven 'MAVEN3'
  }
  /*=======================================工具环境修改-end=======================================*/

  options {
    timestamps()
    disableConcurrentBuilds()
    buildDiscarder(logRotator(
      numToKeepStr: '20',
      daysToKeepStr: '30',
    ))
  }

  /*=======================================常修改变量-start=======================================*/

  environment {
    gitUrl = "https://gitee.com/youmeek/springboot-jenkins-demo.git"
    branchName = "master"
    giteeCredentialsId = "Gitee"
    projectWorkSpacePath = "${env.WORKSPACE}"
    projectBuildTargetPath = "${env.WORKSPACE}/target"
    projectJarNewName = "${env.JOB_NAME}.jar"
    supervisorConfigFileFullPath = "/etc/supervisor/conf.d/${env.JOB_NAME}.conf"
    supervisorLogPath = "/var/log/supervisor"

  }
  
  /*=======================================常修改变量-end=======================================*/
  
  stages {
    
    stage('Pre Env') {
      steps {
         echo "======================================项目名称 = ${env.JOB_NAME}"
         echo "======================================项目 URL = ${gitUrl}"
         echo "======================================项目分支 = ${branchName}"
         echo "======================================当前编译版本号 = ${env.BUILD_NUMBER}"
         echo "======================================项目空间文件夹路径 = ${projectWorkSpacePath}"
         echo "======================================项目 build 后 jar 路径 = ${projectBuildTargetPath}"
         echo "======================================项目 jar 新名称 = ${projectJarNewName}"
         echo "======================================supervisor 配置文件路径 = ${supervisorConfigFileFullPath}"
         echo "======================================supervisor 存放 log 路径 = ${supervisorLogPath}"
      }
    }
    
    stage('Git Clone'){
      steps {
          git branch: "${branchName}",
          credentialsId: "${giteeCredentialsId}",
          url: "${gitUrl}"
      }
    }

    stage('Maven Clean') {
      steps {
        sh "mvn clean"
      }
    }

    stage('Maven Package') {
      steps {
        sh "mvn package -DskipTests"
      }
    }

    stage('Spring Boot Run') {
      steps {

sh """
mv ${projectBuildTargetPath}/*.jar ${projectBuildTargetPath}/${projectJarNewName}

if [ ! -f ${supervisorConfigFileFullPath} ]; then

touch ${supervisorConfigFileFullPath}
    
cat << EOF >> ${supervisorConfigFileFullPath}
[program:${env.JOB_NAME}]
command=java -jar ${projectBuildTargetPath}/${projectJarNewName}
stdout_logfile=${supervisorLogPath}/${env.JOB_NAME}.log
stderr_logfile=${supervisorLogPath}/${env.JOB_NAME}-err.log
user=root
autostart=true
autorestart=false
startsecs=5
priority=1
stopasgroup=true
killasgroup=true
EOF

/usr/bin/supervisorctl update
fi

/usr/bin/supervisorctl restart ${env.JOB_NAME}
"""

      }
    }

  }
}

简单的 pipeline 写法(Docker 方式运行)(闭源项目 – 码云为例)

FROM java:8
VOLUME /tmp

ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

ADD ./target/buildApp.jar /app.jar

RUN bash -c 'touch /app.jar'

EXPOSE 8081

ENTRYPOINT ["java", "-jar", "-Xms512M", "-Xmx512M" , "-XX:MetaspaceSize=128M", "-XX:MaxMetaspaceSize=256M" ,"/app.jar"]
pipeline {
  agent any

  /*=======================================工具环境修改-start=======================================*/
  tools {
    jdk 'JDK8'
    maven 'MAVEN3'
  }
  /*=======================================工具环境修改-end=======================================*/

  options {
    timestamps()
    disableConcurrentBuilds()
    buildDiscarder(logRotator(
      numToKeepStr: '20',
      daysToKeepStr: '30',
    ))
  }

  /*=======================================常修改变量-start=======================================*/

  environment {
    gitUrl = "https://gitee.com/youmeek/springboot-jenkins-demo.git"
    branchName = "master"
    giteeCredentialsId = "Gitee"
    projectWorkSpacePath = "${env.WORKSPACE}"
    projectBuildTargetPath = "${env.WORKSPACE}/target"
    projectJarNewName = "buildApp.jar"


    dockerImageName = "docker.youmeek.com/demo/${env.JOB_NAME}:${env.BUILD_NUMBER}"
    dockerContainerName = "${env.JOB_NAME}"
    inHostPort = "8082"
    inDockerAndJavaPort = "8081"
    inHostLogPath = "/data/docker/logs/${dockerContainerName}/${env.BUILD_NUMBER}"
    inDockerLogPath = "/data/logs"
    dockerRunParam = "--name=${dockerContainerName} --hostname=${dockerContainerName} -v /etc/hosts:/etc/hosts -v ${inHostLogPath}:${inDockerLogPath} --restart=always  -p ${inHostPort}:${inDockerAndJavaPort}"
  }
  
  /*=======================================常修改变量-end=======================================*/
  
  stages {
    
    stage('Pre Env') {
      steps {
         echo "======================================项目名称 = ${env.JOB_NAME}"
         echo "======================================项目 URL = ${gitUrl}"
         echo "======================================项目分支 = ${branchName}"
         echo "======================================当前编译版本号 = ${env.BUILD_NUMBER}"
         echo "======================================项目空间文件夹路径 = ${projectWorkSpacePath}"
         echo "======================================项目 build 后 jar 路径 = ${projectBuildTargetPath}"
         echo "======================================项目 jar 新名称 = ${projectJarNewName}"
         echo "======================================Docker 镜像名称 = ${dockerImageName}"
         echo "======================================Docker 容器名称 = ${dockerContainerName}"
      }
    }
    
    stage('Git Clone'){
      steps {
          git branch: "${branchName}",
          credentialsId: "${giteeCredentialsId}",
          url: "${gitUrl}"
      }
    }

    stage('Maven Clean') {
      steps {
        sh "mvn clean"
      }
    }

    stage('Maven Package') {
      steps {
        sh "mvn package -DskipTests"
      }
    }

    stage('构建 Docker 镜像') {
      steps {
        sh """
            mv ${projectBuildTargetPath}/*.jar ${projectBuildTargetPath}/${projectJarNewName}
            
            cd ${projectWorkSpacePath}
            
            docker build -t ${dockerImageName} ./
        """
      }
    }

    stage('运行 Docker 镜像') {
      steps {
        sh """
            docker stop ${dockerContainerName} | true

            docker rm -f ${dockerContainerName} | true
            
            docker run -d  ${dockerRunParam} ${dockerImageName}
        """
      }
    }
    
    

    
    

  }
}

简单的 pipeline 写法(Docker + Harbor 方式运行)(闭源项目 – 码云为例)

pipeline {
  agent any

  /*=======================================工具环境修改-start=======================================*/
  tools {
    jdk 'JDK8'
    maven 'MAVEN3'
  }
  /*=======================================工具环境修改-end=======================================*/

  options {
    timestamps()
    disableConcurrentBuilds()
    buildDiscarder(logRotator(
      numToKeepStr: '20',
      daysToKeepStr: '30',
    ))
  }

  /*=======================================常修改变量-start=======================================*/

  environment {
    gitUrl = "https://gitee.com/youmeek/springboot-jenkins-demo.git"
    branchName = "master"
    giteeCredentialsId = "Gitee"
    projectWorkSpacePath = "${env.WORKSPACE}"
    projectBuildTargetPath = "${env.WORKSPACE}/target"
    projectJarNewName = "buildApp.jar"

    projectDockerDaemon = "tcp://192.168.1.12:2376"
    harborUrl = "192.168.1.13"
    harborProjectName = "demo"
    dockerImageName = "${harborUrl}/${harborProjectName}/${env.JOB_NAME}:${env.BUILD_NUMBER}"
    dockerContainerName = "${env.JOB_NAME}"
    inHostPort = "8082"
    inDockerAndJavaPort = "8081"
    inHostLogPath = "/data/docker/logs/${dockerContainerName}/${env.BUILD_NUMBER}"
    inDockerLogPath = "/data/logs"
    dockerRunParam = "--name=${dockerContainerName} --hostname=${dockerContainerName} -v /etc/hosts:/etc/hosts -v ${inHostLogPath}:${inDockerLogPath} --restart=always  -p ${inHostPort}:${inDockerAndJavaPort}"
  }
  
  /*=======================================常修改变量-end=======================================*/
  
  stages {
    
    stage('Pre Env') {
      steps {
         echo "======================================项目名称 = ${env.JOB_NAME}"
         echo "======================================项目 URL = ${gitUrl}"
         echo "======================================项目分支 = ${branchName}"
         echo "======================================当前编译版本号 = ${env.BUILD_NUMBER}"
         echo "======================================项目空间文件夹路径 = ${projectWorkSpacePath}"
         echo "======================================项目 build 后 jar 路径 = ${projectBuildTargetPath}"
         echo "======================================项目 jar 新名称 = ${projectJarNewName}"
         echo "======================================Docker 镜像名称 = ${dockerImageName}"
         echo "======================================Docker 容器名称 = ${dockerContainerName}"
         echo "======================================harbor 地址 = ${harborUrl}"
         echo "======================================harbor 项目名称 = ${harborProjectName}"
         echo "======================================项目在宿主机的端口 = ${inHostPort}"
         echo "======================================项目在 Docker 容器中的端口 = ${inDockerAndJavaPort}"
         echo "======================================项目在宿主机的 log 路径 = ${inHostLogPath}"
         echo "======================================项目在 docker 容器的 log 路径 = ${inDockerLogPath}"
         echo "======================================项目运行的 Docker remote ip 信息 = ${projectDockerDaemon}"
         echo "======================================项目运行的参数 = ${dockerRunParam}"
      }
    }
    
    stage('Git Clone'){
      steps {
          git branch: "${branchName}",
          credentialsId: "${giteeCredentialsId}",
          url: "${gitUrl}"
      }
    }

    stage('Maven Clean') {
      steps {
        sh "mvn clean"
      }
    }

    stage('Maven Package') {
      steps {
        sh "mvn package -DskipTests"
      }
    }

    stage('构建 Docker 镜像') {
      steps {
        sh """
            mv ${projectBuildTargetPath}/*.jar ${projectBuildTargetPath}/${projectJarNewName}
            
            cd ${projectWorkSpacePath}
            
            docker build -t ${dockerImageName} ./
        """
      }
    }

    stage('Push Docker 镜像') {
      options {
        timeout(time: 5, unit: 'MINUTES') 
      }
      steps {
        sh """
          docker push ${dockerImageName}
          docker rmi ${dockerImageName}
        """
      }
    }

    stage('运行远程 Docker 镜像') {
      options {
        timeout(time: 5, unit: 'MINUTES') 
      }
      steps {
        sh """
            docker -H ${projectDockerDaemon} pull ${dockerImageName}
            
            docker -H ${projectDockerDaemon} stop ${dockerContainerName} | true
            
            docker -H ${projectDockerDaemon} rm -f ${dockerContainerName} | true
            
            docker -H ${projectDockerDaemon} run -d  ${dockerRunParam} ${dockerImageName}
        """
      }
    }
    
    

    
    

  }
}

多节点 master 与 slave


资料