企业级流水线的两种部署场景

目前,在企业中部署应用一般就是普通虚拟机部署和k8s容器化部署两种方式。这篇文章主要用来介绍这两种场景下分别怎么部署。

普通虚拟机部署

普通虚拟机部署通常有两种方式,分别是:

  • 自由风格方式部署
  • pipeline流水线方式部署
  • maven方式部署

安装 Jenkins 插件

Publish Over SSHPublish Over SSH

Jenkins->Manage Jenkins->Manage Plugins,点击 Available

Publish Over SSH
Publish Over SSH

创建流水线

pipeline{
    agent any
    stages{
        stage("拉取代码"){
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: '68a87abf-6af7-4e60-94dd-cf45c280c247', url: 'git@gitlab.abck8s.com:xiaoyangaijishu/html.git']]])
            }
        }
        stage("SonarQube代码审查"){
            steps {
                script {
                    scannerHome = tool 'sonarqube-scanner'
                }
                withSonarQubeEnv('sonarqube8.9.8') {
                    sh "${scannerHome}/bin/sonar-scanner"
                }
            }
        }
        stage("判断代码扫描状态"){
            steps {
                script {
                    timeout(5) {
                        qg = waitForQualityGate()
                        if (qg.status != 'OK') {
                              error "扫描失败,状态错误: ${qg.status}"
                        } else {
                            echo "扫描成功"
                        }
                    }
                 }
            }
        }
    }
}
pipeline{
    agent any
    stages{
        stage("拉取代码"){
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: '68a87abf-6af7-4e60-94dd-cf45c280c247', url: 'git@gitlab.abck8s.com:xiaoyangaijishu/html.git']]])
            }
        }
        stage("SonarQube代码审查"){
            steps {
                script {
                    scannerHome = tool 'sonarqube-scanner'
                }
                withSonarQubeEnv('sonarqube8.9.8') {
                    sh "${scannerHome}/bin/sonar-scanner"
                }
            }
        }
        stage("判断代码扫描状态"){
            steps {
                script {
                    timeout(5) {
                        qg = waitForQualityGate()
                        if (qg.status != 'OK') {
                              error "扫描失败,状态错误: ${qg.status}"
                        } else {
                            echo "扫描成功"
                        }
                    }
                 }
            }
        }
        stage("部署代码"){
            steps {
                sshPublisher(
                    publishers: [
                        sshPublisherDesc(
                            configName: 'web01', 
                            transfers: [
                                sshTransfer(
                                    cleanRemote: false, 
                                    excludes: '', 
                                    execCommand: '''#!/bin/bash''', 
                                    execTimeout: 120000, 
                                    flatten: false, 
                                    makeEmptyDirs: false, 
                                    noDefaultExcludes: false, 
                                    patternSeparator: '[, ]+', 
                                    remoteDirectory: '', 
                                    remoteDirectorySDF: false, 
                                    removePrefix: '', 
                                    sourceFiles: '**/**'
                                )
                            ], 
                            usePromotionTimestamp: false, 
                            useWorkspaceInPromotion: false, 
                            verbose: false
                        ), 
                        sshPublisherDesc(
                            configName: 'web02', 
                            transfers: [
                                sshTransfer(
                                    cleanRemote: false, 
                                    excludes: '', 
                                    execCommand: '#!/bin/bash', 
                                    execTimeout: 120000, 
                                    flatten: false, 
                                    makeEmptyDirs: false, 
                                    noDefaultExcludes: false, 
                                    patternSeparator: '[, ]+', 
                                    remoteDirectory: '', 
                                    remoteDirectorySDF: false, 
                                    removePrefix: '', 
                                    sourceFiles: '**/**'
                                )
                            ], 
                            usePromotionTimestamp: false, 
                            useWorkspaceInPromotion: false, 
                            verbose: false
                        )
                    ]
                )
            }
        }
    }
}

部署成功。

部署结束发送邮件

post {
  always {
    emailext (
        body: """
        <!DOCTYPE html><html><head><meta charset="UTF-8"><title>${PROJECT_NAME}-第${BUILD_NUMBER}次构建日志</title></head><body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
      offset="0"><table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif"><tr>(本邮件由系统自动发出,无需回复!)<br/>各位好,以下是${PROJECT_NAME}项目构建信息<br/><td><font color="#CC0000">构建结果 - ${BUILD_STATUS}</font></td></tr><tr><td><br/><b><font color="#0B610B">构建信息 - ${BUILD_STATUS}</font></b><hr size="2" width="100%" align="center" /></td></tr><tr><td><ul><li>项目名称:${PROJECT_NAME}</li><li>构建编号:第${BUILD_NUMBER}次构建</li><li>构建版本:2021.1.0.0</li><li>触发原因:${CAUSE}</li><li>构建状态:${BUILD_STATUS}</li><li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li><li>构建地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li><li>工作目录:<a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li><li>项目地址:<a href="${PROJECT_URL}">${PROJECT_URL}</a></li><li><a href="http://1xx.1xx.3.xx:81xx/plateform-backend/report/interfaceReport/xxx/${BUILD_TIMESTAMP}/index.html" >查看测试报告</a></li></ul><h4><font color="#0B610B">测试结果</font></h4><hr size="2" width="100%" /><div><hr size="2" width="100%" />
$FAILED_TESTS<br/><h4><font color="#0B610B">变更记录</font></h4><hr size="2" width="100%" />变更明细:<a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a><br/></td></tr></table></body></html>
""",
        mimeType: 'text/html',
        subject: '自动化构建报告:$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!',
        to: 'chenyangqit@163.com'
    )
  }
}

K8S容器化部署

