版權聲明
轉載請與作者聯繫,轉載時請務必標明文章原始出處和作者信息及本聲明。
|
|
|
微信掃瞄二維碼進入 Netkiller 微信訂閲號 QQ群:128659835 請註明“讀者” |
2015-11-10
源碼獲取,源碼編譯,處理配置檔案,應用部署,遠程備份,部署回撤,啟動,伺服器狀態,停止
在你的企業中是怎樣完成從開發,測試到運維的?
很多企業的升級是這樣做的,寫完代碼後編譯打包,放到FTP上,同時發送一個升級郵件。然後讓運維按照升級文檔,一步一步操作。
這樣的流程有很多問題
開發者通常是在Windows系統上完成開發與編譯,而伺服器通常是Linux操作系統,操作系統的差異可能導致編譯後的程序運行不了。
安全形度,源碼可以審查,但編譯檔案無法審查,打包過程可能被植入惡意代碼
經常出現生產環境與本地開發環境不一致,運行有差異
浪費人力,理論上代碼寫完,就跟開發人員一點關係都沒有了,但實際上每次升級過程開發與測試都需要在場
稍先進一點做法是使用Subversion/Git,開發將代碼放到版本庫中,運維直接使用 svn up / git pull 升級,這樣做法也有很多問題存在
我們需要什麼樣的流程或者什麼樣的流程才是最理想流程?
開發人員不要做與開發無關的事情,代碼寫完就與開發沒有半點關係了。通知測試人員,代碼已經完成。
測試人員自己部署測試環境,不依賴開發人員,測試完成,通知運維人員可能升級了
運維人員不接受任何部門提供的打包或補丁程序,代碼只能在配置管理伺服器上完成編譯打包以及部署。
升級應該由自動化工具完成,而不是人工操作。
開發,測試,運維各司其職,這就是DevOps。
實現自動化部署有很多方法,很多年前筆者就開始研究總結,下面是一些經驗分享。
開發,測試,生產三個環境的配置如果出自同一個模板會減少很多由於環境差異帶來的困擾。
無人值守安裝
通過無人值守腳本安裝操作系統,減少人為安裝造成的差異
運行環境
統一配置運行環境,開發庫以及版本統一
應用伺服器統一
應用伺服器版本,安裝標準,配置檔案都需要統一,減少差異
實現應用程序自動部署,首先你要清楚自動部署所需要的流程,部署一個流程通常是這樣的:
初始化
建立工作環境,例如目錄,檢查所需環境
獲取
從版本庫指定分支中獲取代碼並保存到本地
編譯
編譯可執行代碼
配置
處理配置檔案
備份
備份應用程序
停止
服務服務
部署
部署應用程序到目的主機,如果已存在需要覆蓋原來的程序
啟動
啟動服務
自動部署程序完成上面的部署,還需要做下面一些事情。
準備一個全新的的伺服器,最小化安裝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
安裝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
如果你想學習製作部署工具,還可以看看筆者早期的作品https://github.com/oscm/deployment這個工具使用Bash開發,寫這個工具僅僅半天時間,後面小改過幾次,這個工具伴隨筆者很多年。
第一個版本因為很多缺陷存在,筆者使用Python重新開發 https://github.com/oscm/devops 這個工具更適合PHP項目部署
筆者微信公眾號,QQ群:128659835 請註明“讀者”
![]() |