• 部署环境与流程
    1) Jenkins是java产品,需安装JDK8。由于.netFreamwork项目自动化发布时是基于Windows,所以继续使用Windows,在Windows server 2012环境下已有的Jenkins环境,部署、构建dotnet Core项目继续在Windows平台下操作。
    2) .NET Core SDK:2.2.402。dotnet build构建。
    3) 代码仓库GitLab。
    4) .NET Core服务端CentOS7
    部署环境流程:
    Python+JenkinsApi自动化部署.Net Core项目_第1张图片
  • 部署需求
    一个项目下分两个子项目,而子项目需分别进行构建部署,构建后子项目分别打包同步到不同的server上。所以,计划Jenkins上创建三个Job:A、B、C。A、B分别表示子项目,C进行统一管理A、B。即C作为A、B的构建入口。C-Job中上按参数选择构建应用,会触发对应的Job-B或Job-C构建,实现思路是python调用JenkinsAPI去实现,后面会具体讲到。大致流程如下:
    Python+JenkinsApi自动化部署.Net Core项目_第2张图片
  • Jenkins操作
    1) Jenkins具体安装略。下载见官方网站:https://jenkins.io/download/ ,选择安装Windows版本。
    这里Jenkins安装前,需配置好JDK环境,配置JDK8。
    2) 插件安装
    Jenkins安装好后,进入系统管理->插件管理,安装好Msbuild、GitLab、python等。
    Python+JenkinsApi自动化部署.Net Core项目_第3张图片
    3) 新建Job-A
    列出Job中主要设置项。
    Gitlab代码仓库和分支配置如下:
    Python+JenkinsApi自动化部署.Net Core项目_第4张图片
    构建build:
    build前新建“Exceute Windows batch command”,如下图:
    Python+JenkinsApi自动化部署.Net Core项目_第5张图片
    Python+JenkinsApi自动化部署.Net Core项目_第6张图片
    build命令:
    dotnet restore "%WORKSPACE%\PreventFraudAPI.Server"
    dotnet build "%WORKSPACE%\PreventFraudAPI.Server"
    dotnet publish "%WORKSPACE%\PreventFraudAPI.Server\PreventFraudAPI.sln" -o "E:\Publish-web\PreventFraudAPI-test\PreventFraudAPI.Server"

    dotnet restore :还原。主要是寻找当前目录下的项目文件(project.json),利用NuGet库还原整个项目的依赖库,并且遍历每个目录,生成项目文件,继续还原该项目文件中的依赖项。
    dotnet build :编译应用程序。该命令将项目及其依赖项生成为一组二进制文件。二进制文件包括扩展名为 .dll 的中间语言 (IL) 文件中的项目代码。
    dotnet publish:发布项目,使可跨平台运行程序。Windows环境build完之后,可发布到Linux环境下运行。
    dotnet run:运行应用程序。
    Build构建完后,再新建“Exceute Windows batch command”,从gitlab中拉取项目文件配置项。gitlbab中进行集中存放。将集中配置项文件copy到项目构建后的目录中。
    Python+JenkinsApi自动化部署.Net Core项目_第7张图片
    配置文件操作完后,需将Jenkins平台下已构建完后的项目文件打包、同步到.NET Core服务器端的CentOS7 Server上。Windows和Linux不同平台文件操作,这里选择Python实现,主要作了服务器端dotnet应用服务操作、应用程序备份、代码同步等。
    Python+JenkinsApi自动化部署.Net Core项目_第8张图片
    这里使用python下的paramiko模块实现。paramiko模块属于第三方库,实现了SSHv2协议,可以在Python代码中直接使用SSH协议对远程服务器执行操作,而无需通过ssh命令对远程服务器进行操作,使用前需要使用如下命令先进行安装:

    pip install paramiko

    paramiko包含两个核心组件:SSHClient和SFTPClient。
    SSHClient:类似于Linux的ssh命令,是对SSH会话的封装,该类封装了传输(Transport),通道(Channel)及SFTPClient建立的方法(open_sftp),常用于执行远程命令。
    SFTPClient:类似与Linux的sftp命令,是对SFTP客户端的封装,用以实现远程文件操作,如文件上传、下载、修改文件权限等操作。
    这里根据实际需求,使用了SSHClient这个组件。
    Python代码细节如下:

    import sys
    import paramiko
    class SSHconnection(object):
    def __init__(self, host, port, username, password):
        self._host = host
        self._port = port
        self._username = username
        self._password = password
        self._transport = None
        self._client = None
        self._connect()
    #建立connect连接
    def _connect(self):
        transport = paramiko.Transport((self._host, self._port))
        transport.connect(username=self._username, password=self._password)
        self._transport = transport
    def exec_command(self, command, step):
        if self._client is None:
            self._client = paramiko.SSHClient()
            self._client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self._client._transport = self._transport
        stdin, stdout, stderr = self._client.exec_command(command)
        data = stdout.read()
        print('%s 执行结果: ' % step)
        print(data.decode('utf-8'))
        # #输出结果
        # if len(data) > 0:
            # print('执行结果:')
            # print(data.decode('utf-8'))
        err = stderr.read()
        #输出错误结果
        if len(err) > 0:
            print('%s 执行的错误输出:' % step)
            print(err.decode('utf-8'))
    #关闭close连接
    def close(self):
        if self._transport:
            self._transport.close()
        if self._client:
            self._client.close()
    if __name__=="__main__":
    host = "10.10.10.75"
    port = 65089
    username = "root"
    password = "password"
    cmd_stop = "systemctl stop supervisor"
    cmd_backup = "cp -r /usr/soft/package/HiCore.PreventFraudAPI.Web/ /usr/soft/backup/HiCore.PreventFraudAPI.Web-`date +%Y-%m-%d-%H:%M`"
    cmd_rsync = "rsync   -vzrtopg  --no-super --numeric-ids  --progress  --port=873 --password-file=/opt/scripts/passwd.sh   [email protected]::PreventFraudAPI-test   /usr/soft/package/HiCore.PreventFraudAPI.Web/"
    cmd_start = "systemctl start supervisor"
    conn = SSHconnection(host, port, username, password)
    print('开始停supervisor服务...')
    conn.exec_command(cmd_stop, 'supervisor_stop_service')
    print('开始备份本地PreventFraudAPI程序...')
    conn.exec_command(cmd_backup, 'backup_app')
    print('开始同步PreventFraudAPI程序...')
    conn.exec_command(cmd_rsync, 'rsync_app')
    print('开始启supervisor服务...')
    conn.exec_command(cmd_start, 'supervisor_start_service')
    print('PreventFraudAPI程序发布完成,请验证!')

    同理,Job-B操作跟Job-A一样。主要是Job-C有差异,Job配置中有带参数。
    4) 新建Job-C
    列出Job中主要设置项。
    选择“This project is parameterized”,添加参数选择“Choice Parameter”,配置如下:
    Python+JenkinsApi自动化部署.Net Core项目_第9张图片
    根据选择的参数触发远程Job构建。如选择选项"Web"触发远程Job-A构建,选择选项"File"触发远程Job-B构建。
    构建build:
    build构建步骤选择新建“Exceute Windows batch command”,如下图:
    Python+JenkinsApi自动化部署.Net Core项目_第10张图片

  • Python操作Jenkins API
    目前Python版本Jenkins支持的API主要有2个第三方的包。
    JenkinsApi 和 Python-Jenkins
    1) Python-Jenkins
    多数文章建议使用Python-Jenkins模块,相对JenkinsApi,Python-Jenkins模块封装的更好,接口调用更方便,更容易。这里本来也是首选建议的Python-Jenkins模块,但是,在实际操作时报错:
    Python+JenkinsApi自动化部署.Net Core项目_第11张图片
    此类报错网上看了几篇文章,描述的多数是因为jenkins-python在python3.6存在bug,url没有转码。而这里是python3.7版本,也归类到版本问题。在Python2中可以使用。这里贴出Python-Jenkins方式代码,主要是要导入import jenkins模块。代码如下:
    import jenkins
    jenkins_server_url = 'http://jenkins.hicore.local/'
    user = 'yuhuanghui'
    api_token= '11f6714b10b086b9165ed507dd2f5e161a'
    #实例化jenkins对象,连接远程的jenkins server
    server = jenkins.Jenkins(jenkins_server_url,username=user,password=api_token)
    print(server)
    #构建job
    server.build_job('PreventFraudAPI-test')
    #查看某个job的构建信息
    job_info=server.get_job_info('PreventFraudAPI-test')
    print(job_info)

    这里就不更换python版本了,其他Job用到的python都是Python3,所以用另一种API方式JenkinsApi 。
    2) JenkinsApi
    Python+JenkinsApi自动化部署.Net Core项目_第12张图片
    使用JenkinsApi方式需要导入from jenkinsapi.jenkins import Jenkins、from jenkinsapi.build import Build模块。
    上面Job-C中的python脚本:

    import os,sys
    from jenkinsapi.jenkins import Jenkins
    from jenkinsapi.build import Build
    def get_server_instance():
    jenkins_url = 'http://10.10.10.69:8080/'
    server = Jenkins(jenkins_url, username='xiaoming', password='password')
    return server
    server = get_server_instance()
    #版本
    print('Jenkins版本:',server.version)
    #所有的job列表
    #print('Jobs:', server.keys())
    print('查看Jobs列表:',server.get_jobs_list())
    #判断job是否存在,存在返回true,不存在返回false。
    Web_Job = server.has_job('PreventFraud-test')
    File_Job = server.has_job('PreventFraudFile-test')
    env = os.getenv("ENV")
    print('选择发布构建的应用是:', env)
    if env == 'Web':
    print('开始Build构建PreventFraud-Web项目!')
    if Web_Job == True:
        #获取job名称
        job = server.get_job('PreventFraud-test')
        print('要Build构建的job是:', job)
        #构建,无参数的构建
        #params = {'Branch': 'oriin/master', 'host': '192.168.1.1'}
        res = server.build_job('PreventFraud-test')
        print('开始触发远程Job的构建,请查看远程Job:%s' % job)
        print(res)
        #print(job.__dict__['_data']['builds'])
        url = job.__dict__['_data']['lastBuild']['url']
        number = job.__dict__['_data']['lastBuild']['number']
        obj = Build(url, number, job)
        print('此次构建的Job名称:%s,Job的URL是:%s, 是第 %d 次构建。' % (job, url, number))
        print('构建的结果:', obj.get_status())
    else:
        print('要构建的Job不存在,请检查!')
    elif env == 'File':
    print('开始Build构建PreventFraud-File项目!')
    if File_Job == True:
        #获取job名称
        job = server.get_job('PreventFraudFile-test')
        print('要远程触发Build构建的job是:', job)
        #构建,无参数的构建
        #params = {'Branch': 'oriin/master', 'host': '192.168.1.1'}
        res = server.build_job('PreventFraudFile-test')
        print('开始触发远程Job的构建,请查看远程Job:%s' % job)
        print(res)
        #print(job.__dict__['_data']['builds'])
        url = job.__dict__['_data']['lastBuild']['url']
        number = job.__dict__['_data']['lastBuild']['number']
        obj = Build(url, number, job)
        print('此次构建的Job名称:%s,Job的URL是:%s, 是第 %d 次构建。' % (job, url, number))
        print('构建的结果:', obj.get_status())
    else:
        print('要构建的Job不存在,请检查!')
    else:
    print('请选择正确ENV环境项目!')
  • 构建
    Job-C中选择带参数构建,点击“Build with Parameters"进入后在”ENV“中选择”Web“构建,此时会远程触发Job-A构建。如下图所示:
    Python+JenkinsApi自动化部署.Net Core项目_第13张图片
    Job-C控制台输出情况:
    Python+JenkinsApi自动化部署.Net Core项目_第14张图片
    几秒钟后,查看Job-A控制台输出情况:
    Python+JenkinsApi自动化部署.Net Core项目