前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >打造企业级自动化运维平台系列(五):Jenkis 基本使用介绍

打造企业级自动化运维平台系列(五):Jenkis 基本使用介绍

作者头像
民工哥
发布2024-01-18 16:37:36
1770
发布2024-01-18 16:37:36
举报

这篇主要系统的介绍一下 jenkins 的使用,这里jenkins是搭建在 windows上。

常用功能介绍

常用插件介绍

除了最开始安装jenkins时他推荐让你下载的插件,还有一些插件是需要我们自行下载的,所以在这part我就简单汇总下其他我们可能要用到的一些插件。

  • 注意: jenkins上自行下载的一些插件,需要重启jenkins后才生效;
  • 另外像jdk,maven这些插件必须要自行在jenkins上配置好环境变量才可以运用。

因为jenkins下载了插件只代表你目前的jenkins能够支持使用这个插件,但是具体的插件位置其实是你本地的,而环境变量的配置就是去找你本地的目录。

另外常用的插件介绍
  • Rebuilder: 此插件可以直接重复上次构建
  • Pipeline: 持续交付插件,可以在新增 job时选择这一类型插件,然后通过写pipeline代码去运行job
  • Blue Ocean: 蓝海,可可视化看到任务的状态
  • Allure : 使用allure生成测试报告
  • robotframework: jenkins集成robotframework

创建一个自由风格的Job

我这里只是简单介绍一个简单任务的创建,大家可以按照各自需求配置自己的任务。

Jenkins新增节点

一般情况下,我们都不会在master节点上面去运行任务,通常会新增slave节点运行,由于我jenkins搭建在windows上,我这里就简单写下windows节点的新增。

新增windows节点
启动windows节点
在新节点上运行任务

Jenkins 配置报警机制

流程简单来说:

  • 就是在jenkins中配置好email后,
  • 运行任务时我们添加邮件触发器,当任务失败或者成功时,自动发送邮件
配置Email
下载Email相关插件
  • Email Extension
  • Email Extension Template Plugin

这两插件的作用即:帮助用户方便的设置格式化邮件。

配置管理员邮箱
配置邮件通知
配置邮件模板

Jenkins可以根据你配置的邮件模板格式发送结果邮件,通过Jenkins的参数定制自己的Email模板,常用的参数key值如下。

代码语言:javascript
复制
# 常用参数
$BUILD_STATUS -构建结果
$PROJECT_NAME -构建脚本名称
$BUILD_NUMBER -构建脚本编号
$JOB_DESCRIPTION -构建项目描述
$CAUSE - 脚本启动原因
$BUILD_URL - 脚本构建详情URL地址

模板内容,可以自行写

代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_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>
            <td>本邮件是Jenkins自动发送,请勿回复!</td>
        </tr>
        <tr>
            <td><h3>
                    <font color="#e53935">&nbsp&nbsp&nbsp&nbsp构建结果 - ${BUILD_STATUS}!</font>
                </h3></td>
        </tr>
        <tr>
            <td><br />
            <b><font color="#3f51b5">构建信息:</font></b>
            <hr size="2" width="100%" align="center" /></td>
        </tr>
        <tr>
            <td>
                <ul>
                    <li>项目名称&nbsp;:&nbsp;${PROJECT_NAME}</li>
                    <li>构建编号&nbsp;:&nbsp;第${BUILD_NUMBER}次构建</li>
                    <li>触发原因:&nbsp;${CAUSE}</li>
                    <li>构建日志:&nbsp;<a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
                    <li>构建&nbsp;&nbsp;Url&nbsp;:&nbsp;<a href="${BUILD_URL}">${BUILD_URL}</a></li>
                    <li>工作目录&nbsp;:&nbsp;<a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
                    <li>项目&nbsp;&nbsp;Url&nbsp;:&nbsp;<a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></a></li>
                </ul>
            </td>
         <tr>
            <td><b><font color="#3f51b5">构建日志:</font></b>
            <hr size="2" width="100%" align="center" /></td>
        </tr>
        <tr>
            <td><textarea cols="160" rows="80" readonly="readonly"
                    style="font-family: Microsoft YaHei">${BUILD_LOG,maxLines=1000}</textarea>
            </td>
        </tr>
</html>
任务配置触发器
配置任务触发器

给你想要添加报警机制的任务添加即可

执行任务,查看邮件

Jenkins配置父子job

父子Job简要介绍

正常情况下,我们通常会有很多个任务,然后这些任务之间是有衔接的,比如先要执行一个任务,且这个任务是成功的状态下再去执行另一个任务

  • 适用场景:有先后次序关系的任务
  • 举个简单的例子:当我们要实现UI自动化时,首先我们需要先将最新的APP包给下载下来,下载成功后我们再去运行UI自动化用例
