Apache Ant 实现自动化部署

Apache Ant 实现自动化部署

http://www.netkiller.cn/journal/java.ant.html

MrNeo Chen (陈景峯)netkiller, BG7NYT


中国广东省深圳市龙华新区民治街道溪山美地
518131
+86 13113668890

<netkiller@msn.com> html

版权声明 java

转载请与做者联系,转载时请务必标明文章原始出处和做者信息及本声明。 linux

文档出处:
http://netkiller.github.io
http://netkiller.sourceforge.net

微信扫描二维码进入 Netkiller 微信订阅号 git

QQ群:128659835 请注明“读者” github

2015-12-10 web

这篇文章帮你解决下列问题:

源码获取,源码编译,处理配置文件,应用部署,远程备份,部署回撤,启动,服务器状态,中止 shell


1. 背景

在你的企业中是怎样完成从开发,测试到运维的? apache

不少企业的升级是这样作的,写完代码后编译打包,放到FTP上,同时发送一个升级邮件。而后让运维按照升级文档,一步一步操做。 centos

这样的流程有不少问题 tomcat

  1. 开发者一般是在Windows系统上完成开发与编译,而服务器一般是Linux操做系统,操做系统的差别可能致使编译后的程序运行不了。

  2. 安全角度,源码能够审查,但编译文件没法审查,打包过程可能被植入恶意代码

  3. 常常出现生产环境与本地开发环境不一致,运行有差别

  4. 浪费人力,理论上代码写完,就跟开发人员一点关系都没有了,但实际上每次升级过程开发与测试都须要在场

稍先进一点作法是使用Subversion/Git,开发将代码放到版本库中,运维直接使用 svn up / git pull 升级,这样作法也有不少问题存在

  1. 首次升级很是慢,svn 还好些,svn只取最后一次提交的版本;git 将全部的版本克隆到本地。
  2. 若是修改了本地文件,更新会产生冲突
  3. 配置文件没法个性化配置

2. 咱们须要什么样的流程

咱们须要什么样的流程或者什么样的流程才是最理想流程?

我认为:
  1. 开发人员不要作与开发无关的事情,代码写完就与开发没有半点关系了。通知测试人员,代码已经完成。

  2. 测试人员本身部署测试环境,不依赖开发人员,测试完成,通知运维人员可能升级了

  3. 运维人员不接受任何部门提供的打包或补丁程序,代码只能在配置管理服务器上完成编译打包以及部署。

  4. 升级应该由自动化工具完成,而不是人工操做。

开发,测试,运维各司其职,这就是DevOps。

3. 怎样实现自动部署

实现自动化部署有不少方法,不少年前笔者就开始研究总结,下面是一些经验分享。

3.1. 操做系统

开发,测试,生产三个环境的配置若是出自同一个模板会减小不少因为环境差别带来的困扰。

过程 1. 操做系统部署
  1. 无人值守安装

    经过无人值守脚本安装操做系统,减小人为安装形成的差别

  2. 运行环境

    统一配置运行环境,开发库以及版本统一

  3. 应用服务器统一

    应用服务器版本,安装标准,配置文件都须要统一,减小差别

3.2. 程序部署

实现应用程序自动部署,首先你要清楚自动部署所须要的流程,部署一个流程一般是这样的:

过程 2. 自动部署步骤
  1. 初始化

    创建工做环境,例如目录,检查所需环境

  2. 获取

    从版本库指定分支中获取代码并保存到本地

  3. 编译

    编译可执行代码

  4. 配置

    处理配置文件

  5. 备份

    备份应用程序

  6. 中止

    服务服务

  7. 部署

    部署应用程序到目的主机,若是已存在须要覆盖原来的程序

  8. 启动

    启动服务

3.3. 自动部署程序

自动部署程序完成上面的部署,还须要作下面一些事情。

日志功能
  1. 记录什么时间点作过部署
  2. 部署了那些文件

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项目部署

相关文章
相关标签/搜索