千家信息网

授之以渔-运维平台发布模块一(Jenkins篇)

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,本着步子迈得太大容易扯蛋的原则,平台设计初衷就是能调用开源产品肯定不自己做,这样平台只作为一个综合调度中心使用,无需考虑后面具体的功能实现逻辑。使用Jenkins还是要追溯到很久很久之前认知的一家公司
千家信息网最后更新 2026年11月04日授之以渔-运维平台发布模块一(Jenkins篇)

本着步子迈得太大容易扯蛋的原则,平台设计初衷就是能调用开源产品肯定不自己做,这样平台只作为一个综合调度中心使用,无需考虑后面具体的功能实现逻辑。

使用Jenkins还是要追溯到很久很久之前认知的一家公司,当时的技术总监张晓峰让我学到了持续集成引擎Hudson,也就是后来的Jenkins。以前公司是Jenkins结合Maven,Ant做敏捷式开发,而我只是取巧,用了其中的一些最基本的功能来实现系统发布更新。

传统的运维发布

  • SVN迁出代码-本地打成tar包(rar包)- sftp上传到服务器

  • Jenkins建立发布项目-SVN迁出代码-通过SFTP插件直接分发到服务器

优点:粗暴简单


缺点:

  • 效率: 发布方式一单一服务器上线没问题,多服务器分发效率下降。如果网内是统一入口登录(即堡垒机为单一入口时),发布工作将变得极为困难。

  • 安全风险:发布方式二的SSH账号密码必须存在Jenkins上,虽然不是明文,但.....同样也面临这服务器的22口要对Jenkins开放,安全是问题。

采用系统方案:YUM

我当时的思路:公司是等保三级的单位,在当初我制定内网规则的时候,强烈建议SSH登录范围必须限定,统一的入口可以极大的减少被***跳板式***的可能,所以我想到了是用YUM更新的方式:

  1. 发布:把代码从SVN上迁出后,打成RPM包(强烈推介FPM)

  2. 更新:通过YUM的特性,更新的程序包每次保持版本号+1,例如test-519-1.x86_64(519就是Jenkins的发布版本号),服务器每次只需要执行以下2条命令即可。

    bash yum clean all yum install test

  3. 批量操作:通过Saltstack去通知每台服务器去进行Yum的动作啦。。。

  4. 回退: 就更简单了,粗暴点在YUM服务器直接 mv test-518-1.x86_64 test-520-1.x86_64即可,斯文点当然还是回调Jenkins的接口,使用TAG回滚。

具体逻辑及实施

那么下面先来解决打RPM包,更新YUM源的问题(我的Jenkins就是我们内网的YUM源):

配置Jenkins

首先我们需要打开Jenkins中的batch tasks(批处理,其实就是脚本),不会用Jenkins自己百度吧。

  • 点击Add post-build action-选择Invoke batch tasks

  • 在Batch tasks里填入脚本

bashmkdir -p /home/release/$JOB_NAME && \fpm -s dir -t rpm -n $JOB_NAME -v $BUILD_NUMBER --prefix /home/www/bbs -C /var/lib/jenkins/workspace/$JOB_NAME -p /home/release/$JOB_NAME ./ && \createrepo --update /home/release/$JOB_NAME/ && \curl -d "job_id=$JOB_NAME" http://salt master IP/cmdb/salt_jenkins_post/


这段Jenkins脚本的大体意思:

  • 创建/home/release/$JOB_NAME目录

  • 然后把/var/lib/jenkins/workspace/$JOB_NAME(Jenkins项目工作区)的代码打成一个以$JOB_NAME命名,版本号为$JOB_NAME的RPM包,其存放在/home/release/$JOB_NAME这个目录里,其解压后会解压到/home/www/bbs目录。

  • 然后createrepo --update /home/release/$JOB_NAME/ 通知更新更新YUM源.

  • 最后就是回调我的Salt接口(此接口的作用其实就是根据这个项目反查对应的哪几台发布主机,然后在这些主机上执行yum install命令,是不是很无脑~)

Saltstack接口(saltjenkinspost)

由于我的平台和Salt master是同一台(主要是省事),省去了调用API,直接调用了本地Saltstack已经封装的一些yum install 之类的命令。

  • upgradeavailable 验证yum源是否更新

  • install 安装

  • modrepo 创建yum源

  • getrepo 验证yum源是否存在

  • intro 执行更新后的一些命令

我在接口处理的每一步后都会验证返回的主机是否跟数据库预设的项目主机一样,只有一样了才会进行下一步(比如接口只返回了一台服务器通过salt执行的结果,而数据库里该项目是两台服务器,我会认为这个发布有问题,而进行中断)这样也是为了避免有的主机更新成功了,有的主机没更新成功,导致线上用户体验不好(目前已经成功从深信服公司要到了负载均衡的API)后面要做的就是采用灰度发布,从负载上摘除一个然后就更新一个,更新完毕再加回负载。