任务启动的触发条件:其他任务的运行结果

那下面我分别来详细讲下这三种情况的具体操作

  • 1、前驱任务成功的条件下被触发
  • 2、前驱任务失败的条件下被触发
  • 3、前驱任务不稳定的条件下被触发
父Job成功的条件下被触发
父Job失败的条件下被触发
  • 这里不重新再创建新任务,只在原任务上稍微调整一下
父Job不稳定的条件下被触发
  • 一样的,我这里也还是在原有任务上面进行简单修改,实现这种场景
  • 这里用到了一个新的插件Text Find,之前统一让大家下载过,如果没有下载过的话自行先下载下这个插件

JenkinsAPI 接口调用

Jenkins_API简要介绍

Jenkins_API:即Jenkins对外暴露的动作交互入口,为外部程序提供入口,可以控制Jenkins。

  • 支持协议:Http
  • 常用功能:运行Job,查看任务状态,返回任务编号
request调用JenkinsAPI

这里简单介绍下request进行调用JenkinsAPI,详细看下注释,其实很简单。

代码语言:javascript
复制
"""
    该类调用jenkins_api接口
        1、获取任务的最新编号
        2、获取任务的详细信息
"""
import json

import requests

# 注意:这个地址前面部分
# mikasa:yy1998123 是你的jenkins用户名和密码
# 127.0.0.1:8080 是本地jenkins域名+端口号
url = "http://mikasa:yy1998123@127.0.0.1:8080/jenkins/job/"

def get_jenkins_url(job_name):
    """
    拼接url+任务job
    :return:
    """
    # print("拼接url为:", url + job_name)
    return url + job_name

def send_api(req, tools="requests"):
    """
    对发送接口测试的工具进行封装(可以使用urlib3/requests)
    :param tools:
    :param req:
    :return:
    """
    if tools == "requests":
        return requests.request(**req)

def get_latest_job_number():
    """
    1、获取最新任务编号
    :return:
    """
    req = {
        "method": "GET",
        "url": get_jenkins_url("mikasa_demo001") + "/lastBuild/buildNumber",
    }
    res = send_api(req)
    print("最新任务编号:", res.json())

def get_job_info():
    """
    2、获取job详细信息
    :return:
    """
    req = {
        "method": "GET",
        "url": get_jenkins_url("mikasa_demo001") + "/api/json",
    }
    res = send_api(req)
    res_json = json.dumps(res.json(), indent=2)
    print("返回结果:", res_json)

get_latest_job_number()
get_job_info()
使用jenkins api库调用

-这里介绍下利用jenkins api库去调用,上面是我们自己去写request请求去调用,而其实目前已经存在了轮子,我们直接使用Jenkins api即可。

下载jenkinsapi库
封装jenkins调用
  • jenkins_api.py
代码语言:javascript
复制
"""
    封装jenkins调用类
"""
import configparser
import datetime
import logging
import os
import re
from jenkinsapi.jenkins import Jenkins

logging.basicConfig(level=logging.INFO, format='[%(asctime)s] - [%(name)s] - [%(levelname)s] - [%(message)s]')
log = logging.getLogger(__name__)

def get_jenkins_config(chose):
    """
    读取Jenkins配置:从配置文件中jenkins_server.ini
    :param chose:
    :return:
    """
    config = configparser.ConfigParser()
    # 读取配置
    config.read(os.path.join(os.getcwd(), 'jenkins_server.ini'))
    username = config.get(chose, 'username')
    password = config.get(chose, 'password')
    host = config.get(chose, 'host')
    port = config.get(chose, 'port')
    url = "http://" + host + ":" + port
    return url, username, password