K8S容器化部署就是说将应用部署到容器中。

安装 k8s 插件

Jenkins 连接 K8S

最近我们构建和部署服务的方式与原来相比简直就是突飞猛进,像那种笨拙的、单一的、用于构建单体式应用程序的方式已经是过去式了。现在的应用为了提供更好的拓展性和可维护性,都会去拆解成各种相互依赖小、解耦性强的微服务,这些服务有各自的依赖和进度。这跟我们的Kubernetes不谋而合。

使用Jenkins链接K8S需要创建一些秘钥。

第一步:创建admin-csr.json

cat > admin-csr.json << EOF
{
    "CN":"admin",
    "key":{
        "algo":"rsa",
        "size":2048
    },
    "names":[
        {
            "C":"CN",
            "L":"BeiJing",
            "ST":"BeiJing",
            "O":"system:masters",
            "OU":"System"
        }
    ]
}
EOF

第二步:创建证书和私钥

cfssljson:https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64

cfssl:https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64

cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key --profile=kubernetes admin-csr.json | cfssljson -bare admin

第三步:配置证书

openssl pkcs12 -export -out ./jenkins-admin.pfx -inkey ./admin-key.pem -in ./admin.pem -passout pass:123456

第四步:将证书私钥填写至Jenkins

cat /etc/kubernetes/pki/ca.crt

第五步:上传证书并输入密码

Jenkins 连接 k8s

测试部署

使用 Jenkins 打包镜像部署到 k8s。

注意:配置清单中的变量居多,小心配置。

