Operation development story public account: Jock

Online release is the daily work of operation and maintenance. The common release methods are as follows:

  • Manual release
  • Jenkins Publishing Platform
  • Gitlab CI
  • .

There is also the need for open source software, which has great release management capabilities.

Problems faced

As operation and maintenance personnel, online release is an essential part of the process, what is a normal release process?

  • The demand side proposes the release task and goes through the release process
  • Supplier launches online

Link seems to be simple, but there is a fault in the middle. Generally, enterprises go online through some public channels, such as email, dingding and flying books, which are difficult to be associated with the online publishing platform of operation and maintenance execution, and it is not intuitive. So we need to solve the following problems:

  • The process is connected to the O&M platform
  • Form a closed loop from initiation to termination

In order to choose JIRA?

JIRA’s excellent project management, problem tracking tool, and its process management and Kanban modes make it very intuitive to see where the process is. In addition, it can establish friendly connections with other platforms through Webhook, easy to expand. Moreover, Jira is a daily tool for developers, testers, project managers, etc., with a high level of proficiency, reducing additional learning success. In view of this, we choose JIRA as the operation and maintenance publishing platform, striving to do everything on one platform.

The project design

Design ideas

Take full advantage of the Webhook capabilities of Jira and Gitlab, as well as Jenkins’ flexibility.

  • A status update on Jira triggers Jenkins to run the merge branch pipeline
  • Jenkins is triggered to execute the release pipeline after the code merge on Gitlab is successful
  • The results of the release will be notified by dingding and other software

The overall idea is relatively simple, and the difficulties mainly focus on Jenkins’ acquisition of the data of Jira and Gitlab. Fortunately, Jenkins’ plug-in functions are very rich, and the Generic Webhook Trigger plug-in is used here, which can flexibly obtain the information of the Trigger software.

Release Process Scheme

Then sort out the following release process.

Involved in the software

software function
Jira Release Process Management
Jenkins Execute various flow lines
Gitlab Code warehouse
Kubernetes Application management
Helm/kustomize Package management
nailing alerts
trivy Image scanning
Mirror warehouse Ali Cloud mirror warehouse

PS: There is no specific software deployment

Jira and Jenkins integrate merged branches

Jenkins configuration

Jenkins configuration mainly includes two parts, as follows:

  • Configure the Jenkins ShareLibrary function
  • Write Jira to trigger the corresponding Jenkinsfile

(1) Configure ShareLibarary system configuration on Jenkins > System configuration >Global Pipeline Libraries(2) Create pipeline, configure Webhook and add Jenkinsfile

  • Configuring triggers

Start by configuring a variable and reYou need to configure a Token

  • Configure pipeline and add Jenkinsfile for

(3) The main logic of Jenkinsfile is as follows

PS: The following is only a general framework, without detailed code

  • Obtain Jira configuration information for parsing
  • Perform different operations based on different information
  • Merging branches is done mainly by tuning Gitlab’s API interface
#! groovy@Library('lotbrick') _

def gitlab = new org.devops.gitlab()
def tool = new org.devops.tools()
def dingmes = new org.devops.sendDingTalk()

pipeline {
    agent { node { label "master"}}

    environment {
        DINGTALKHOOK = "https://oapi.dingtalk.com/robot/send?access_token=xxxx"   
    }

    stages{

        stage("FileterData"){
            steps{
                script{
                    response = readJSON text: """${webHookData}"""

                    // println(response)

                    env.eventType = response["webhookEvent"]

                    if (eventType == "jira:issue_updated") {// Get the status value
                        env.jiraStatus = response['issue'] ['fields'] ['status'] ['name']
                        env.gitlabInfos = response['issue'] ['fields'] ['customfield_10219']
                        infos = "${gitlabInfos}".split("\r\n")
                        for (info in infos){
                            prName = "$info".split("/") [0]
                            // brName = "$info".split("/")[1]
                            brName = info - "${prName}/"
                            println(prName)
                            println(brName)
                            if (jiraStatus == "Published (UAT)"){
                                println('Merge PRE branches')}else if (jiraStatus == "Published (PROD)"){
                                println('Merge PROD branches')}else if (jiraStatus == "Done"){
								println('Branch Tag and delete original branch')}else{
                                println("None found.")}}}}}}}// Post-build operations
	post {
		failure {
			script{ 
				println("Failure: Execute only if build fails")
				dingmes.SendDingTalk("Branch merge failed ❌")
			}
		}
		aborted {
            script{
				println("Aborted: The build will only be executed if cancelled")
				dingmes.SendDingTalk("Branch merge cancelled ❌"."Suspension or interruption")}}}}Copy the code

