缺點(diǎn):
效率: 發(fā)布方式一單一服務(wù)器上線沒問題,多服務(wù)器分發(fā)效率下降。如果網(wǎng)內(nèi)是統(tǒng)一入口登錄(即堡壘機(jī)為單一入口時),發(fā)布工作將變得極為困難。
安全風(fēng)險:發(fā)布方式二的SSH賬號密碼必須存在Jenkins上,雖然不是明文,但…..同樣也面臨這服務(wù)器的22口要對Jenkins開放,安全是問題。
采用系統(tǒng)方案:YUM
我當(dāng)時的思路:公司是等保三級的單位,在當(dāng)初我制定內(nèi)網(wǎng)規(guī)則的時候,強(qiáng)烈建議SSH登錄范圍必須限定,統(tǒng)一的入口可以極大的減少被***跳板式***的可能,所以我想到了是用YUM更新的方式:
發(fā)布:把代碼從SVN上遷出后,打成RPM包(強(qiáng)烈推介FPM)
更新:通過YUM的特性,更新的程序包每次保持版本號 1,例如test-519-1.x86_64(519就是Jenkins的發(fā)布版本號),服務(wù)器每次只需要執(zhí)行以下2條命令即可。
bash
yum clean all
yum install test
批量操作:通過Saltstack去通知每臺服務(wù)器去進(jìn)行Yum的動作啦。。。
回退: 就更簡單了,粗暴點(diǎn)在YUM服務(wù)器直接 mv test-518-1.x86_64 test-520-1.x86_64
即可,斯文點(diǎn)當(dāng)然還是回調(diào)Jenkins的接口,使用TAG回滾。
具體邏輯及實(shí)施
那么下面先來解決打RPM包,更新YUM源的問題(我的Jenkins就是我們內(nèi)網(wǎng)的YUM源):
配置Jenkins
首先我們需要打開Jenkins中的batch tasks(批處理,其實(shí)就是腳本),不會用Jenkins自己百度吧。
點(diǎn)擊Add post-build action
-選擇Invoke batch tasks
在Batch tasks
里填入腳本
bash mkdir -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腳本的大體意思:
創(chuàng)建/home/release/$JOB_NAME
目錄
然后把/var/lib/jenkins/workspace/$JOB_NAME
(Jenkins項(xiàng)目工作區(qū))的代碼打成一個以$JOB_NAME
命名,版本號為$JOB_NAME
的RPM包,其存放在/home/release/$JOB_NAME
這個目錄里,其解壓后會解壓到/home/www/bbs
目錄。
然后createrepo --update /home/release/$JOB_NAME/
通知更新更新YUM源.
最后就是回調(diào)我的Salt接口(此接口的作用其實(shí)就是根據(jù)這個項(xiàng)目反查對應(yīng)的哪幾臺發(fā)布主機(jī),然后在這些主機(jī)上執(zhí)行yum install
命令,是不是很無腦~)
Saltstack接口(saltjenkinspost)
由于我的平臺和Salt master
是同一臺(主要是省事),省去了調(diào)用API,直接調(diào)用了本地Saltstack已經(jīng)封裝的一些yum install
之類的命令。
upgradeavailable
驗(yàn)證yum源是否更新
install
安裝
modrepo
創(chuàng)建yum源
getrepo
驗(yàn)證yum源是否存在
intro
執(zhí)行更新后的一些命令
我在接口處理的每一步后都會驗(yàn)證返回的主機(jī)是否跟數(shù)據(jù)庫預(yù)設(shè)的項(xiàng)目主機(jī)一樣,只有一樣了才會進(jìn)行下一步(比如接口只返回了一臺服務(wù)器通過salt執(zhí)行的結(jié)果,而數(shù)據(jù)庫里該項(xiàng)目是兩臺服務(wù)器,我會認(rèn)為這個發(fā)布有問題,而進(jìn)行中斷)這樣也是為了避免有的主機(jī)更新成功了,有的主機(jī)沒更新成功,導(dǎo)致線上用戶體驗(yàn)不好(目前已經(jīng)成功從深信服公司要到了負(fù)載均衡的API)后面要做的就是采用灰度發(fā)布,從負(fù)載上摘除一個然后就更新一個,更新完畢再加回負(fù)載。
import json from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt try: import salt.client except: pass from 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): 檢測目標(biāo)主機(jī)組項(xiàng)目在yum上是否有新版本更新,返回可以更新的主機(jī) 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安裝項(xiàng)目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): 創(chuàng)建項(xiàng)目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): 驗(yàn)證項(xiàng)目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): 執(zhí)行svn_intro內(nèi)命令 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) 目標(biāo)主機(jī)檢查YUM源是否存在 if sorted(salt_jenkins.getrepo()) == sorted(str(job_hosts).split(\\\',\\\')): pass else: 不存在就創(chuàng)建YUM源 salt_jenkins.modrepo() 目標(biāo)主機(jī)檢查YUM源是否更新 if sorted(salt_jenkins.upgradeavailable()) == sorted(str(job_hosts).split(\\\',\\\')): if sorted(salt_jenkins.install()) == sorted(str(job_hosts).split(\\\',\\\')): 目標(biāo)主機(jī)執(zhí)行命令 salt_jenkins.install() 目標(biāo)主機(jī)執(zhí)行命令 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\\\')
后續(xù)會介紹發(fā)布的狀態(tài)返回,也就是Saltstack的MasterEvent及通過Jenkins結(jié)合Saltstack創(chuàng)新發(fā)布項(xiàng)目。
更多關(guān)于云服務(wù)器,域名注冊,虛擬主機(jī)的問題,請?jiān)L問西部數(shù)碼官網(wǎng):m.bingfeng168.cn