pipeline {
  agent {
    kubernetes {
      cloud "${KUBERNETES_NAME}"
      slaveConnectTimeout 1200
      yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
    - name: jnlp
      image: jenkins/inbound-agent:4.7-1-jdk11
      args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "volume-2"
          readOnly: false
    - name: docker
      image: docker:19.03.15-git
      imagePullPolicy: IfNotPresent
      tty: true
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "volume-2"
          readOnly: false
        - mountPath: "/var/run/docker.sock"
          name: "volume-docker"
          readOnly: false
        - mountPath: "/etc/hosts"
          name: "volume-hosts"
          readOnly: false
    - name: kubectl
      image: registry.cn-beijing.aliyuncs.com/citools/kubectl:1.17.4
      imagePullPolicy: IfNotPresent
      tty: true
      command:
        - "cat"
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "volume-2"
          readOnly: false
        - mountPath: "/var/run/docker.sock"
          name: "volume-docker"
          readOnly: false
        - mountPath: "/root/.kube"
          name: "kubeconfig"
          readOnly: false
        - mountPath: "/.kube"
          name: "kubeconfig"
          readOnly: false
    - name: maven
      image: maven:3.6.3-openjdk-8
      tty: true
      command:
        - "cat"
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "volume-2"
          readOnly: false
        - mountPath: "/root/.m2/repository"
          name: "volume-maven-repo"
          readOnly: false
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
    - name: sonarscanner
      image: emeraldsquad/sonar-scanner:2.2.0
      tty: true
      command:
        - "cat"
      volumeMounts:
        - mountPath: "/etc/localtime"
          name: "volume-2"
          readOnly: false
        - mountPath: "/root/.m2/repository"
          name: "volume-maven-repo"
          readOnly: false
        - mountPath: "/etc/hosts"
          name: "volume-hosts"
          readOnly: false
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
  volumes:
    - name: volume-maven-repo
      emptyDir: {}
    - name: volume-2
      hostPath:
        path: "/usr/share/zoneinfo/Asia/Shanghai"
    - name: kubeconfig
      secret:
        secretName: kubeconfig
        items:
          - key: config
            path: config
    - name: volume-docker
      hostPath:
        path: "/var/run/docker.sock"
    - name: volume-hosts
      hostPath:
        path: /etc/hosts

'''
    }
  }

  stages {


    stage('源代码管理') {
      parallel {
        stage('拉取代码') {
          steps {
                git(url: "${GIT_REPOSITORY_URL}", branch: "master", changelog: true, credentialsId: "${CREDENTIALS_ID}")
            }
        }

        stage('系统检查及初始化') {
          steps {
            sh """

            echo "Check Sysyem Env"

"""
          }
        }

      }
    }

    stage('代码处理') {
      steps {
        sh """

        git checkout $GIT_TAG

        """
      }
    }
      stage("SonarQube代码审查"){
          steps {
              container(name: 'sonarscanner') {
                script {
                    scannerHome = tool 'sonarqube-scanner'
                }
                withSonarQubeEnv('sonarqube8.9.8') {
                    sh "${scannerHome}/bin/sonar-scanner"
                }
            }
          }
      }
      stage("判断代码扫描状态"){
          steps {
              script {
                  timeout(5) {
                      qg = waitForQualityGate()
                      if (qg.status != 'OK') {
                          error "扫描失败,状态错误: ${qg.status}"
                      } else {
                          echo "扫描成功"
                      }
                  }
              }
          }
      }

    stage('编译及构建') {
      parallel {
        stage('初始化操作系统及kubernetes环境') {
          steps {
            script {
              CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
              CommitMessage = sh(returnStdout: true, script: "git log -1 --pretty=format:'%h : %an  %s'").trim()
              def curDate = sh(script: "date '+%Y%m%d-%H%M%S'", returnStdout: true).trim()
              TAG = curDate[0..14] + "-" + CommitID + "-master"
            }
          }
        }

      }
    }

    stage('构建镜像及检查kubernetes环境') {
      parallel {
        stage('构建镜像') {
          steps {
            withCredentials([usernamePassword(credentialsId: "${DOCKER_REPOSITORY_CREDENTIAL_ID}", passwordVariable: "Password", usernameVariable: "Username")]) {
              container(name: 'docker') {
                sh """
                  docker build -t ${HARBOR_HOST}/${NAMESPACE_NAME}/${REPOSITORY_NAME}:${TAG} .
                  docker login ${HARBOR_HOST} --username=${Username} --password=${Password}
                  docker push ${HARBOR_HOST}/${NAMESPACE_NAME}/${REPOSITORY_NAME}:${TAG}
                """
              }
            }
          }
        }

        stage('检查kubernetes环境') {
          steps {
              withCredentials([usernamePassword(credentialsId: "${DOCKER_REPOSITORY_CREDENTIAL_ID}", passwordVariable: "Password", usernameVariable: "Username")]) {
                container(name: 'kubectl') {
                sh """
                    kubectl get nodes --kubeconfig=/root/.kube/config
                    kubectl delete secret aliyun-registry-key -n ${K8S_NAMESPACE_NAME}
                    kubectl create secret docker-registry aliyun-registry-key -n ${K8S_NAMESPACE_NAME} --docker-server=${HARBOR_HOST} --docker-username=${Username} --docker-password=${Password} --kubeconfig=/root/.kube/config
    """
                }
              }
          }
        }

      }
    }

    stage('部署容器到kubernetes') {
      steps {
        container(name: 'kubectl') {
              sh """
               kubectl set image ${CONTROLLER_TYPE} -l ${CONTROLLER_LABEL} -n ${K8S_NAMESPACE_NAME} ${CONTAINER_NAME}=${HARBOR_HOST}/${NAMESPACE_NAME}/${REPOSITORY_NAME}:${TAG} --kubeconfig=/root/.kube/config
"""
        }
      }
    }
  }
    post {
  always {
    emailext (
        body: '测试邮件',
        mimeType: 'text/html',
        subject: '自动化构建报告',
        to: 'cxxxxit@163.com'
    )
  }
}
}

k8s 部署清单

apiVersion: apps/v1
kind: Deployment
metadata:
  name: python
  labels:
    app: python
spec:
  selector:
    matchLabels:
      app: python
  template:
    metadata:
      labels:
        app: python
    spec:
      containers:
        - name: python
          image: nginx
---
apiVersion: v1
kind: Service
metadata:
  name: python
  labels:
    app: python
spec:
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080
  selector:
    app: python
  type: NodePort

Jenkins部署Npm项目

linux虚拟机版

// 前端项目
    // 1、拉取代码
    // 2、切换分支
    // 3、扫描代码
    // 4、获取代码状态
    // 5、编译代码
    // 6、部署
    // 7、发送部署邮件

pipeline {

    agent any

    parameters {
      listGitBranches branchFilter: '.*', 
      credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930', 
      defaultValue: '', 
      listSize: '5', 
      name: 'GIT_TAG', 
      quickFilterEnabled: false, 
      remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/vue-tetris-master.git', 
      selectedValue: 'NONE', 
      sortMode: 'NONE', 
      tagFilter: '*', 
      type: 'PT_TAG'
    }


    stages {

        stage("拉取代码") {
            steps {
                checkout(
                    [
                        $class: 'GitSCM', 
                        branches: [[name: '*/master']], 
                        extensions: [], 
                        userRemoteConfigs: [[
                            credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
                            url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/vue-tetris-master.git'
                        ]]
                    ]
                )
            }
        }
        stage("切换分支") {
            steps {

                script {

                    sh """
                        git checkout $GIT_TAG
                    """
                }

            }
        }

        stage("代码漏洞扫描") {
            steps {
                // 指定需要使用的Tools
                script {
                    scannerTool = tool(
                        name: 'sonarqube-scanner', 
                        type: 'hudson.plugins.sonar.SonarRunnerInstallation'
                    )
                }

                // 使用Tool来进行代码扫描
                withSonarQubeEnv('sonarqube8.9.8') {
                    sh "${scannerTool}/bin/sonar-scanner"
                }
            }
        }

        stage("代码漏洞扫描状态判断") {
            steps {
                script {
                    timeout(1) {
                        qg = waitForQualityGate()
                        if (qg.status != 'OK') {
                          error "代码漏洞扫描失败,状态为: ${qg.status}"
                        } else {
                            echo "代码漏洞扫描通过"
                        }
                    }
                }
            }
        }

        stage("编译代码") {
            steps {
                script {

                    sh """
                        npm config set registry https://registry.npm.taobao.org
                        npm install
                        npm run build
                    """

                }
            }
        }
        stage("部署") {
            steps {

                sshPublisher(
                    publishers: [
                        sshPublisherDesc(
                            configName: 'web02', 
                            transfers: [
                                sshTransfer(
                                    cleanRemote: false, 
                                    excludes: '', 
                                    execCommand: '''#!/bin/bash
                                        mkdir vue-tetris
                                        mv dist vue-tetris''', 
                                    execTimeout: 120000,
                                    flatten: false, 
                                    makeEmptyDirs: false, 
                                    noDefaultExcludes: false, 
                                    patternSeparator: '[, ]+', 
                                    remoteDirectory: '', 
                                    remoteDirectorySDF: false, 
                                    removePrefix: '', sourceFiles: 'dist/**,index.html'
                                )
                            ], 
                            usePromotionTimestamp: false, 
                            useWorkspaceInPromotion: false, 
                            verbose: false
                        )
                    ]
                )

            }
        }

    }

}

k8s容器版

pipeline {
    agent {
        kubernetes {
            cloud 'kubernetes'
            namespace 'default'
            yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
    - name: jnlp
      image: jenkins/inbound-agent:4.7-1-jdk11
      args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /etc/hosts
          name: hosts
    - name: docker
      image: docker:19.03.15-git
      imagePullPolicy: IfNotPresent
      tty: true
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /var/run/docker.sock
          name: docker-socket
        - mountPath: /etc/hosts
          name: hosts
    - name: kubectl
      image: alvinos/kubectl:1.17.4
      imagePullPolicy: IfNotPresent
      tty: true
      command:
        - cat
      volumeMounts:
        - mountPath: /.kube
          name: kubeconfig
          readOnly: false
        - mountPath: /etc/localtime
          name: valume-time
    - name: sonarqube
      image: emeraldsquad/sonar-scanner:2.2.0
      tty: true
      command:
        - cat
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /etc/hosts
          name: hosts
    - name: node
      image: node:16.15.1
      tty: true
      command:
        - cat
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
  volumes:
    - name: valume-time
      hostPath:
        path: /usr/share/zoneinfo/Asia/Shanghai
    - name: docker-socket
      hostPath:
        path: /var/run/docker.sock
    - name: hosts
      hostPath:
        path: /etc/hosts
    - name: kubeconfig
      secret:
        secretName: kubeconfig
        items:
          - key: config
            path: config
    - name: maven-repository
      nfs:
        path: /nfs/v2
        server: 172.16.0.11
    - name: maven-k8s-devops
      configMap:
        name: maven-k8s-devops
        items:
          - key: settings.xml
            path: settings.xml
'''
        }
    }

    parameters {
        listGitBranches branchFilter: '.*',
        credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
        defaultValue: '',
        listSize: '5',
        name: 'GIT_TAG',
        quickFilterEnabled: false,
        remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/vue-tetris-master.git',
        selectedValue: 'NONE',
        sortMode: 'NONE',
        tagFilter: '*',
        type: 'PT_TAG'
    }


    stages {

        stage("拉取代码") {
            steps {
                checkout(
                    [
                        $class: 'GitSCM',
                        branches: [[name: '*/master']],
                        extensions: [],
                        userRemoteConfigs: [[
                            credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
                            url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/vue-tetris-master.git'
                        ]]
                    ]
                )
            }
        }
        stage("切换分支") {
            steps {
                script {
                    sh """
                        git checkout $GIT_TAG
                    """
                }
            }
        }

        stage("代码漏洞扫描") {
            steps {
                container('sonarqube') {
                    script {
                        scannerTool = tool(
                            name: 'sonarqube-scanner',
                            type: 'hudson.plugins.sonar.SonarRunnerInstallation'
                        )
                    }
                    withSonarQubeEnv('sonarqube8.9.8') {
                        sh """
                            export JAVA_HOME=/usr/local/openjdk-11
                            ${scannerTool}/bin/sonar-scanner
                        """
                    }
                }
            }
        }

        stage("代码漏洞扫描状态判断") {
            steps {
                script {
                    timeout(1) {
                        qg = waitForQualityGate()
                        if (qg.status != 'OK') {
                          error "代码漏洞扫描失败,状态为: ${qg.status}"
                        } else {
                            echo "代码漏洞扫描通过"
                        }
                    }
                }
            }
        }

        stage("编译代码") {
            steps {
                container('node') {
                    sh """
                        npm config set registry https://registry.npm.taobao.org
                        npm install
                        npm run build
                    """
                }
            }
        }

        stage("初始化docker环境和k8s环境") {
            steps {
                script {
                    CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
                    BuildTime = sh(returnStdout: true, script: "date '+%s'").trim()
                    TAG = CommitID + "-" + BuildTime + "-" + GIT_TAG
                }
            }
        }

        stage("构建docker镜像") {
            steps {
                withCredentials([
                    usernamePassword(
                        credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350',
                        passwordVariable: 'Password',
                        usernameVariable: 'Username'
                    )]) {
                    container('docker'){
                        sh """
                            docker build -t registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} .
                            docker login registry.cn-hangzhou.aliyuncs.com --username=${Username} --password=${Password}
                            docker push registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG}
                        """
                    }
                }
            }
        }

        stage("部署到k8s集群中") {
            steps {
                withCredentials([
                    usernamePassword(
                        credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350',
                        passwordVariable: 'Password',
                        usernameVariable: 'Username'
                    )]) {
                    container('kubectl'){
                        sh """
                            kubectl delete secrets aliyun-registry  --kubeconfig=/.kube/config
                            kubectl create secret docker-registry aliyun-registry --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=${Username} --docker-password=${Password} --kubeconfig=/.kube/config
                            kubectl set image deployment vue vue=registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} --kubeconfig=/.kube/config
                        """
                    }
                }
            }
        }

    }

}

