转 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 ...
随机推荐
- java--方法重写与重载
方法重写 /*方法重写(一般多用在继承上) 定义:它是指子类和父类的关系,子类重写了父类的方法. 两个方法返回值.方法名.参数列表必须完全一致! 出现原因:在Java中,子类可继承父类中的方法,而不需 ...
- 常用类型转换 一.常用int和string类型转换
常用类型转换 一.常用int类型转换1. int.parse(string) 这个类型只支持string类型 2.double doubleType = Int32.MaxValue + 1; i ...
- EasyuiAPI:布局
一.Panel(面板) 1.通过标签创建: <div id="p" class="easyui-panel" title="My Panel&q ...
- 关于Unity项目中创建项目遇到的一些问题
1.Unity调用Android的方法默认不是在UI线程执行,所以在Android上写一些页面的重绘的方法,让Unity去调用时,注意要在Android中添加对应的runOnUiThread才可以: ...
- POJ 1042 Gone Fishing#贪心
(- ̄▽ ̄)-* #include<iostream> #include<cstdio> #include<cstring> using namespace std ...
- openwrt的uboot环境变量分析
目前烧写完CC(chaos calmer 15.05)版本,查看其uboot变量如下: ath> printenvbootargs=console=ttyS0,115200 root=31:02 ...
- 洛谷-火柴棒等式-NOIP2008提高组复赛
题目描述 Description 给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A.B.C是用火柴棍拼出的整数(若该数非零,则最高位不能是0).用火柴棍拼数字0-9的拼法如图所示: ...
- wc的用法
wc -c filename:显示一个文件的字节数 wc -m filename:显示一个文件的字符数 wc -l filename:显示一个文件的行数 wc -L filename:显示一个文件中的 ...
- qq昵称由fly改为思诺
刚才,把高三申请的qq号,昵称fly 改为 思诺,英文名称为saynoer,say+no+er, 意思你懂的.
- js对象,类
js闭包网站:http://www.cnblogs.com/qieguo/p/5457040.html 有权访问另一个函数作用域内变量的函数都是闭包. 这里 inc 函数访问了构造函数 a 里面的变量 ...

