转 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 ...
随机推荐
- Struts2-1.配置&与第一个应用
配置流程 1.web项目中导入Strus2应用需要的包,复制到项目的lib文件夹下 点击此处下载需要的包,解压后复制进去即可:http://pan.baidu.com/s/1jHhjd2Y 2.编写S ...
- iOS开发下架在AppStore中销售的app
1.登陆开发者账号 2.选择itunes connect 选择我的app 3.选择要下架的app 4.价格与销售范围 5.销售范围 6.点击存储 //如果想要重新在AppStore中进行销售只需要选择 ...
- c#笔记之启动新线程
可已通过下面方法来启动一个新线程并执行相应的方法 new Thread(new ThreadStart(new Action(() => { ...
- HDU 1017 A Mathematical Curiosity(枚举)
题目链接 Problem Description Given two integers n and m, count the number of pairs of integers (a,b) suc ...
- [ An Ac a Day ^_^ ] FZU 2030 括号问题 搜索
FZU一直交不上去 先写在这吧 #include<stdio.h> #include<iostream> #include<algorithm> #include& ...
- GetLastError() 返回值含义
[0]-操作成功完成.[1]-功能错误.[2]-系统找不到指定的文件.[3]-系统找不到指定的路径.[4]-系统无法打开文件.[5]-拒绝访问.[6]-句柄无效.[7]-存储控制块被损坏.[8]-存储 ...
- ***1133. Fibonacci Sequence(斐波那契数列,二分,数论)
1133. Fibonacci Sequence Time limit: 1.0 secondMemory limit: 64 MB is an infinite sequence of intege ...
- Python 学习笔记7
今天很残酷,明天很残酷,后天很美好.但绝大多数人会死在明天的路上.只有真正的勇士才能看到后天的太阳! Python学习是枯燥的.但是一定要坚持! 昨天学习了数据结构和模块. 今天学习输入和输出.错误与 ...
- 解决curl中errno为51和60的错误
今天使用curl调用https接口的时候,发现接收不了数据 然后打印出curl_errno和curl_error发现是60错误,而生产环境是51错误 查了相关资料 加上两个参数就可以了 curl_se ...
- Mysql CPU占用高的问题解决方法小结
通过以前对mysql的操作经验,先将mysql的配置问题排除了,查看msyql是否运行正常,通过查看mysql data目录里面的*.err文件(将扩展名改为.txt)记事本查看即可.如果过大不建议用 ...