部署Java项目

部署Tomcat

wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.64/bin/apache-tomcat-9.0.64.tar.gz

[root@nexus apache-tomcat-9.0.64]# vim conf/tomcat-users.xml 
    <role rolename="tomcat"/>
    <role rolename="role1"/>
    <role rolename="manager-script"/>
    <role rolename="manager-gui"/>
    <role rolename="manager-status"/>
    <role rolename="admin-gui"/>
    <role rolename="admin-script"/>
    <user username="tomcat" password="tomcat" roles="manager-gui,manager-script,tomcat,admin-gui,admin-script"/>


[root@nexus apache-tomcat-9.0.64]# vim webapps/manager/META-INF/context.xml
  <!--<Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />-->
// Java项目
    // 1、拉取代码
    // 2、切换分支
    // 3、扫描代码
    // 4、获取代码状态
    // 5、编译代码
    // 6、上传到制品库
    // 6、部署
    // 7、发送部署邮件
pipeline {

    agent any

    environment {
        NEXUS_VERSION = "nexus3"
        NEXUS_MOTHEN = "http"
        NEXUS_URL = "nexus.abck8s.com"
        NEXUS_REPOSITORY = "xiaoyangaijishu-devops"
        NEXUS_CREDENTIAL_ID = "16352058-0ab1-4270-858b-3639919803ca"
    }

    parameters {
        listGitBranches branchFilter: '.*',
        credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
        defaultValue: '',
        listSize: '5',
        name: 'GIT_TAG',
        quickFilterEnabled: false,
        remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/springboot.git',
        selectedValue: 'NONE',
        sortMode: 'NONE',
        tagFilter: '*',
        type: 'PT_TAG'
    }

    stages {
        stage("拉取代码") {
            steps {
                checkout(
                    [
                        $class: 'GitSCM',
                        branches: [[name: '*/master']],
                        extensions: [],
                        userRemoteConfigs: [[
                            credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
                            url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/springboot.git'
                        ]]
                    ]
                )
            }
        }
        stage("切换分支") {
            steps {

                script {

                    sh """
                        git checkout $GIT_TAG
                    """
                }

            }
        }

        stage("代码测试") {
            steps {
                script {
                    sh """
                        mvn test
                    """
                }
            }
        }

        stage("代码漏洞扫描") {
            steps {
                // 指定需要使用的Tools
                script {
                    scannerTool = tool(
                        name: 'sonarqube-scanner',
                        type: 'hudson.plugins.sonar.SonarRunnerInstallation'
                    )
                }

                // 使用Tool来进行代码扫描
                withSonarQubeEnv('sonarqube8.9.8') {
                    sh "${scannerTool}/bin/sonar-scanner"
                }
            }
        }

        stage("代码漏洞扫描状态判断") {
            steps {
                script {
                    timeout(1) {
                        qg = waitForQualityGate()
                        if (qg.status != 'OK') {
                          error "代码漏洞扫描失败,状态为: ${qg.status}"
                        } else {
                            echo "代码漏洞扫描通过"
                        }
                    }
                }
            }
        }
        stage("编译代码") {
            steps {
                script {
                    sh """
                        mvn package -DskipTests=true
                    """
                }
            }
        }
        stage("上传至制品库") {
            steps {
                script {
                    // 获取pom.xml中的详细信息
                    pom = readMavenPom file: 'pom.xml'
                    // 通过 pom.xml 获取可能生成的文件相对路径
                    filesbyGlob = findFiles(glob: "target/*.${pom.packaging}")
                    // 判断该文件是否生成
                    artifactPath = filesbyGlob[0].path
                    artifactExists = fileExists artifactPath

                    // 如果存在则开始上传至 Nexus 制品库
                    if (artifactExists) {
                        nexusArtifactUploader(
                            artifacts: [
                                [
                                    artifactId: pom.artifactId,
                                    classifier: '',
                                    file: artifactPath,
                                    type: pom.packaging
                                ], [
                                    artifactId: pom.artifactId,
                                    classifier: '',
                                    file: 'pom.xml',
                                    type: 'pom'
                                ]
                            ],
                            credentialsId: NEXUS_CREDENTIAL_ID,
                            groupId: pom.groupId,
                            nexusUrl: NEXUS_URL,
                            nexusVersion: NEXUS_VERSION,
                            protocol: NEXUS_MOTHEN,
                            repository: NEXUS_REPOSITORY,
                            version: pom.version
                        )
                    } else {
                        // 不存在则返回提示信息
                        error "文件 ${artifactPath} 不存在"
                    }
                }
            }
        }


        stage("部署到Tomcat") {
            steps {
                deploy(
                    adapters: [
                        tomcat9(
                            credentialsId: '822eba73-92cf-424b-b381-80a2ca3e70ad',
                            path: '',
                            url: 'http://192.168.15.31:8080')],
                    contextPath: null,
                    war: 'target/*.war'
                )
            }
        }

    }

}

