Jenkins 持續化部署實例

開始本篇章之前介紹一個寫筆記的方法:康奈爾筆記法(新學的,很實用)

在此之前老大讓它們弄一個web端更新的界面系統,本來我也打算用django+bootstrap+python實現,但是此時python和bootstrap還沒有特別熟悉,目前技術不達標。不過期間碰到了jenkins,一個現成的實現持續交付部署的開源項目(但他的作用可不止如此),讚歎開源界的龐大。

----------------------------------------------------------------------------------------------

一:簡介 
官網:https://jenkins.io/ 
用於:監控外部調用的執行工作
用於:持續的軟件版本/項目的發佈(功能很多需要探索)
Jenkins 是一個開源軟件項目,基於 java 開發的 持續集成 工具,旨在提供一個開放易用的軟件平臺;
二:流程架構  
1、研發集成後上傳 svn/git
2、創建項目 center --- 將svn上的對應版本 上傳到分發服務器
3、創建項目 check --- 檢查查看目前使用的版本是哪個,避免下面更新把現有的更新
4、創建項目 online ---   更改 onlinever 文件中的版本號,供客戶端python檢索更新
5、python.py --- 編寫腳本,寫到cron,實現檢測md5、修改軟鏈、刪除老的版本

Jenkins 在日常使用中的架構如下,連接 svn/git,下載到分發服務器上(中控/vps中心),然後客戶端 poll 分發服務器內容。

wKiom1kCyqaBNIKsAAC_gCp3wTs406.png


三:安裝 jenkins  

1、安裝啓動

目前版本爲2.7.4,下面實驗環境在 centos7 上,具體安裝環境步驟,官網有明確說明

wKioL1kDAlKQLcGdAAB--L58_tA749.png

方式一:

wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo

rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key

yum install jenkins

systemctl  start  jenkins

方式二:

wget https://pkg.jenkins.io/redhat-stable/jenkins-2.7.4-1.1.noarch.rpm

rpm -ivh jenkins-2.7.4-1.1.noarch.rpm

systemctl  start  jenkins

方式三:

wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war

java -jar jenkins.war(war文件路徑) --port=8080(端口)

或者安裝 tomcat 並放到 webapps 下啓動(會自動解壓)

2、web端訪問

web訪問ip:8080 > 將該路徑下的密碼粘貼到這 > 自定義或者默認安裝插件 > 填寫資料(用戶名密碼用於後期登陸) 

項目目錄(即家目錄)默認在 /var/lib/jenkins

wKiom1kDAp6wkESvAACJqsyoNMs447.png

wKioL1kDAp7wYLxvAACMvug1IaQ248.png


三:持續化集成發佈 wordpress  

線上環境我們應用的話,我們要有自己的 svn 或者 git 等版本管理服務,因爲我們實驗就暫時借用 wordpress 的svn;wordpress 是一個有 GUN 協議的開源項目,php 寫的非常主流的博客系統,很美觀並支持中文。

官網:https://cn.wordpress.org/

svn :http://core.svn.wordpress.org/tags/

1、新建項目 wordpress_center_last

目的:作爲分發服務器

指定svn,拉取指定的版本(最新)

將下載的版本打包爲 tar.gz,利於傳輸

記錄此版本壓縮包的 md5 值,用於比對

記錄此版本號到文件 lastver,用於客戶端檢索自動更新

準備:

mkdir -p /data/web/wordpress/download

chown -R /data/web/wordpress/

/var/lib/jenkins/workspace/wordpress_center_last/wordpress-3.1  //poll過來的路徑

接下來就是點點點 .........

wKiom1kDA2SzrOPcAAFg5pxiKyc724.png

wKioL1kDA2Sj083cAAC6BGdQZXs084.png

wKiom1kDA2WCFGE7AACcnDsMVew806.png

wKiom1kDA7SDqZ3cAAB1YXNVRXg945.png

wKioL1kDA7WinYKLAACkVVGK7Pk607.png

wKiom1kDA7XTdQ3QAADJ0IKjNh0666.png

wKioL1kDA7bTZnBrAAAnAezYn9Y949.png


2、檢查項目 wordpress_check

