首页 > 代码库 > Jenkins 持续化部署实例

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 分发服务器内容。

技术分享


三:安装 jenkins  

1、安装启动

目前版本为2.7.4,下面实验环境在 centos7 上,具体安装环境步骤,官网有明确说明

技术分享

方式一:

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

技术分享

技术分享


三:持续化集成发布 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过来的路径

接下来就是点点点 .........

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享

技术分享


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"

            """)

技术分享


方式二:ansible(推荐:集合了fabric、saltstack等众多自动化工具的优点)

vim /etc/ansible/host  //编写ip列表模块,比如 test

技术分享


3、创建项目 wordpress_online

目的:更新版本

新建文本 onlinever,记录版本号,供客户端python脚本检索其内容进行更新

首先随便执行一个版本,初始化一下(顺便测试)

技术分享

技术分享


四:编写客户端更新脚本 (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


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



本文出自 “北冰--Q” 博客,请务必保留此出处http://beibing.blog.51cto.com/10693373/1920557

Jenkins 持续化部署实例