Jenkins部署Python项目

Nginx + uwsgi

因为nginx不支持uwsgi协议,无法直接调用py开发的webApp。 在nginx+uWsgi+Django的框架里,nginx代理+webServer,uWsgi是wsgiServer,Django是webApp。 nginx接收用户请求,并判定哪些转发到uWsgi,uWsgi再去调用pyWebApp。

创建项目用户

groupadd django -g 888
useradd django -u 888 -g 888 -r -M -s /bin/sh

安装依赖软件

yum install python3 libxml* python-devel gcc* pcre-devel openssl-devel python3-devel -y

安装uWsgi

pip3 install uwsgi django -i  https://pypi.doubanio.com/simple

配置uwsgi

[root@localhost ~]# cat /opt/linux/myweb_uwsgi.ini 
[uwsgi]
# 端口号
socket            = :8000
# 指定项目的目录
chdir           = /opt/python
# wsgi文件路径
wsgi-file       = python/wsgi.py
# 模块wsgi路径
module          = python.wsgi
# 是否开启master进程
master          = true
# 工作进程的最大数目
processes       = 4
# 结束后是否清理文件
vacuum          = true

配置Nginx

[root@localhost ~]# cat /etc/nginx/conf.d/python.conf 
server {
  listen 80;
  server_name py.test.com;
  location / {
      include uwsgi_params;
      uwsgi_pass 127.0.0.1:8000;
      uwsgi_read_timeout 2;
      uwsgi_param UWSGI_SCRIPT python.wsgi;
      uwsgi_param UWSGI_CHDIR /opt/python;
      index index.html index.htm;
      client_max_body_size 35m;
  }
}

Linux版Python部署