import jsonfrom django.http import HttpResponsefrom django.views.decorators.csrf import csrf_exempttry:    import salt.clientexcept:    passfrom cmdb.models import *class Salt_jenkins:    def __init__(self, host_list, job):        self.client = salt.client.LocalClient()        self.host_list = host_list        self.type = type        self.job = job    def upgradeavailable(self):        """检测目标主机组项目在yum上是否有新版本更新,返回可以更新的主机"""        ret = self.client.cmd('%s'% self.host_list, 'pkg.upgrade_available', ['%s'% self.job],expr_form='list',ret='return_redis')        true_hostlist = []        for host in ret.keys():            if ret['%s' % host]:                true_hostlist.append(host)            else:                pass        return true_hostlist    def install(self):        """YUM安装项目RPM包"""        ret = self.client.cmd('%s'% self.host_list, 'pkg.install', ['%s'% self.job],expr_form='list',ret='return_redis')        true_hostlist = []        for host in ret.keys():            if ret['%s' % host] != {}:                install_ret = ret['%s' % host]['%s' % self.job]                if install_ret != '':                    true_hostlist.append(host)                else:                    pass            else:                pass        return true_hostlist    def modrepo(self):        """创建项目YUM源"""        ret = self.client.cmd('%s'% self.host_list, 'pkg.mod_repo',['repo=%s'% self.job,'baseurl=http://172.18.11.98/release/%s'% self.job,'enabled=1','gpgcheck=0','name=%s'% self.job,'priority=10'],expr_form='list',ret='return_redis')        true_hostlist = []        for host in ret.keys():            if type(ret['%s' % host]) == dict:               true_hostlist.append(host)            else:                pass        return  true_hostlist    def getrepo(self):        """验证项目YUM源是否存在"""        ret = self.client.cmd('%s'% self.host_list, 'pkg.get_repo', ['repo=%s'% self.job],expr_form='list',ret='return_redis')        true_hostlist = []        for host in ret.keys():            if ret['%s' % host] != {}:               true_hostlist.append(host)            else:                pass        return  true_hostlist    def intro(self):        """执行svn_intro内命令"""        command = Svn.objects.get(svn_name = self.job).svn_intro        ret = self.client.cmd('%s'% self.host_list, 'cmd.run', ['%s'% command],expr_form='list',ret='return_redis')        return ret@csrf_exempt    def salt_jenkins_post(request):    if request.method == 'POST':             ip = request.META.get("REMOTE_ADDR", None)        if ip == '172.18.11.98':               job =  request.POST.get('job_id')            job_hosts =  Svn.objects.get(svn_name=job).svn_hosts            if job =='cms_template.youth.cn' or job =='cms_assets.youth.cn':                pass            else:                """初始化Salt_jenkins"""                salt_jenkins = Salt_jenkins(job_hosts, job)                """目标主机检查YUM源是否存在"""                if sorted(salt_jenkins.getrepo()) == sorted(str(job_hosts).split(',')):                    pass                else:                    """不存在就创建YUM源"""                    salt_jenkins.modrepo()                """目标主机检查YUM源是否更新"""                if sorted(salt_jenkins.upgradeavailable()) == sorted(str(job_hosts).split(',')):                    if sorted(salt_jenkins.install()) == sorted(str(job_hosts).split(',')):                        """目标主机执行命令"""                        salt_jenkins.install()                        """目标主机执行命令"""                        salt_jenkins.intro()                        return HttpResponse('install success')                    else:                        return HttpResponse('install fail')                else:                    return HttpResponse('upgradeavailable fail')        else:            return HttpResponse('ip deny')    else:        return HttpResponse('get deny')

后续会介绍发布的状态返回,也就是Saltstack的MasterEvent及通过Jenkins结合Saltstack创新发布项目。

更新 主机 服务器 项目 服务 命令 就是 接口 目标 代码 公司 问题 验证 平台 成功 入口 方式 版本 目录 脚本 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 广州紫鲸互联网科技有限公司 互联网是不是新科技 互联网巨头科技公司 互联网 科技 美国互联网科技 上海挚品互联网科技 互联网科技生活的内容 中国的互联网科技企业的崛起 湖南一路畅行互联网科技 哈尔滨屹滨互联网科技有限公司 深圳育鹏互联网科技有限公司招聘 中国互联网十大科技股排名 中天科技中国工业互联网 陕西云淼互联网科技公司 新氧科技和美国互联网有关系吗 广东鹅鹅鹅互联网科技有限公司 国产互联网科技公司 广州三三互联网科技有限公司 互联网科技创新创业项目 现代科技的标志之一的互联网 互联网科技有限公司 有格互联网科技 广州万易互联网科技有限公司 云之行互联网科技 深圳互联网络科技有限公司 互联网 的科技创新 互联网金融科技平台 以后互联网后是啥科技 华夏恒生互联网科技013171 昆明中奇联合互联网科技
0