一、Tomcat部署的場景分析
通常,我們對tomcat部署需求可以分為幾種:單例項單應用,單例項多應用,多例項單應用,多例項多應用。
對於第一種場景,如果不要求週期性地維護tomcat版本,一般的做法是把打好的war包丟到webapps目錄下,然後執行startup.sh指令碼,並且可以在瀏覽器裡訪問就行了。
對於第二種場景,是把多個應用程式的war包放在同一個tomcat的webapps目錄,這樣一來,關閉和啟動tomcat會影響所有專案。
對於第三種場景,各個tomcat都執行同一個應用程式,對應地需要修改不同的監聽埠,這種方式通常會和apache httpd或者nginx整合使用,做一些負載均衡的處理。
對於第四種場景相當於第一種場景的複數形式,除了修改不同的監聽埠,沒有本質區別。
一般來說,多例項部署tomcat,可以充分利用系統資源,不過這種方式,也有幾個方面需要考慮:
- 多例項tomcat的更新維護,例如對tomcat進行升級等操作,我們需要考慮如何能“優雅”地對所有例項進行升級
- 儘量不要影響應用程式,在更新tomcat時,一不小心就把conf目錄等全部覆蓋,所以儘量要把配置檔案和安裝目錄隔離
- 對於單應用來說,如果將war包分別置於各個tomcat的webapps目錄,那麼在釋出新版本的war時,可能會出現某個例項更新失敗,導致使用者在訪問時可能會訪問到不同版本的web app,因此,比較好的方式就是所有tomcat例項都統一指向同一個應用程式
本文重點闡述多例項應用的部署方案,但是為了解決上述幾個問題,我們需要先來了解一下tomcat的一些基本情況
二、基本要點
2.1 分離目錄
首先來看一下tomcat的目錄結構,一個剛解壓出來的tomcat打包檔案應該有以下幾個目錄
bin | 主要存放指令碼檔案,例如比較常用的windows和linux系統中啟動和關閉指令碼 |
conf | 主要存放配置檔案,其中最重要的兩個配置檔案是server.xml和web.xml |
lib | 主要存放tomcat執行所依賴的包 |
logs | 主要存放執行時產生的日誌檔案,例如catalina.{date}.log等 |
temp | 存放tomcat執行時產生的臨時檔案,例如開啟了hibernate快取的應用程式,會在該目錄下生成一些檔案 |
webapps | 部署web應用程式的預設目錄 |
work | 主要存放由JSP檔案生成的servlet(java檔案以及最終編譯生成的class檔案) |
再介紹兩個tomcat中比較重要的概念(通常也是兩個系統變數)——CATALINA_HOME和CATALINA_BASE:
- CATALINA_HOME:即指向Tomcat安裝路徑的系統變數
- CATALINA_BASE:即指向活躍配置路徑的系統變數
通過設定這兩個變數,就可以將tomcat的安裝目錄和工作目錄分離,從而實現tomcat多例項的部署。
Tomcat官方文件指出,CATALINA_HOME路徑的路徑下只需要包含bin和lib目錄,這也就是支援tomcat軟體執行的目錄,而CATALINA_BASE設定的路徑可以包括上述所有目錄,不過其中bin和lib目錄並不是必需的,預設時會使用CATALINA_HOME中的bin和conf。如此,我們就可以使用一個tomcat安裝目錄部署多個tomcat例項,這樣的好處在於方便升級,就可以在不影響tomcat例項的前提下,替換掉CATALINA_HOME指定的tomcat安裝目錄。
2.2 修改server.xml
這裡不詳細分析server.xml中每一個配置項,網上也有很多這方面的文件。下面主要說明監聽埠和Host的配置內容。
在server.xml中配置了四個監聽埠,分別是:
- Server Port:該埠用於監聽關閉tomcat的shutdown命令,預設為8005
- Connector Port:該埠用於監聽HTTP的請求,預設為8080
- AJP Port:該埠用於監聽AJP( Apache JServ Protocol )協議上的請求,通常用於整合Apache Server等其他HTTP伺服器,預設為8009
- Redirect Port:重定向埠,出現在Connector配置中,如果該Connector僅支援非SSL的普通http請求,那麼該埠會把https的請求轉發到這個Redirect Port指定的埠,預設為8443
可見,如果不是使用AJP協議連線tomcat,只需要保證多例項中的Server Port和Connect Port不同即可。
再來說Host配置,Host就是所謂的虛擬主機,對應包含了一個或者多個web應用程式,預設的Host配置如下
1 |
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> |
其中:
- name: 虛擬主機的名稱,一臺主機表示了完全限定的域名或IP地址,預設為localhost,同時也是唯一的host,進入tomcat的所有http請求都會對映到該主機上
- appBase:web應用程式目錄的路徑,可以是CATALINA_HOME的相對路徑,也可以寫成絕對路徑,預設情況下為$CATALINA_HOME/webapps
- unpackWARs: 表示是否自動解壓war包
- autoDeploy:所謂的熱部署,即在tomcat正在執行的情況下,如果有新的war加入,則會立即執行部署操作
- 另外再介紹一個Host中的屬性—deployOnStartup:表示tomcat啟動時是否自動部署appBase目錄下所有的Web應用程式,預設為true。這個屬性和autoDeploy會產生兩次部署的“副作用”:一次是tomcat啟動時就開始部署,第二次就是autoDeploy引起的熱部署。因此最好將autoDeploy置為false
在部署多例項單應用的時候,預設的$CATALINA/webapps會因為tomcat安裝目錄升級產生不必要的麻煩,我們考慮將appBase的目錄統一到另外的路徑下。
最後再說明一下Context的配置,它出現在Host配置內,一個Context的配置就代表了一個web應用程式,如果配置多應用程式,就需要在Host下配置多個Context,一個簡單的Context配置如下
1 |
<Context path="/some" docBase="someapp.war" > |
其中:
- path:表示訪問入口,例如,path=”/abc”,則訪問localhost:8080/abc時,就可以訪問該Context對應的應用程式。如果path=””,則直接用localhost:8080就可以訪問
- docBase:表示應用程式的解包目錄或者war檔案路徑,是Host的appBase配置目錄的相對路徑,也可以是直接寫成絕對路徑,但是不要將appBase的值,作為docBase配置路徑的字首,例如appBase=”somedir”,docBase=”somedir-someapp.war”,這樣的配置會導致部署錯誤
通過配置Host的appBase和Context的docBase兩個屬性,可以將應用程式的檔案和tomcat相關的目錄進行分離,這樣webapps目錄也就沒有作用了。
最終我們可以得到多例項單應用部署方案的整體框架:
三、方案實施
現在假設我們有一臺已經配置好Java環境的伺服器:
1 2 3 4 5 6 7 8 |
# export JAVA_HOME=/application/jdk # export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH # export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar # java -version java version "1.8.0_101" Java(TM) SE Runtime Environment (build 1.8.0_101-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode) |
另外假設一個完好的可以執行的web應用程式已經打包成some.war,放在/data/www目錄下,其中包含一個簡單的index.jsp
XHTML
1 2 3 4 5 |
<html> <body> <h2>Hello World!</h2> </body> </html> |
3.1 下載並解壓tomcat
1 2 3 4 5 |
# cd /usr/local # wget -q http://mirrors.cnnic.cn/apache/tomcat/tomcat-7/v7.0.72/bin/apache-tomcat-7.0.72.tar.gz # tar zxf apache-tomcat-7.0.72.tar.gz # ls apache-tomcat-7.0.72 bin conf lib LICENSE logs NOTICE RELEASE-NOTES RUNNING.txt temp webapps work |
3.2 配置tomcat多例項
可以用一小段指令碼來完成批量建立的工作
1 2 3 4 5 6 7 8 9 10 11 |
for ((i=1;i<=3;i++)) do mkdir /application/tomcat7-$i/{work,temp,conf,logs} -p cp -a /application/tomcat7-$i/application/tomcat7-$i && sed -i 22s@8005@80${i}5@ /application/tomcat7-$i/conf/server.xml // 修改tomcat關閉埠 sed -i 71s@8080@808${i}@ /application/tomcat7-$i/conf/server.xml // 修改Http監聽埠 sed -i 93s@8009@80${i}9@ /application/tomcat7-$i/conf/server.xml // 修改AJP埠 sed -i '125s@appBase="webapps"@appBase="/data/www"@' /application/tomcat7-$i/conf/server.xml //統一web應用程式的路徑 sed -i '126s@autoDeploy="true"@autoDeploy="false"@' /application/tomcat7-$i/conf/server.xml //關閉自動部署 sed -i '126a ' /application/tomcat7-$i/conf/server.xml //配置Context資訊,指向some.war的路徑 done |
3.3 建立啟停指令碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#!/bin/sh CUR_DIR=`dirname $BASH_SOURCE` export JAVA_HOME="/application/jdk" export CATALINA_BASE=`readlink -f $CUR_DIR` export CATALINA_HOME="/usr/local/apache-tomcat-7.0.72" case $1 in start) [-f$CATALINA_HOME/bin/startup.sh]&&$CATALINA_HOME/bin/startup.sh ;; stop) [-f$CATALINA_HOME/bin/shutdown.sh]&&$CATALINA_HOME/bin/shutdown.sh ;; restart) [-f$CATALINA_HOME/bin/shutdown.sh]&&$CATALINA_HOME/bin/shutdown.sh&& [-f$CATALINA_HOME/bin/startup.sh]&&$CATALINA_HOME/bin/startup.sh ;; *) echo"usage : $0 { start | stop | restart }" return1; ;; esac return 0 |
把該指令碼放在tomcat7-1,tomcat7-2和tomcat7-3目錄下
現在我們的目錄結構如下
1 2 3 4 5 6 7 8 9 |
# ls tomcat7-1 tomcat7-2 tomcat7-3 tomcat7-1: conf logs temp tomcat.sh work tomcat7-2: conf logs temp tomcat.sh work tomcat7-3: conf logs temp tomcat.sh work |
3.4 啟動tomcats
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# cd /application # . tomcat7-1/tomcat.sh start # . tomcat7-2/tomcat.sh start # . tomcat7-3/tomcat.sh start # netstat -tunlp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 25757/sshd tcp 0 0 :::8029 :::* LISTEN 21225/java tcp 0 0 ::ffff:127.0.0.1:8035 :::* LISTEN 21186/java tcp 0 0 :::8039 :::* LISTEN 21186/java tcp 0 0 ::ffff:127.0.0.1:8015 :::* LISTEN 21002/java tcp 0 0 :::8081 :::* LISTEN 21002/java tcp 0 0 :::8082 :::* LISTEN 21225/java tcp 0 0 :::8083 :::* LISTEN 21186/java tcp 0 0 :::8019 :::* LISTEN 21002/java tcp 0 0 :::22 :::* LISTEN 25757/sshd tcp 0 0 ::ffff:127.0.0.1:8025 :::* LISTEN 21225/java |
可以看到8081,8082,8083等其他埠都已經啟動,現在可以使用curl命令進行訪問
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# curl localhost:8081 <html> <body> <h2>Hello World!</h2> </body> </html> # curl localhost:8082 <html> <body> <h2>Hello World!</h2> </body> </html> # curl localhost:8083 <html> <body> <h2>Hello World!</h2> </body> </html> |
完成!
四、參考文獻
- (美)布里泰恩, (美)達爾文, 吳豪. Tomcat權威指南[M]. 中國電力出版社, 2009.
- tomcat官方文件:https://tomcat.apache.org/tomcat-7.0-doc/RUNNING.txt