转 Apache Ant 实现自动化部署
Apache Ant 实现自动化部署
http://www.netkiller.cn/journal/java.ant.html
Mr. Neo Chen (陈景峯), netkiller, BG7NYT
版权声明
转载请与作者联系,转载时请务必标明文章原始出处和作者信息及本声明。
|
|
|
微信扫描二维码进入 Netkiller 微信订阅号 群:128659835 请注明“读者” |
2015-12-10
源码获取,源码编译,处理配置文件,应用部署,远程备份,部署回撤,启动,服务器状态,停止
编程语言
操作系统
Netkiller Database 手札 | Netkiller PostgreSQL 手札 | Netkiller MySQL 手札 | Netkiller NoSQL 手札 | Netkiller LDAP 手札 |
网络设备及其他
Netkiller Network 手札 | Netkiller Cisco IOS 手札 | Netkiller H3C 手札 | Netkiller Amateur Radio 手札 |
您可以使用iBook阅读当前文档
1. 背景
在你的企业中是怎样完成从开发,测试到运维的?
很多企业的升级是这样做的,写完代码后编译打包,放到FTP上,同时发送一个升级邮件。然后让运维按照升级文档,一步一步操作。
这样的流程有很多问题
开发者通常是在Windows系统上完成开发与编译,而服务器通常是Linux操作系统,操作系统的差异可能导致编译后的程序运行不了。
安全角度,源码可以审查,但编译文件无法审查,打包过程可能被植入恶意代码
经常出现生产环境与本地开发环境不一致,运行有差异
浪费人力,理论上代码写完,就跟开发人员一点关系都没有了,但实际上每次升级过程开发与测试都需要在场
稍先进一点做法是使用Subversion/Git,开发将代码放到版本库中,运维直接使用 svn up / git pull 升级,这样做法也有很多问题存在
- 首次升级非常慢,svn 还好些,svn只取最后一次提交的版本;git 将所有的版本克隆到本地。
- 如果修改了本地文件,更新会产生冲突
- 配置文件无法个性化配置
2. 我们需要什么样的流程
我们需要什么样的流程或者什么样的流程才是最理想流程?
开发人员不要做与开发无关的事情,代码写完就与开发没有半点关系了。通知测试人员,代码已经完成。
测试人员自己部署测试环境,不依赖开发人员,测试完成,通知运维人员可能升级了
运维人员不接受任何部门提供的打包或补丁程序,代码只能在配置管理服务器上完成编译打包以及部署。
升级应该由自动化工具完成,而不是人工操作。
开发,测试,运维各司其职,这就是DevOps。
3. 怎样实现自动部署
实现自动化部署有很多方法,很多年前笔者就开始研究总结,下面是一些经验分享。
3.1. 操作系统
开发,测试,生产三个环境的配置如果出自同一个模板会减少很多由于环境差异带来的困扰。
无人值守安装
通过无人值守脚本安装操作系统,减少人为安装造成的差异
运行环境
统一配置运行环境,开发库以及版本统一
应用服务器统一
应用服务器版本,安装标准,配置文件都需要统一,减少差异
3.2. 程序部署
实现应用程序自动部署,首先你要清楚自动部署所需要的流程,部署一个流程通常是这样的:
初始化
建立工作环境,例如目录,检查所需环境
获取
从版本库指定分支中获取代码并保存到本地
编译
编译可执行代码
配置
处理配置文件
备份
备份应用程序
停止
服务服务
部署
部署应用程序到目的主机,如果已存在需要覆盖原来的程序
启动
启动服务
3.3. 自动部署程序
自动部署程序完成上面的部署,还需要做下面一些事情。
- 记录什么时间点做过部署
- 部署了那些文件
4. Apache Ant 实现自动化部署
4.1. 运行环境
准备一个全新的的服务器,最小化安装CentOS 7操作系统,然后运行下面脚本初始化
curl -s https://raw.githubusercontent.com/oscm/shell/master/os/centos7.sh | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/os/selinux.sh | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/os/iptables/iptables.sh | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/os/ntpd/ntp.sh | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/os/ssh/sshd_config.sh | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/os/user/www.sh | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/gcc/gcc.sh | bash
安装 server-jre 与 apache-tomcat
curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/java/server-jre-8u40.sh | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/web/tomcat/apache-tomcat-8.0.26.sh | bash
curl -s https://raw.githubusercontent.com/oscm/shell/master/web/tomcat/systemctl.sh | bash
请使用systemctl 启动与停止 Tomcat
systemctl start tomcat
systemctl stop tomcat
Infrastructure Management Shell https://github.com/oscm/shell
4.2. 部署机
安装Ant
curl -s https://raw.githubusercontent.com/oscm/shell/master/lang/java/ant.sh | bash
下载build.xml文件 https://github.com/oscm/build/tree/master/Ant
wget https://raw.githubusercontent.com/oscm/build/master/Ant/build.xml
打开 build.xml 文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Homepage: http://www.netkiller.cn
Author: neo <netkiller@msn.com>
Date: 2015-12-07
-->
<project name="admin.example.com" default="compile" basedir="."> <property name="repository" value="git@58.96.11.18:example.com/admin.example.com.git" />
<property name="branch" value="master" /> <property name="remote" value="www@23.25.22.72" />
<property name="destination" value="/www/example.com/admin.example.com" /> <property name="project.dir" value="repository" />
<property name="project.src" value="${project.dir}/src" />
<property name="project.build" value="build" />
<property name="project.config" value="config" />
<property name="project.log" value="log" /> <property name="pkg" value="example-1.0.0.jar" /> <property name="backup.dir" value="backup" />
<property name="receive.timepoint" value="2015-12-04.17:46:35" /> <property name="build.sysclasspath" value="last" />
<property environment="env" />
<echo message="JAVA_HOME is set to = ${env.JAVA_HOME}" />
<echo message="CATALINA_HOME is set to = ${env.CATALINA_HOME}" /> <path id="classpath">
<fileset dir="${env.JAVA_HOME}/lib">
<include name="*.jar" />
</fileset>
<fileset dir="${env.CATALINA_HOME}/lib">
<include name="*.jar" />
</fileset>
<fileset dir="${project.dir}/WebRoot/WEB-INF/lib" includes="*.jar" />
</path> <macrodef name="git">
<attribute name="command" />
<attribute name="dir" default="" />
<element name="args" optional="true" />
<sequential>
<!-- echo message="git @{command}" / -->
<exec executable="git" dir="@{dir}">
<arg value="@{command}" />
<args />
</exec>
</sequential>
</macrodef> <macrodef name="rsync">
<attribute name="option" default="auzv" />
<attribute name="src" default="" />
<attribute name="dest" default="" />
<element name="args" optional="true" />
<sequential>
<!-- echo message="rsync @{option} ${src} ${dest}" / -->
<exec executable="rsync">
<arg value="@{option}" />
<args />
<arg value="@{src}" />
<arg value="@{dest}" />
</exec>
</sequential>
</macrodef> <macrodef name="ssh">
<attribute name="host" />
<attribute name="command" />
<attribute name="keyfile" default="~/.ssh/id_rsa" />
<element name="args" optional="true" />
<sequential>
<exec executable="ssh">
<arg value="@{host}" />
<!-- arg value="-i @{keyfile}" / -->
<args />
<arg value="@{command}" />
</exec>
</sequential>
</macrodef> <target name="dir.check">
<condition property="dir.exists">
<available file="${project.dir}" type="dir" />
</condition>
</target> <target name="clone" depends="dir.check" unless="dir.exists">
<echo>clone</echo>
<git command="clone">
<args>
<arg value="${repository}" />
<arg value="${project.dir}" />
</args>
</git>
</target> <target name="pull" depends="clone" if="dir.exists">
<echo>${project.dir} exists</echo>
<git command="pull" dir="${project.dir}" />
<git command="clean" dir="${project.dir}">
<args>
<arg value="-df" />
</args>
</git> <git command="reset" dir="${project.dir}">
<args>
<arg value="HEAD" />
<arg value="--hard" />
</args>
</git>
</target> <target name="branch" depends="pull" if="dir.exists">
<echo>${project.dir} exists</echo>
<git command="checkout" dir="${project.dir}">
<args>
<arg value="-f" />
<arg value="${branch}" />
</args>
</git>
</target> <target name="init" depends="branch"> <mkdir dir="${project.build}" />
<mkdir dir="${project.log}" /> <copy todir="${project.build}">
<fileset dir="${project.dir}/WebRoot" includes="**/*" />
</copy> <copy todir="${project.build}/WEB-INF/classes">
<fileset dir="${project.src}">
<include name="**/*.xml" />
<include name="**/*.properties" />
</fileset>
</copy> </target>
<target name="compile" depends="init">
<javac srcdir="${project.src}" destdir="${project.build}/WEB-INF/classes">
<classpath refid="classpath" />
</javac>
</target> <target name="config" depends="compile">
<copy todir="${project.build}" overwrite="true">
<fileset dir="${project.config}" includes="**/*" />
</copy>
</target> <target name="deploy" depends="config">
<tstamp>
<format property="timepoint" pattern="yyyy-MM-dd.HH:mm:ss" locale="cn,CN" />
</tstamp>
<rsync option="-auzv" src="${project.build}/" dest="${remote}:${destination}">
<args>
<arg value="--exclude=.git" />
<arg value="--exclude=.svn" />
<arg value="--exclude=.gitignore" />
<arg value="--backup" />
<arg value="--backup-dir=~/${backup.dir}/${timepoint}" />
<arg value="--log-file=log/${ant.project.name}.${timepoint}.log" />
</args>
</rsync>
</target> <target name="pkg" depends="compile">
<jar jarfile="${pkg}" basedir="${project.build}" />
</target> <target name="backup" depends="">
<tstamp>
<format property="TIMEPOINT" pattern="yyyy-MM-dd.HH:mm:ss" locale="cn,CN" />
</tstamp>
<echo>the backup directory is ${TIMEPOINT}.</echo>
<mkdir dir="${backup.dir}/${TIMEPOINT}" />
<rsync option="-auzv" src="${remote}:${destination}" dest="${backup.dir}/${TIMEPOINT}">
</rsync>
</target> <target name="receive" depends="">
<echo>the receive directory is ${receive.timepoint}.</echo>
<rsync option="-auzv" src="${backup.dir}/${receive.timepoint}" dest="${remote}:${destination}" />
</target> <target name="fetch">
<ant target="pull" />
<ant target="branch" />
</target> <target name="stop" depends="">
<!-- ssh host="${remote}" command="/srv/apache-tomcat/bin/catalina.sh stop -force" keyfile="~/.ssh/id_rsa" / -->
<ssh host="${remote}" command="/srv/apache-tomcat/bin/shutdown.sh" />
<ant target="status" />
</target>
<target name="start" depends="">
<ssh host="${remote}" command="/srv/apache-tomcat/bin/startup.sh" keyfile="~/.ssh/id_rsa" />
<ant target="status" />
</target>
<target name="status" depends="">
<ssh host="${remote}" command="ps ax | grep tomcat | grep -v grep" />
</target>
<target name="kill" depends="">
<ssh host="${remote}" command="pkill -9 -f tomcat" />
<ant target="status" />
</target>
<target name="run" depends="">
<java classname="test.ant.HelloWorld" classpath="${hello}" />
</target>
<target name="clean">
<delete dir="${project.build}" />
<delete file="${hello}" />
</target>
</project>
修改下面几处定义
<property name="repository" value="版本库地址" />
<property name="branch" value="部署分支" />
<property name="remote" value="远程服务器" />
<property name="destination" value="远程目录" />
开始部署代码
ant backup
ant stop
ant deploy
ant start
5. 延伸阅读
如果你想学习制作部署工具,还可以看看笔者早期的作品https://github.com/oscm/deployment这个工具使用Bash开发,写这个工具仅仅半天时间,后面小改过几次,这个工具伴随笔者很多年。
第一个版本因为很多缺陷存在,笔者使用Python重新开发 https://github.com/oscm/devops 这个工具更适合PHP项目部署
转 Apache Ant 实现自动化部署的更多相关文章
- Jenkins+Ant/maven+Svn实现自动化部署,编译,运行,测试结果自动邮件通知
Jenkins+Ant+Svn实现自动化部署,编译,运行,测试结果自动邮件通知
- Apache Ant 项目构建
项目构建:通过构建工具对多个项目进行统一批量的编译和运行,比如,对多个Jmeter脚本批量运行 1.Ant是什么? Ant是 构建工具,Apache Ant是一个将软件编译.测试.部署等步骤联系在一起 ...
- [Java] Apache Ant 构建基础教程
环境:Ubuntu 12.04, java 1.7.0, ant 1.8.2. 前言 Apache Ant 是一个软件自动化构建工具,构建过程包括编译.测试和部署等.它和 Make 工具相似,但由 J ...
- Jmeter(二十七)Jmeter Question 之“集成Ant+Jenkins自动化”
首先介绍一下Ant.Apache Ant,是一个将软件编译.测试.部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发.由Apache软件基金会所提供. 是的.还是Apache家 ...
- Jenkins+Ant+Jmeter自动化集成测试实例
通过学习Jmeter自动化测试,接触到了Ant命令和其构建文件build.xml文件的编写,与此同时,通过将测试项目集成在jenkins上,进一步学习了jenkins的一些环境配置知识.以下是自己的初 ...
- Jmeter Question 之“集成Ant+Jenkins自动化”
首先介绍一下Ant.Apache Ant,是一个将软件编译.测试.部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发.由Apache软件基金会所提供. 是的.还是Apache家 ...
- Jenkins自动化部署最完整教程
1.概述 Jenkins 是一个可扩展的持续集成引擎.主要用于持续.自动地构建/测试软件项目.监控一些定时执行的任务.Jenkins用Java语言编写,可在Tomcat等流行的servlet容器中运行 ...
- jenkins+git+maven搭建自动化部署项目环境
简介 折腾了两个晚上,趁着今晚比较有空,把jenkins+git+maven搭建自动化部署项目环境搭建的过程记录一下,这里我把github作为git的远程仓库(https://github.co ...
- LTMP手动编译安装以及全自动化部署实践(附详细代码)
大家使用LNMP架构,一般可以理解为Linux Shell为CentOS/RadHat/Fedora/Debian/Ubuntu/等平台安装LNMP(Nginx/MySQL /PHP),LNMPA(N ...
随机推荐
- CSS3秘笈复习:第十一章
1.text-align与vertical-align: text-align控制水平方向的定位,关键字是left.right.center和justify. vertical-align控制垂直方向 ...
- Python虚拟环境的配置
Python中,配置虚拟环境主要是为了防止版本之间的冲突,我是这么理解的: 1.用虚拟环境可以在一个电脑中使用多个Python解释器以及扩展: 2.可以方便的在同一台电脑中使用多个版本的代码. 虚拟环 ...
- Angular2,React集成
https://www.packtpub.com/books/content/integrating-angular-2-react http://www.syntaxsuccess.com/view ...
- 使 httpClient 支持中文
一个有效的方法:重载 PostMethod 的 getRequestCharSet 方法 1: class PostChinese { 2: HttpClient httpClient = new H ...
- Python 拆分字符串
数:split() Python中有split()和os.path.split()两个函数,具体作用如下:split():拆分字符串.通过指定分隔符对字符串进行切片,并返回分割后的字符串列表(list ...
- C - 小Y上学记——认识新同学
C - 小Y上学记——认识新同学 Time Limit: 4000/2000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) ...
- Meta标签中的属性及含义
一.Meta标签中的format-detection属性及含义 format-detection翻译成中文的意思是“格式检测”,顾名思义,它是用来检测html里的一些格式的,那关于meta的forma ...
- SpringMvc+thymeleaf+HTML5中文乱码问题
SpringMvc+thymeleaf+HTML5环境下遇到中文乱码...... 按照以往经验逐个排查,开发环境统一为utf-8编码,服务器也配置了编码过滤器,tomcat也是utf-8编码.前台页面 ...
- 浅谈C/C++引用和指针的联系和区别
为什么C/C++语言使用指针? 答案:①一方面,每一种编程语言都使用指针.不止C/C++使用指针. 每一种编程语言都使用指针.C++将指针暴露给了用户(程序员),而Java和C#等语言则将指针隐藏起来 ...
- Elasticsearch Java虚拟机配置详解(转)
引言: 今天,事情终于发生了.Java6(Mustang),是2006年早些时候出来的,至今仍然应用在众多生产环境中,现在终于走到了尽头.已经没有什么理由阻止迁移到Java7(Dolphin)上了. ...