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

相關文章
相關標籤/搜索