授之以渔-运维平台发布模块一(Jenkins篇)-成都快上网建站

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

建站服务器

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

从江网站制作公司哪家好,找成都创新互联!从网页设计、网站建设、微信开发、APP开发、响应式网站等网站项目制作,到程序开发,运营维护。成都创新互联于2013年开始到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选成都创新互联

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

传统的运维发布

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

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

优点:粗暴简单


缺点:

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

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

采用系统方案:YUM

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

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

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

bash yum clean all yum install test

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

回退: 就更简单了,粗暴点在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里填入脚本

bash
mkdir-p/home/release/$JOB_NAME&&\\
fpm-sdir-trpm-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-djob_id=$JOB_NAMEhttp://saltmasterIP/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)后面要做的就是采用灰度发布,从负载上摘除一个然后就更新一个,更新完毕再加回负载。

importjson
fromdjango.httpimportHttpResponse
fromdjango.views.decorators.csrfimportcsrf_exempt

try:
importsalt.client
except:
pass
fromcmdb.modelsimport*

classSalt_jenkins:
def__init__(self,host_list,job):
self.client=salt.client.LocalClient()
self.host_list=host_list
self.type=type
self.job=job


defupgradeavailable(self):
检测目标主机组项目在yum上是否有新版本更新,返回可以更新的主机
ret=self.client.cmd(\'%s\'%self.host_list,\'pkg.upgrade_available\',[\'%s\'%self.job],expr_form=\'list\',ret=\'return_Redis\')
true_hostlist=[]
forhostinret.keys():
ifret[\'%s\'%host]:
true_hostlist.append(host)
else:
pass
returntrue_hostlist

definstall(self):
YUM安装项目RPM包
ret=self.client.cmd(\'%s\'%self.host_list,\'pkg.install\',[\'%s\'%self.job],expr_form=\'list\',ret=\'return_redis\')
true_hostlist=[]
forhostinret.keys():
ifret[\'%s\'%host]!={}:
install_ret=ret[\'%s\'%host][\'%s\'%self.job]
ifinstall_ret!=\'\':
true_hostlist.append(host)
else:
pass
else:
pass
returntrue_hostlist

defmodrepo(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=[]
forhostinret.keys():
iftype(ret[\'%s\'%host])==dict:
true_hostlist.append(host)
else:
pass
returntrue_hostlist

defgetrepo(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=[]
forhostinret.keys():
ifret[\'%s\'%host]!={}:
true_hostlist.append(host)
else:
pass
returntrue_hostlist

defintro(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\')
returnret


@csrf_exempt
defsalt_jenkins_post(request):
ifrequest.method==\'POST\':
ip=request.META.get(REMOTE_ADDR,None)
ifip==\'172.18.11.98\':
job=request.POST.get(\'job_id\')
job_hosts=Svn.objects.get(svn_name=job).svn_hosts
ifjob==\'cms_template.youth.cn\'orjob==\'cms_assets.youth.cn\':
pass
else:
初始化Salt_jenkins
salt_jenkins=Salt_jenkins(job_hosts,job)

目标主机检查YUM源是否存在
ifsorted(salt_jenkins.getrepo())==sorted(str(job_hosts).split(\',\')):
pass
else:
不存在就创建YUM源
salt_jenkins.modrepo()
目标主机检查YUM源是否更新
ifsorted(salt_jenkins.upgradeavailable())==sorted(str(job_hosts).split(\',\')):
ifsorted(salt_jenkins.install())==sorted(str(job_hosts).split(\',\')):
目标主机执行命令
salt_jenkins.install()
目标主机执行命令
salt_jenkins.intro()
returnHttpResponse(\'installsuccess\')
else:
returnHttpResponse(\'installfail\')
else:
returnHttpResponse(\'upgradeavailablefail\')
else:
returnHttpResponse(\'ipdeny\')
else:
returnHttpResponse(\'getdeny\')

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


本文题目:授之以渔-运维平台发布模块一(Jenkins篇)
网页URL:http://kswjz.com/article/chopdd.html
扫二维码与项目经理沟通

我们在微信上24小时期待你的声音

解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流