The above Jenkins configuration is basically completed.

On Jira configuration

The main configurations on Jira are as follows:

  • Establish workflow
  • Workflow associated projects
  • Configure the project to trigger Webhook

Establish workflow

Associate workflows with project teams

Configuration webhook

Settings –> System –> Network hooks

After the above configuration is complete, the Jira configuration is complete, and then you can view all the projects to be published on the corresponding project kanban, as follows:Then drag or click the publish button to change the state and trigger the pipeline for corresponding operations.

Gitlab and Jenkins integrate the release system

Brief development Branch

The functional branch development mode is mainly used here, which is mainly divided into the following branches:

  • DEV branch: Development environment branch
  • TEST branch: the TEST environment branch
  • UAT branch: joint environment branch
  • PRE branch: pre-release environment branch
  • MASTER branch: the production environment branch

The code merge route is DEV->TEST->UAT->PRE->MASTER and then execute the deployment of different environments according to the different branch judgment.

Jenkins configuration pipeline

(1) Set Webhook plug-in parameters

Get the Gitlab branchDefining a Gitlab push condition does not require any changes to trigger the pipeline

Define filter regular expressionsThis will only trigger the pipeline at commit time.

(2) Configure Jenkinsfile

def labels = "slave-${UUID.randomUUID().toString()}"

// Reference the shared library
@Library('jenkins_shareLibrary')

// Apply the methods in the shared library
def tools = new org.devops.tools()

def branchName = ""

// Get the branch
if ("${gitlabWebhook}"= ="gitlabPush"){
    branchName = branch - "refs/heads/"
	currentBuild.description = Constructor ${userName} branch ${branchName}
}