class JenkinsDemo:
    def __init__(self, job_name, chose='jenkins'):
        """
        初始化,拿到jenkins配置
        :param job_name:
        :param chose:
        """
        self.job_name = job_name
        config = get_jenkins_config(chose)
        print("config:", config)
        # 解包元祖
        self.jk = Jenkins(*config, useCrumb=True)

    def __get_job_from_keys(self):
        """
        拿到所有的job名称
        :return: 返回一个列表
        """
        choose_list = []
        print(self.jk.keys())
        for my_job_name in self.jk.keys():
            # 遍历拿到所有的job,判断当前job是否在job列表里面,在的话添加到自定义列表
            if self.job_name in my_job_name:
                choose_list.append(my_job_name)
        return choose_list

    def __job_build(self, my_job_name):
        """
        构建job
        :param my_job_name:
        :return:
        """
        if self.jk.has_job(my_job_name):
            # 如果有这个job拿到他里面的job对象
            my_job = self.jk.get_job(my_job_name)
            if not my_job.is_queued_or_running():
                # 如果job当前没有在运行的话,就运行
                try:
                    # 若当前没有在跑的话,拿到最后一次构建数
                    last_build = my_job.get_last_buildnumber()
                except:
                    # 若没有获取到最后一次构建数的话,默认置为0
                    last_build = 0
                # 最新构建数+1
                build_num = last_build + 1
                try:
                    # 开始打包
                    self.jk.build_job(my_job_name)
                except Exception as e:
                    log.error(str(e))

                # 循环判断Jenkins是否打包完成
                while True:
                    # 若当前任务没有运行才获取信息
                    if not my_job.is_queued_or_running():
                        # 拿到最新一次的大奥信息
                        count_build = my_job.get_build(build_num)
                        # 获取打包开始时间
                        start_time = count_build.get_timestamp() + datetime.timedelta(hours=8)
                        # 获取打包日志
                        console_out = count_build.get_console()
                        # 获取打包状态
                        status = count_build.get_status()
                        # 获取变更内容
                        change = count_build.get_changeset_items()
                        log.info(" " + str(start_time) + " 发起的" + my_job_name + "构建已经完成,构建的状态为:" + status)
                        p2 = re.compile(r".*ERROR.*")
                        err_list = p2.findall(console_out)
                        log.info("打包日志为:" + str(console_out))
                        if status == "SUCCESS":
                            if len(change) > 0:
                                for data in change:
                                    for file_list in data["affectedPaths"]:
                                        log.info("发起的" + my_job_name + "变更的类:" + file_list)
                                    log.info("发起的" + my_job_name + "变更的备注:" + data["msg"])
                                    log.info("发起的" + my_job_name + "变更的提交人:" + data["author"]["fullName"])
                            else:
                                log.info("发起的" + my_job_name + "构建没有变更内容")

                            if len(err_list) > 0:
                                log.warning("构建的" + my_job_name + "构建状态为成功,但包含了以下错误:")
                                for error in err_list:
                                    log.error(error)
                        else:
                            if len(err_list) > 0:
                                log.warning("构建的" + my_job_name + "包含了以下错误:")
                                for error in err_list:
                                    log.error(error)
                        break
            else:
                log.warning("发起的" + my_job_name + "Jenkins is running")
        else:
            log.warning("发起的" + my_job_name + "没有该服务")

    def run(self):
        my_job_name = self.__get_job_from_keys()
        if len(my_job_name) == 1:
            self.__job_build(my_job_name[0])
        elif len(my_job_name) == 0:
            log.error("输入的job名称不正确!")

if __name__ == '__main__':
    jk = JenkinsDemo("mikasa_demo001")
    jk.run()
  • jenkins_server.ini
代码语言:javascript
复制
[jenkins]
username=mikasa
password=yy1998123
host=127.0.0.1
port=8080

Jenkins多线程任务执行

正常一个项目部署中,为了节省时间,我们通常都可以将一些没有依赖关系的任务同步执行。

  • 比如说:在进行UI自动化中,下载app包的同时,我们可以把git源码同步更新给拉下来

那本章就简单讲一个例子,多线程的情况下我们如何去写jenkinsfile。

任务示例
  • 代码我已上传到github:https://github.com/Burden1/Mikasa_pipeline_demo
mikasa_parallel_demo
  • 并行任务即在外面加个**parallel{}**,里面包含stage{}即可。
代码语言:javascript
复制
pipeline {
    agent none
 stages {
     stage('run parallel Stage') {
         parallel {
             stage('mikasa_Stage_1') {
                 agent { label "slave" }
                 steps {
                     echo "at agent slave run task 1."
                     bat "ipconfig"
                     sleep 10
                 }
             }
             stage('mikasa_Stage_2') {
                 agent { label "master" }
                 steps {
                     echo "at agent master run task 2."
                     bat "ipconfig"
                     sleep 10
                 }
             }
         }
     }
 }
}

参考文章:https://blog.csdn.net/makasa/category _10722865.html

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-01-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 民工哥技术之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 常用功能介绍
  • 常用插件介绍
  • 创建一个自由风格的Job
  • Jenkins新增节点
    • 新增windows节点
      • 启动windows节点
        • 在新节点上运行任务
        • Jenkins 配置报警机制
          • 配置Email
            • 任务配置触发器
            • Jenkins配置父子job
              • 父子Job简要介绍
                • 任务启动的触发条件:其他任务的运行结果
                  • 父Job成功的条件下被触发
                    • 父Job失败的条件下被触发
                      • 父Job不稳定的条件下被触发
                      • JenkinsAPI 接口调用
                        • Jenkins_API简要介绍
                          • request调用JenkinsAPI
                            • 使用jenkins api库调用
                            • Jenkins多线程任务执行
                              • 任务示例
                                • mikasa_parallel_demo
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档