// python项目
	// 1、拉取代码
	// 2、切换分支
	// 3、扫描代码
	// 4、获取代码状态
	// 6、部署
	//    6.1、下载包
	// 7、发送部署邮件

pipeline {

	agent any

	parameters {
	  listGitBranches branchFilter: '.*',
	  credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
	  defaultValue: '',
	  listSize: '5',
	  name: 'GIT_TAG',
	  quickFilterEnabled: false,
	  remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/python.git',
	  selectedValue: 'NONE',
	  sortMode: 'NONE',
	  tagFilter: '*',
	  type: 'PT_TAG'
	}


	stages {

		stage("拉取代码") {
			steps {
				checkout(
					[
						$class: 'GitSCM',
						branches: [[name: '*/master']],
						extensions: [],
						userRemoteConfigs: [[
							credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
							url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/python.git'
						]]
					]
				)
			}
		}
		stage("切换分支") {
			steps {

				script {

					sh """
						git checkout $GIT_TAG
					"""
				}

			}
		}

		stage("代码漏洞扫描") {
			steps {
				// 指定需要使用的Tools
				script {
					scannerTool = tool(
						name: 'sonarqube-scanner',
						type: 'hudson.plugins.sonar.SonarRunnerInstallation'
					)
				}

				// 使用Tool来进行代码扫描
				withSonarQubeEnv('sonarqube8.9.8') {
					sh "${scannerTool}/bin/sonar-scanner"
				}
			}
		}

		stage("代码漏洞扫描状态判断") {
			steps {
				script {
					timeout(1) {
						qg = waitForQualityGate()
						if (qg.status != 'OK') {
						  error "代码漏洞扫描失败,状态为: ${qg.status}"
						} else {
							echo "代码漏洞扫描通过"
						}
					}
				}
			}
		}

		stage("部署") {
			steps {

				sshPublisher(
					publishers: [
						sshPublisherDesc(
							configName: 'jenkins',
							transfers: [
								sshTransfer(
									cleanRemote: false,
									excludes: '',
									execCommand: '''#!/bin/bash
									    pip3 install django===2.2.2 -i  https://pypi.doubanio.com/simple

									    pip3 install uwsgi -i  https://pypi.doubanio.com/simple

                                        cd /opt/python

                                        uwsgi --stop uwsgi.pid || echo 1

									    uwsgi -d --ini uwsgi.ini
									    ''',
									execTimeout: 120000,
									flatten: false,
									makeEmptyDirs: false,
									noDefaultExcludes: false,
									patternSeparator: '[, ]+',
									remoteDirectory: '',
									remoteDirectorySDF: false,
									removePrefix: '', sourceFiles: '**/**'
								)
							],
							usePromotionTimestamp: false,
							useWorkspaceInPromotion: false,
							verbose: false
						)
					]
				)

			}
		}

	}

}

k8s容器版Python部署

// python项目
	// 1、拉取代码
	// 2、切换分支
	// 3、扫描代码
	// 4、获取代码状态
	// 6、部署
	//    6.1、下载包
	// 7、发送部署邮件