pipeline {
    agent {
        kubernetes {
            label labels
            yaml """ apiVersion: v1 kind: Pod metadata: labels: some-label: some-label-value spec: volumes: - name: docker-sock hostPath: path: /var/run/docker.sock type: '' - name: maven-cache persistentVolumeClaim: claimName: Maven - cache - PVC containers: - name: JNLP image: registry.cn-hangzhou.aliyuncs.com/rookieops/inbound-agent:4.3-4 - name: Maven image: registry.cn-hangzhou.aliyuncs.com/rookieops/maven:3.5.0-alpine command: - cat tty: true volumeMounts: - name: maven-cache mountPath: /root/.m2 - name: docker image: Registry.cn-hangzhou.aliyuncs.com/rookieops/docker:19.03.11 command: - cat tty: true volumeMounts: - name: docker-sock mountPath: /var/run/docker.sock - name: sonar-scanner image: registry.cn-hangzhou.aliyuncs.com/rookieops/sonar-scanner:latest command: - cat tty: true - name: kustomize image: Registry.cn-hangzhou.aliyuncs.com/rookieops/kustomize:v3.8.1 command: - cat tty: true - name: kubedog image: Registry.cn-hangzhou.aliyuncs.com/rookieops/kubedog:v0.5.0 command: [' cat '] tty: true - name: trivy image: registry.cn-hangzhou.aliyuncs.com/rookieops/trivy:v2 command: ['cat'] tty: true volumeMounts: - name: docker-sock mountPath: /var/run/docker.sock """
        }
    }

    environment {
        auth = 'joker'
    }

    options {
        timestamps()    // Log will have time
        skipDefaultCheckout()    Delete the implicit checkout SCM statement
        disableConcurrentBuilds()    // Disable parallelism
        timeout(time:1.unit:'HOURS') // Set pipeline timeout
    }

    stages {
        // Pull code
        stage('GetCode') {
            steps {
                checkout([$class: 'GitSCM'.branches: [[name: "${gitBranch}"]],
                    doGenerateSubmoduleConfigurations: false.extensions:[].submoduleCfg:[].userRemoteConfigs: [[credentialsId: '83d2e934-75c9-48fe-9703-b48e2feff4d8'.url: "${gitUrl}"]]])}}// Unit tests and build packages
        stage('Build&Test') {
            steps {
                container('maven') {
                    script {
                        tools.PrintMes('Compile package'.'blue')}}}}// Code scan
        stage('CodeScanner') {
            steps {
                container('sonar-scanner') {
                    script {
						tools.PrintMes('Code scan'.'blue')}}}}// Build the image
        stage('BuildImage') {
            steps {
                container('docker') {
					script {
						tools.PrintMes('Build image'.'blue')}}}}// Mirror scan
		stage('Vulnerability Scanner') {
            steps {
                container('trivy') {
                    script{
						tools.PrintMes('Mirror scan'.'blue')}}}}// Push image
		stage('Push Image') {
            steps {
                container('docker') {
                    script{
						tools.PrintMes('Push image'.'blue')}}}}/ / deployment
        stage('Deploy DEV') {
			when {
				branchName 'dev'
			}
            steps {
                container('kustomize'){
					script{
						tools.PrintMes('Deploy DEV environment'.'blue')
					}
				}
            }
        }
		stage('Deploy TEST') {
			when {
				branchName 'test'
			}
            steps {
                container('kustomize'){
					script{
						tools.PrintMes('Deploy the TEST environment'.'blue')
					}
				}
            }
        }
		stage('Deploy UAT') {
			when {
				branchName 'uat'
			}
            steps {
                container('kustomize'){
					script{
						tools.PrintMes('Deploy the UAT environment'.'blue')
					}
				}
            }
        }
		stage('Deploy PRE') {
			when {
				branchName 'pre'
			}
            steps {
                container('kustomize'){
					script{
						tools.PrintMes('Deploy the PRE environment'.'blue')
					}
				}
            }
        }
		stage('Deploy PROD') {
			when {
				branchName 'master'
			}
            steps {
                container('kustomize'){
					script{
						tools.PrintMes('Deploy the PROD environment'.'blue')}}}}// Trace application startup status
		stage('Check App Start') {
			steps{
				container('kubedog'){
					script{
						tools.PrintMes('Trace application startup'.'blue')}}}}// Interface test
        stage('InterfaceTest') {
            steps {
                sh Echo "interface test"}}}// Post-build operations
    post {
        success {
            script {
                println('Success: Execute only if build is successful')
                currentBuild.description += '\n Build successful! '
                dingmes.SendDingTalk("Build successful ✅")
            }
        }
        failure {
            script {
                println('Failure: Execute only if build fails')
                currentBuild.description += '\n Build failed! '
                dingmes.SendDingTalk("Build failed ❌")
            }
        }
        aborted {
            script {
                println('Aborted: The build will only be executed if cancelled')
                currentBuild.description += '\n Build cancelled! '
                dingmes.SendDingTalk("Build failed ❌"."Suspension or interruption")}}}}Copy the code

(3) Configure hook Settings -> Webhook on Gitlab

Here, the integration of Gitlab and Jenkins is almost complete, followed by specific debugging and configuration.

Wrote last

Thousands of roads, suitable for their own best.

The above is the operation and maintenance release made according to the actual situation of the work. The overall idea and implementation method are not complicated, mainly making full use of the webhook ability of each software and the flexible plug-in function of Jenkins, so as to get through the creation of release plan and implementation of release.

Personally, I think it is necessary to record it, and I hope it can help those who need it.