目的:檢查客戶端在線的版本

檢查現在客戶端對應的版本,如果都已經是最新的版本,就不用更新了,節約資源

並且可以根據需求查看目前對應的版本

可以用的工具有很多 python的fabric、ansible、shell 等都可以

方式一:fabric

vim /data/web/wordpress/fabfile.py

#!/usr/bin/env python

from fabric.api import *

env.user='test'    #新建用戶,也可以用root用戶,但要在客戶端上傳公鑰

env.password='123'

env.hosts = ['localhost','192.168.1.104','192.168.1.107',] #設置客戶端的ip


def host_type():

    run('uname -s;echo $USER')


def check_ver():

        run("""ONLINE_VER=`curl -s http://center_ip:8080/deploy/onlinever`;

               ONLINE_WP=/var/www/releases/wordpress-$ONLINE_VER;

               test -d $ONLINE_WP && echo "$ONLINE_WP is exists" || echo "$ONLINE_WP is not exists"

            """)

wKioL1kDBJqThgA1AAAjMiR7m5c952.png


方式二:ansible(推薦:集合了fabric、saltstack等衆多自動化工具的優點)

vim /etc/ansible/host  //編寫ip列表模塊,比如 test

wKioL1kDBLaSXe4VAAAlOqdElds942.png


3、創建項目 wordpress_online

目的:更新版本

新建文本 onlinever,記錄版本號,供客戶端python腳本檢索其內容進行更新

首先隨便執行一個版本,初始化一下(順便測試)

wKioL1kDBRChCLVCAACBm4PX-3I737.png

wKioL1kDBSrBsfdWAACowv3CtcA955.png


四:編寫客戶端更新腳本 (python爲例)

#!/usr/bin/env python
#coding=utf-8

import urllib,urllib2
import os,sys
import hashlib,tarfile
import shutil

#定義分發服務器上用的到變量,最好配個dns服務器,供內部使用
URL_LASTVER = "http://192.168.1.107/wordpress/lastver"
URL_ONLINEVER = "http://192.168.1.107/wordpress/onlinever"
URL_PKG = "
 
#定義本地路徑變量
LOCAL_DOWNLOAD = "/data/web/wordpress/local/download/" #客戶端系下載的tar包
LOCAL_DEPLOY = "/data/web/wordpress/local/deploy/" #客戶端解壓使用版本目錄
DOC_WWW = "/data/web/wordpress/local/www" #軟鏈 至 worpress 版本
TOBE_KEEP = 2 #要保留的版本數量
WHITE_LST = []  #禁止刪除版本的白名單

#定義用到的文件名字
APP_NAME = "wordpress"
LASTVER = urllib2.urlopen(URL_LASTVER).read().strip() #讀取最新版本號
URL_LAST_PKG = URL_PKG + "%s-%s.tar.gz" % (APP_NAME,LASTVER) #服務端tar包
LOCAL_LAST_PKG = os.path.join(LOCAL_DOWNLOAD + "%s-%s.tar.gz" % (APP_NAME,LASTVER)) #客戶端tar包
ONLINEVER = urllib2.urlopen(URL_ONLINEVER).read().strip() #讀取在線版本號
LOCAL_ONLINE_PKG = os.path.join(LOCAL_DEPLOY + "%s-%s" % (APP_NAME,ONLINEVER)) #在線使用的版本

#初始化本地目錄
def init():
    if not os.path.exists(LOCAL_DOWNLOAD):
        os.makedirs(LOCAL_DOWNLOAD)
    if not os.path.exists(LOCAL_DEPLOY):
        os.makedirs(LOCAL_DEPLOY)
        
#檢查最新的版本並下載
def checkMd5file(f):  #由md5判斷下載是否正確
    URL_LAST_PKG_MD5 = f + ".md5file"
    URL_MD5 = urllib2.urlopen(URL_LAST_PKG_MD5).read().strip()
    with open(LOCAL_LAST_PKG) as fd:
        m = hashlib.md5(fd.read()).hexdigest()
        if m == URL_MD5:
            return True
        return False
