读者须知:
1、本手记本着记续接前面的两张手记内容整理
2、本手记针对tomcat部署测试环境实现
最近工作比较繁忙,导致这章一直拖延,没有太抽出时间来总结。要实现Jenkins端的持续集成,其实在CI服务配置端很容易,难点呢?就是如何实现自动化的部署。我的脚本设计就是为了解决以下难题:
难点一、如何使得自动化部署脚本更通用
我用的脚本,依赖依赖一个配置文件的模块化,让每一个应用业务模块更加通用。自动化所执行的命令呢?
我也是设计想法本着更加通用平台的原则,至少对于tomcat+java or java+socket这种模式通用。
难点二、如何使得自动化的部署简单有效
本脚本,更加切合实际,例:自动化部署关闭tomcat,我们常常会选择catalina.sh stop去关闭,然而这里我选择了kill的方式,如果检测中没有顺利关闭,我将调用kill -9 去直接关闭。(没办法,选择了通用,你是没遇到过tomcat 一直有线程卡住,关闭不了的情况吧。)
难点三、需要让我们自动化的部署实现高的可靠性
体现在:
1、每一次的部署,配置选项中都会进行备份。(备份只一次)
2、服务自动备份完毕后,需要实现检测(这里我在配置模块中有加入日志终端输出)
当然,这个脚本中还有未完成的地方:
1、服务启动后,自动化的检测机制还是太薄弱。
2、暂时此脚本还无法通用到php,python等环境的更多平台
3、代码备份方式上,应该更加具更多灵活性。
这里,如果你觉得我的脚本可以补充,不如大家一起加入进来(留言、或者邮件我jeson@imoocc.com),我也很想学习学习大家的想法。
一、自动化部署原理图示
1、2、3、4 表示执行的4个部署基础步骤
图片描述
二、实现
1、Tomcat 进程设置唯一标记
用于识别出一个服务器中唯一的Tomcat进程
java -Dmyapp.name=“project_name”
如果用的tomcat我们可以,直接修改启动控制文件catalina.sh。
JAVA_OPTS="-Dmyapp.name:"project_name" -server -Xms1024M -Xmx4096M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=1024M"
2、实现自动化登录
一般有两种方式:
方式一、模拟用户密码交互方式,大家可以学习家py中依赖pexcept模块。
方式二、用ssh + Key方式,这个是ssh的一种公钥认证机制。本脚本中用的这种,大家自行学习。
3、CI服务器需要在服务端配置rsync服务端
实现中,主要用于客户端服务拖取代码。
4、配置文件解释
[imoocc.com-server] //服务的模块名称,这里需要注意,需要具有唯一性,且服务的进程标示命名一致
CI_IP=ci.iaskjob.com //CI服务器地址
Login_ISA_Key=/back/key/jeson_iaskjob_rsa //登录ISA的key
Project_IP=192.168.10.99 //工程IP
Project_Login_User=root //对应工程机器登录用户
Project_Login_Port=22 //对应工程机器登录端口
Project_Code_File=/tmp/imoocc //对应工程在CI服务器构建后的执行代码目录
Project_Exclude_File="/var/cache","/var/tmp","jdbc.profile" //不需要向线上同步的文件,如配置文件等等
Project_Backup_Dir=/opt/Jenkins_Backup_Dir //工程备份目录
Project_Deploy_Path=/opt/imoocc //工程部署目录
Project_Start_Command=tomcat/bin/catalina.sh start //工程启动方式
Project_Log_Path=/tmp/imoocc.log //启动后日志的查看方式
分享代码如下:
#
-*- coding: utf-8 -*-
#
!/usr/bin/python
#
########################################################################
#
File Name: Jenkins_Project_Deploy.py
#
Program function: ueed for deployment code in CI server.
#
Author:Jeson
#
mail:jeson@imoocc.com
#
Created Time: 一 6/20 19:24:33 2016
#
========================================================================
import
ConfigParser
import
sys
from sys import argv
import paramiko
def Gennerate_cmd(Project_Name,CI_IP,Project_Code_File,Project_Exclude_File,Project_Backup_Dir,Project_Deploy_Path,Project_Start_Command,Project_Log_Path):
cmd = []
#生成备份命令if Project_Backup_Dir:
#生成备份原有文件
cmd.append("mkdir -p /opt/")
cmd.append("rsync -avzP %s %s && touch /tmp/CI_%s_backuptrue"%(Project_Deploy_Path,Project_Backup_Dir,Project_Name))
#生成关闭原有进程命令
cmd.append(‘test -e /tmp/CI_%s_backuptrue && ps -auxgrep "name:%s"grep -v grepawk ‘{print $2}‘xargs kill‘%(Project_Name,Project_Name))
#生成命令-确认原来服务已经顺利关闭
cmd.append(‘ps -auxgrep "name:%s"grep -v grepawk ‘{print $2}‘&& touch /tmp/CI_killSucc ps -auxgrep "name:%s"grep -v grepawk ‘{print $2}‘xargs kill -9‘%(Project_Name,Project_Name))
#生成命令-用于同步新的代码文件if Project_Code_File == "":
cmd.append(‘test -e "/tmp/CI_%s_killSucc" && rsync -avzP --delete-after --exclude "{%s}" %s::%s %s‘%(Project_Name,Project_Exclude_File,CI_IP,Project_Name,Project_Deploy_Path))
else:
cmd.append(‘test -e "/tmp/CI_%s_killSucc" && rsync -avzP --delete-after --exclude "{%s}" %s::%s/%s %s‘%(Project_Name,Project_Exclude_File,CI_IP,Project_Name,Project_Code_File,Project_Deploy_Path))
#生成命令-用于启动服务 cmd.append(Project_Start_Command)
#生成命令-查看服务启动后的日志
cmd.append(‘tail -n 200 -f %s‘%Project_Log_Path)
#生成命令-清理此次生成的临时文件# cmd.append(‘rm -f /tmp/*%s*‘%Project_Name)return cmd
def Login_Execute_Command(Project_IP,Project_Login_Port,Project_Login_User,Login_ISA_Key,cmds):
Project_Port = int(Project_Login_Port) if Project_Login_Port else 22
if Project_IP and Project_Login_User and Login_ISA_Key:
key = paramiko.RSAKey.from_private_key_file(Login_ISA_Key)
s = paramiko.SSHClient()
s.load_system_host_keys()
s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
s.connect(hostname=Project_IP,port=Project_Port,username=Project_Login_User,pkey=key)
for cmd_item in cmds:
stdin,stdout,stderr=s.exec_command(cmd_item)
print stdout.read()
return True
else:
return false
def main():
if len(argv) > 2:
Config_File = argv[1] if argv[1] else"./Jenkins_Project_Deploy.conf "
Project_Name = argv[2] if argv[2] else""else:
print"Error 0:Input argv format error! ./Jenkins_Project_Deploy.py ./test.conf testname"
sys.exit()
try:
cf = ConfigParser.ConfigParser()
cf.read(Config_File)
CI_IP = cf.get(Project_Name, "CI_IP")
Project_Code_File = cf.get(Project_Name, "Project_Code_File")
Project_Exclude_File = cf.get(Project_Name, "Project_Exclude_File")
Project_Backup_Dir = cf.get(Project_Name, "Project_Backup_Dir")
Project_Deploy_Path = cf.get(Project_Name, "Project_Deploy_Path")
Project_Start_Command = cf.get(Project_Name, "Project_Start_Command")
Project_Log_Path = cf.get(Project_Name, "Project_Log_Path")
execute_command = Gennerate_cmd(Project_Name,CI_IP,Project_Code_File,Project_Exclude_File,Project_Backup_Dir,Project_Deploy_Path,Project_Start_Command,Project_Log_Path)
print"{Step 1: Command collected over!}",execute_command
Project_IP = cf.get(Project_Name, "Project_IP")
Project_Login_Port = cf.get(Project_Name, "Project_Login_Port")
Project_Login_User = cf.get(Project_Name, "Project_Login_User")
Login_ISA_Key = cf.get(Project_Name, "Login_ISA_Key")
except Exception as e:
print"Error 1: %s file open or read error!"%Config_File
sys.exit()
print"{Step 2:Prepare to loging...}",Project_IP
result = Login_Execute_Command(Project_IP,Project_Login_Port,Project_Login_User,Login_ISA_Key,cmds=execute_command)
if result is False:
print"Error 3:Execute command failed!"if__name__ == ‘__main__‘:
main()
读者须知:
1、本手记本着记续接前面的两张手记内容整理
2、本手记针对tomcat部署测试环境实现
最近工作比较繁忙,导致这章一直拖延,没有太抽出时间来总结。要实现Jenkins端的持续集成,其实在CI服务配置端很容易,难点呢?就是如何实现自动化的部署。我的脚本设计就是为了解决以下难题:
难点一、如何使得自动化部署脚本更通用
我用的脚本,依赖依赖一个配置文件的模块化,让每一个应用业务模块更加通用。自动化所执行的命令呢?
我也是设计想法本着更加通用平台的原则,至少对于tomcat+java or java+socket这种模式通用。
难点二、如何使得自动化的部署简单有效
本脚本,更加切合实际,例:自动化部署关闭tomcat,我们常常会选择catalina.sh
stop去关闭,然而这里我选择了kill的方式,如果检测中没有顺利关闭,我将调用kill -9
去直接关闭。(没办法,选择了通用,你是没遇到过tomcat 一直有线程卡住,关闭不了的情况吧。)
难点三、需要让我们自动化的部署实现高的可靠性
体现在:
1、每一次的部署,配置选项中都会进行备份。(备份只一次)
2、服务自动备份完毕后,需要实现检测(这里我在配置模块中有加入日志终端输出)
当然,这个脚本中还有未完成的地方:
1、服务启动后,自动化的检测机制还是太薄弱。
2、暂时此脚本还无法通用到php,python等环境的更多平台
3、代码备份方式上,应该更加具更多灵活性。
这里,如果你觉得我的脚本可以补充,不如大家一起加入进来(留言、或者邮件我jeson@imoocc.com),我也很想学习学习大家的想法。
一、自动化部署原理图示
1、2、3、4 表示执行的4个部署基础步骤
二、实现
- 1、Tomcat 进程设置唯一标记
用于识别出一个服务器中唯一的Tomcat进程
java -Dmyapp.name=“project_name”
如果用的tomcat我们可以,直接修改启动控制文件catalina.sh。
JAVA_OPTS="-Dmyapp.name:"project_name" -server -Xms1024M -Xmx4096M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=1024M"
- 2、实现自动化登录
一般有两种方式:
方式一、模拟用户密码交互方式,大家可以学习家py中依赖pexcept模块。
方式二、用ssh + Key方式,这个是ssh的一种公钥认证机制。本脚本中用的这种,大家自行学习。
3、CI服务器需要在服务端配置rsync服务端
实现中,主要用于客户端服务拖取代码。
4、配置文件解释
[imoocc.com-server] //服务的模块名称,这里需要注意,需要具有唯一性,且服务的进程标示命名一致
CI_IP=ci.iaskjob.com //CI服务器地址
Login_ISA_Key=/back/key/jeson_iaskjob_rsa //登录ISA的key
Project_IP=192.168.10.99 //工程IP
Project_Login_User=root //对应工程机器登录用户
Project_Login_Port=22 //对应工程机器登录端口
Project_Code_File=/tmp/imoocc //对应工程在CI服务器构建后的执行代码目录
Project_Exclude_File="/var/cache","/var/tmp","jdbc.profile" //不需要向线上同步的文件,如配置文件等等
Project_Backup_Dir=/opt/Jenkins_Backup_Dir //工程备份目录
Project_Deploy_Path=/opt/imoocc //工程部署目录
Project_Start_Command=tomcat/bin/catalina.sh start //工程启动方式
Project_Log_Path=/tmp/imoocc.log //启动后日志的查看方式
分享代码如下:
# -*- coding: utf-8 -*-
#!/usr/bin/python
#########################################################################
# File Name: Jenkins_Project_Deploy.py
# Program function: ueed for deployment code in CI server.
# Author:Jeson
# mail:jeson@imoocc.com
# Created Time: 一 6/20 19:24:33 2016
#========================================================================
import
ConfigParser
import
sys
from
sys
import
argv
import
paramiko
def
Gennerate_cmd
(
Project_Name
,
CI_IP
,
Project_Code_File
,
Project_Exclude_File
,
Project_Backup_Dir
,
Project_Deploy_Path
,
Project_Start_Command
,
Project_Log_Path
):
cmd
=
[]
#生成备份命令
if
Project_Backup_Dir
:
#生成备份原有文件
cmd
.
append
(
"mkdir -p /opt/"
)
cmd
.
append
(
"rsync -avzP %s %s && touch /tmp/CI_%s_backuptrue"
%(
Project_Deploy_Path
,
Project_Backup_Dir
,
Project_Name
))
#生成关闭原有进程命令
cmd
.
append
(
‘test -e /tmp/CI_%s_backuptrue && ps -auxgrep "name:%s"grep -v grepawk ‘{print $2}‘xargs kill‘
%(
Project_Name
,
Project_Name
))
#生成命令-确认原来服务已经顺利关闭
cmd
.
append
(
‘ps -auxgrep "name:%s"grep -v grepawk ‘{print $2}‘&& touch /tmp/CI_killSucc ps -auxgrep "name:%s"grep -v grepawk ‘{print $2}‘xargs kill -9‘
%(
Project_Name
,
Project_Name
))
#生成命令-用于同步新的代码文件
if
Project_Code_File
==
""
:
cmd
.
append
(
‘test -e "/tmp/CI_%s_killSucc" && rsync -avzP --delete-after --exclude "{%s}" %s::%s %s‘
%(
Project_Name
,
Project_Exclude_File
,
CI_IP
,
Project_Name
,
Project_Deploy_Path
))
else
:
cmd
.
append
(
‘test -e "/tmp/CI_%s_killSucc" && rsync -avzP --delete-after --exclude "{%s}" %s::%s/%s %s‘
%(
Project_Name
,
Project_Exclude_File
,
CI_IP
,
Project_Name
,
Project_Code_File
,
Project_Deploy_Path
))
#生成命令-用于启动服务
cmd
.
append
(
Project_Start_Command
)
#生成命令-查看服务启动后的日志
cmd
.
append
(
‘tail -n 200 -f %s‘
%
Project_Log_Path
)
#生成命令-清理此次生成的临时文件
# cmd.append(‘rm -f /tmp/*%s*‘%Project_Name)
return
cmd
def
Login_Execute_Command
(
Project_IP
,
Project_Login_Port
,
Project_Login_User
,
Login_ISA_Key
,
cmds
):
Project_Port
=
int
(
Project_Login_Port
)
if
Project_Login_Port
else
22
if
Project_IP
and
Project_Login_User
and
Login_ISA_Key
:
key
=
paramiko
.
RSAKey
.
from_private_key_file
(
Login_ISA_Key
)
s
=
paramiko
.
SSHClient
()
s
.
load_system_host_keys
()
s
.
set_missing_host_key_policy
(
paramiko
.
AutoAddPolicy
())
s
.
connect
(
hostname
=
Project_IP
,
port
=
Project_Port
,
username
=
Project_Login_User
,
pkey
=
key
)
for
cmd_item
in
cmds
:
stdin
,
stdout
,
stderr
=
s
.
exec_command
(
cmd_item
)
print
stdout
.
read
()
return
True
else
:
return
false
def
main
():
if
len
(
argv
)
>
2
:
Config_File
=
argv
[
1
]
if
argv
[
1
]
else
"./Jenkins_Project_Deploy.conf "
Project_Name
=
argv
[
2
]
if
argv
[
2
]
else
""
else
:
print
"Error 0:Input argv format error! ./Jenkins_Project_Deploy.py ./test.conf testname"
sys
.
exit
()
try
:
cf
=
ConfigParser
.
ConfigParser
()
cf
.
read
(
Config_File
)
CI_IP
=
cf
.
get
(
Project_Name
,
"CI_IP"
)
Project_Code_File
=
cf
.
get
(
Project_Name
,
"Project_Code_File"
)
Project_Exclude_File
=
cf
.
get
(
Project_Name
,
"Project_Exclude_File"
)
Project_Backup_Dir
=
cf
.
get
(
Project_Name
,
"Project_Backup_Dir"
)
Project_Deploy_Path
=
cf
.
get
(
Project_Name
,
"Project_Deploy_Path"
)
Project_Start_Command
=
cf
.
get
(
Project_Name
,
"Project_Start_Command"
)
Project_Log_Path
=
cf
.
get
(
Project_Name
,
"Project_Log_Path"
)
execute_command
=
Gennerate_cmd
(
Project_Name
,
CI_IP
,
Project_Code_File
,
Project_Exclude_File
,
Project_Backup_Dir
,
Project_Deploy_Path
,
Project_Start_Command
,
Project_Log_Path
)
print
"{Step 1: Command collected over!}"
,
execute_command
Project_IP
=
cf
.
get
(
Project_Name
,
"Project_IP"
)
Project_Login_Port
=
cf
.
get
(
Project_Name
,
"Project_Login_Port"
)
Project_Login_User
=
cf
.
get
(
Project_Name
,
"Project_Login_User"
)
Login_ISA_Key
=
cf
.
get
(
Project_Name
,
"Login_ISA_Key"
)
except
Exception
as
e
:
print
"Error 1: %s file open or read error!"
%
Config_File
sys
.
exit
()
print
"{Step 2:Prepare to loging...}"
,
Project_IP
result
=
Login_Execute_Command
(
Project_IP
,
Project_Login_Port
,
Project_Login_User
,
Login_ISA_Key
,
cmds
=
execute_command
)
if
result
is
False
:
print
"Error 3:Execute command failed!"
if
__name__
==
‘__main__‘
:
main
()
相关阅读
-
删除数组中的某个(多个)元素(分别用数组和集合的办法删除)
-
Java中Junit4测试实例
-
Spring+SpringMVC+MyBatis+easyUI整合优化篇(三)代码测试
-
Spring+SpringMVC+MyBatis+easyUI整合优化篇(四)单元测试实例
-
Spring+SpringMVC+MyBatis+easyUI整合优化篇(五)MockMvc服务端的单元测试
添加评论
原文:http://www.cnblogs.com/abc8023/p/8056897.html
【说明】:本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!