pipeline {


agent {
		kubernetes {
			cloud 'kubernetes'
			namespace 'default'
			yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
    - name: jnlp
      image: jenkins/inbound-agent:4.7-1-jdk11
      args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /etc/hosts
          name: hosts
    - name: docker
      image: docker:19.03.15-git
      imagePullPolicy: IfNotPresent
      tty: true
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /var/run/docker.sock
          name: docker-socket
        - mountPath: /etc/hosts
          name: hosts
    - name: kubectl
      image: alvinos/kubectl:1.17.4
      imagePullPolicy: IfNotPresent
      tty: true
      command:
        - cat
      volumeMounts:
        - mountPath: /.kube
          name: kubeconfig
          readOnly: false
        - mountPath: /etc/localtime
          name: valume-time
    - name: sonarqube
      image: emeraldsquad/sonar-scanner:2.2.0
      tty: true
      command:
        - cat
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /etc/hosts
          name: hosts
    - name: maven
      image: maven:3.6.3-openjdk-8
      imagePullPolicy: IfNotPresent
      tty: true
      command:
        - cat
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /root/.m2/repository
          name: maven-repository
          readOnly: false
        - mountPath: /usr/share/maven/conf/settings.xml
          name: maven-k8s-devops
          subPath: settings.xml
          readOnly: false
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
  volumes:
    - name: valume-time
      hostPath:
        path: /usr/share/zoneinfo/Asia/Shanghai
    - name: docker-socket
      hostPath:
        path: /var/run/docker.sock
    - name: hosts
      hostPath:
        path: /etc/hosts
    - name: kubeconfig
      secret:
        secretName: kubeconfig
        items:
          - key: config
            path: config
    - name: maven-repository
      nfs:
        path: /nfs/v2
        server: 172.16.0.11
    - name: maven-k8s-devops
      configMap:
        name: maven-k8s-devops
        items:
          - key: settings.xml
            path: settings.xml
'''
		}
	}


	parameters {
	  listGitBranches branchFilter: '.*',
	  credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
	  defaultValue: '',
	  listSize: '5',
	  name: 'GIT_TAG',
	  quickFilterEnabled: false,
	  remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/python.git',
	  selectedValue: 'NONE',
	  sortMode: 'NONE',
	  tagFilter: '*',
	  type: 'PT_TAG'
	}


	stages {

		stage("拉取代码") {
			steps {
				checkout(
					[
						$class: 'GitSCM',
						branches: [[name: '*/master']],
						extensions: [],
						userRemoteConfigs: [[
							credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
							url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/python.git'
						]]
					]
				)
			}
		}
		stage("切换分支") {
			steps {

				script {

					sh """
						git checkout $GIT_TAG
					"""
				}

			}
		}

		stage("代码漏洞扫描") {
			steps {
				container('sonarqube') {
					script {
						scannerTool = tool(
							name: 'sonarqube-scanner',
							type: 'hudson.plugins.sonar.SonarRunnerInstallation'
						)
					}
					withSonarQubeEnv('sonarqube8.9.8') {
						sh """
							export JAVA_HOME=/usr/local/openjdk-11
							${scannerTool}/bin/sonar-scanner
						"""
					}
				}
			}
		}

		stage("代码漏洞扫描状态判断") {
			steps {
				script {
					timeout(1) {
						qg = waitForQualityGate()
						if (qg.status != 'OK') {
						  error "代码漏洞扫描失败,状态为: ${qg.status}"
						} else {
							echo "代码漏洞扫描通过"
						}
					}
				}
			}
		}

		stage("初始化docker环境和k8s环境") {
			steps {
				script {
					CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
					BuildTime = sh(returnStdout: true, script: "date '+%s'").trim()
					TAG = CommitID + "-" + BuildTime + "-" + GIT_TAG
				}
			}
		}

		stage("构建docker镜像") {
			steps {
				withCredentials([
					usernamePassword(
						credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350',
						passwordVariable: 'Password',
						usernameVariable: 'Username'
					)]) {
					container('docker'){
						sh """
							docker build -t registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} .
							docker login registry.cn-hangzhou.aliyuncs.com --username=${Username} --password=${Password}
							docker push registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG}
						"""
					}
				}
			}
		}

		stage("部署到k8s集群中") {
			steps {
				withCredentials([
					usernamePassword(
						credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350',
						passwordVariable: 'Password',
						usernameVariable: 'Username'
					)]) {
					container('kubectl'){
						sh """
							kubectl delete secrets aliyun-registry  --kubeconfig=/.kube/config
							kubectl create secret docker-registry aliyun-registry --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=${Username} --docker-password=${Password} --kubeconfig=/.kube/config
							kubectl set image deployment python python=registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} --kubeconfig=/.kube/config
						"""
					}
				}
			}
		}

	}

}

Jenkins部署Golang项目

linux版

// golang项目
//	1、拉取代码
//	2、切换分支
//	3、代码扫描
//	4、判断代码扫描的状态
//	5、编译
//	6、上传至远程服务器

pipeline {

	agent any


	parameters {
		listGitBranches branchFilter: '.*', 
		credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930', 
		defaultValue: '', 
		listSize: '5', 
		name: 'GIT_TAG', 
		quickFilterEnabled: false, 
		remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/gin.git', 
		selectedValue: 'NONE', 
		sortMode: 'NONE', 
		tagFilter: '*', 
		type: 'PT_TAG'
	}


	stages {
	
		stage("拉取代码") {
			steps {
				checkout(
					[
						$class: 'GitSCM', 
						branches: [[name: '*/master']], 
						extensions: [], 
						userRemoteConfigs: [[
							credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
							url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/gin.git'
						]]
					]
				)
			}
		}
		
		stage("切换分支") {
			steps {
			
				script {
				
					sh """
						git checkout $GIT_TAG
					"""
				}
			
			}
		}
		
		stage("代码漏洞扫描") {
			steps {
				// 指定需要使用的Tools
				script {
					scannerTool = tool(
						name: 'sonarqube-scanner', 
						type: 'hudson.plugins.sonar.SonarRunnerInstallation'
					)
				}
			
				// 使用Tool来进行代码扫描
				withSonarQubeEnv('sonarqube8.9.8') {
					sh "${scannerTool}/bin/sonar-scanner"
				}
			}
		}
		
		stage("代码漏洞扫描状态判断") {
			steps {
				script {
					timeout(1) {
						qg = waitForQualityGate()
						if (qg.status != 'OK') {
						  error "代码漏洞扫描失败,状态为: ${qg.status}"
						} else {
							echo "代码漏洞扫描通过"
						}
					}
				}
			}
		}
		
		
		stage("编译代码") {
			steps {
				script {
					sh """
						sh ./build.sh
					"""
				}
			}
		}
		
		stage("上传至远程服务器") {
			steps {
				
				sshPublisher(
					publishers: [
						sshPublisherDesc(
							configName: 'golang', 
							transfers: [
								sshTransfer(
									cleanRemote: false, 
									excludes: '', 
									execCommand: '''#!/bin/bash
										cd /opt/golang
										chmod +x main
										systemctl restart golang-server
										''', 
									execTimeout: 120000,
									flatten: false, 
									makeEmptyDirs: false, 
									noDefaultExcludes: false, 
									patternSeparator: '[, ]+', 
									remoteDirectory: '', 
									remoteDirectorySDF: false, 
									removePrefix: '', 
									sourceFiles: '**/main'
								)
							], 
							usePromotionTimestamp: false, 
							useWorkspaceInPromotion: false, 
							verbose: false
						)
					]
				)
			
			}
		}
		
		
	
	}

}

k8s版

// golang项目
//	1、拉取代码
//	2、切换分支
//	3、代码扫描
//	4、判断代码扫描的状态
//	5、编译
//	6、上传至远程服务器

pipeline {

agent {
		kubernetes {
			cloud 'kubernetes'
			namespace 'default'
			yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
    - name: jnlp
      image: jenkins/inbound-agent:4.7-1-jdk11
      args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /etc/hosts
          name: hosts
    - name: docker
      image: docker:19.03.15-git
      imagePullPolicy: IfNotPresent
      tty: true
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /var/run/docker.sock
          name: docker-socket
        - mountPath: /etc/hosts
          name: hosts
    - name: kubectl
      image: alvinos/kubectl:1.17.4
      imagePullPolicy: IfNotPresent
      tty: true
      command:
        - cat
      volumeMounts:
        - mountPath: /.kube
          name: kubeconfig
          readOnly: false
        - mountPath: /etc/localtime
          name: valume-time
    - name: sonarqube
      image: emeraldsquad/sonar-scanner:2.2.0
      tty: true
      command:
        - cat
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /etc/hosts
          name: hosts
    - name: maven
      image: maven:3.6.3-openjdk-8
      imagePullPolicy: IfNotPresent
      tty: true
      command:
        - cat
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
        - mountPath: /root/.m2/repository
          name: maven-repository
          readOnly: false
        - mountPath: /usr/share/maven/conf/settings.xml
          name: maven-k8s-devops
          subPath: settings.xml
          readOnly: false
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
    - name: golang
      image: golang:1.16.3
      imagePullPolicy: IfNotPresent
      tty: true
      command:
        - cat
      volumeMounts:
        - mountPath: /etc/localtime
          name: valume-time
      env:
        - name: "LANGUAGE"
          value: "en_US:en"
        - name: "LC_ALL"
          value: "en_US.UTF-8"
        - name: "LANG"
          value: "en_US.UTF-8"
  volumes:
    - name: valume-time
      hostPath:
        path: /usr/share/zoneinfo/Asia/Shanghai
    - name: docker-socket
      hostPath:
        path: /var/run/docker.sock
    - name: hosts
      hostPath:
        path: /etc/hosts
    - name: kubeconfig
      secret:
        secretName: kubeconfig
        items:
          - key: config
            path: config
    - name: maven-repository
      nfs:
        path: /nfs/v2
        server: 172.16.0.11
    - name: maven-k8s-devops
      configMap:
        name: maven-k8s-devops
        items:
          - key: settings.xml
            path: settings.xml
'''
		}
	}


	parameters {
		listGitBranches branchFilter: '.*', 
		credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930', 
		defaultValue: '', 
		listSize: '5', 
		name: 'GIT_TAG', 
		quickFilterEnabled: false, 
		remoteURL: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/gin.git', 
		selectedValue: 'NONE', 
		sortMode: 'NONE', 
		tagFilter: '*', 
		type: 'PT_TAG'
	}


	stages {
	
		stage("拉取代码") {
			steps {
				checkout(
					[
						$class: 'GitSCM', 
						branches: [[name: '*/master']], 
						extensions: [], 
						userRemoteConfigs: [[
							credentialsId: 'bd34af1d-f1fb-4c19-a185-b746531a6930',
							url: 'git@gitlab.abck8s.com:douyin-xiaoyangaijishu/gin.git'
						]]
					]
				)
			}
		}
		
		stage("切换分支") {
			steps {
			
				script {
				
					sh """
						git checkout $GIT_TAG
					"""
				}
			
			}
		}
		
		stage("代码漏洞扫描") {
			steps {
				container('sonarqube') {
					script {
						scannerTool = tool(
							name: 'sonarqube-scanner',
							type: 'hudson.plugins.sonar.SonarRunnerInstallation'
						)
					}
					withSonarQubeEnv('sonarqube8.9.8') {
						sh """
							export JAVA_HOME=/usr/local/openjdk-11
							${scannerTool}/bin/sonar-scanner
						"""
					}
				}
			}
		}
		
		stage("代码漏洞扫描状态判断") {
			steps {
				script {
					timeout(1) {
						qg = waitForQualityGate()
						if (qg.status != 'OK') {
						  error "代码漏洞扫描失败,状态为: ${qg.status}"
						} else {
							echo "代码漏洞扫描通过"
						}
					}
				}
			}
		}
		
		
		stage("编译代码下载代码依赖包") {
			steps {
				container('golang'){
					sh """
						export GOPATH=/go
						sh ./build.sh
					"""
				}
			}
		}
		
		
		stage("初始化docker环境和k8s环境") {
			steps {
				script {
					CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
					BuildTime = sh(returnStdout: true, script: "date '+%s'").trim()
					TAG = CommitID + "-" + BuildTime + "-" + GIT_TAG
				}
			}
		}
		
		stage("构建docker镜像") {
			steps {
				withCredentials([
					usernamePassword(
						credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350', 
						passwordVariable: 'Password', 
						usernameVariable: 'Username'
					)]) {
					container('docker'){
						sh """
							docker build -t registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} .
							docker login registry.cn-hangzhou.aliyuncs.com --username=${Username} --password=${Password}
							docker push registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG}
						"""
					}
				}
			}
		}
		
		stage("部署到k8s集群中") {
			steps {
				withCredentials([
					usernamePassword(
						credentialsId: 'c67fa380-07fa-49c9-9df4-69b3dc562350', 
						passwordVariable: 'Password', 
						usernameVariable: 'Username'
					)]) {
					container('kubectl'){
						sh """
							kubectl delete secrets aliyun-registry  --kubeconfig=/.kube/config
							kubectl create secret docker-registry aliyun-registry --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=${Username} --docker-password=${Password} --kubeconfig=/.kube/config
							kubectl set image deployment python python=registry.cn-hangzhou.aliyuncs.com/alvinos/java:${TAG} --kubeconfig=/.kube/config
						"""
					}
				}
			}
		}

	}
	post {
	  always {
		emailext(
			body: '构建结果通知!', 
			subject: "自动化构建报告:$JOB_NAME - Build", 
			to: 'chenyangqit@163.com'
		)
	  }
	}

}