def downLoad(f):
#    req = urllib2.urlopen(f)
#    data = req.read()
#    with open(LOCAL_LAST_PKG,'wb') as fd: 
#        fd.write(data)  # 一次性讀完,有點佔內存
    req = urllib2.urlopen(f)
    n = 1
    while True:
        data = req.read(4096) #以4096爲單位下載,節省內存
        if not data:
            break
        if n == 1:
            with open(LOCAL_LAST_PKG,'wb') as fd:
                fd.write(data)
                n += 1
        elif n > 1:
            with open(LOCAL_LAST_PKG,'a') as fd:
                fd.write(data)
                n += 1
    if checkMd5file(URL_LAST_PKG):
        return True
    return False
def checkLastVersion():
    WHITE_LST.append(LASTVER)  #加入白名單,禁止刪除
    if not os.path.exists(LOCAL_LAST_PKG):
        downLoad(URL_LAST_PKG)
    extract_dir = os.path.join(LOCAL_DEPLOY + "%s-%s" % (APP_NAME,LASTVER))
    if not os.path.exists(extract_dir): #解壓本地download下的包
        tar = tarfile.open(LOCAL_LAST_PKG)
        tar.extractall(LOCAL_DEPLOY)
        #tarFile(LOCAL_LAST,LOCAL_DEPLOY)
        
#解壓下載的tar包
#def tarFile(fn,d):
#    tar = tarfile.open(fn)
#    tar.extracall('d')

#檢查在線的版本,替換軟鏈
def checkOnlineVersion():
    WHITE_LST.append(ONLINEVER)  #加入白名單,禁止刪除
    if os.path.exists(LOCAL_ONLINE_PKG):
        if not os.path.exists(DOC_WWW): #此路徑是指源目錄
            os.symlink(LOCAL_ONLINE_PKG,DOC_WWW)
        else:
            target = os.readlink(DOC_WWW)
            if target != LOCAL_ONLINE_PKG:
                os.unlink(DOC_WWW)
                os.symlink(LOCAL_ONLINE_PKG,DOC_WWW) 
                
#對版本號進行排序,刪除多餘不用的版本
def versionSort(l):
    from distutils.version import LooseVersion
    vs = [LooseVersion(i) for i in l]
    vs.sort()
    return [o.vstring for o in vs]
def clear():
    DOWNLOAD_LST = [i.split('-')[1][:-7] for i in os.listdir(LOCAL_DOWNLOAD)] #取download下的版本號
    DEPLOY_LST = [i.split('-')[1] for i in os.listdir(LOCAL_DEPLOY)]
    tobe_del_download = versionSort(DOWNLOAD_LST)[:-TOBE_KEEP]
    tobe_del_deploy = versionSort(DEPLOY_LST)[:-TOBE_KEEP]
    for d in tobe_del_download:
        fn = os.path.join(LOCAL_DOWNLOAD + "%s-%s.tar.gz" % (APP_NAME,d))
        if d not in WHITE_LST: #不刪除使用的和最新的版本
            os.remove(fn)
    for d in tobe_del_deploy:
        fn = os.path.join(LOCAL_DEPLOY + "%s-%s" % (APP_NAME,d))
        if d not in WHITE_LST: #不刪除使用的和最新的版本
            #os.remove(fn)     #這隻能刪除空目錄
            shutil.rmtree(fn)
            
#執行時加個文件鎖,避免重複執行
def lockFile(f):
    if os.path.exists(f):
        print "%s is runing......" % __file__
        sys.exit()
    with open(f,'w') as fd:
        fd.write(str(os.getpid()))
def unlockFile(f): #解鎖文件
    if os.path.exists(f):
        os.remove(f)
        
#主程序
if __name__=='__main__':
    lockFile('/tmp/.deploy.lock')
    init()
    checkLastVersion()
    print "checkLastVersion"
    checkOnlineVersion()
    print "checkOnlineVersion"
    clear()
    print "clear"
    #time.sleep(10)
    unlockFile('/tmp/.deploy.lock')


crontab -e  #按時執行,可用ansible管理

*/5 * * * *  python /data/web/wordpress/update.py


-----------------------------------------------------------------------------------------------



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章