Tomcat单机多实例部署及管理

傲视群雄

单台机器部署多个 Tomcat, 每个Tomcat部署独立服务,Tomcat之间启停互不影响

不要问我为什么有这个需求, 复制粘贴就是干


0x00 单机多实例概述

kionf

大概的目录结构:

  • CATALINA_HOME 为Tomcat应用程序运行程序及所需依赖
  • CATALINA_BASE 即我们即将部署的程序

手动更改如下工作目录:

这是我自己个儿整的初始目录结构 download
1
2
3
4
5
6
7
8
9
10
war_apps #手动创建用来存放下载好的war包文件
tomcat #CATALINA_HOME
├── bin
├── INIT_APPS_FILE #CATALINA_BASE
│   ├── conf
│   ├── logs
│   ├── temp
│   ├── webapps
│   └── work
└── lib

然后呢正常的思路就是配置每个APP的server.xml端口:

1
2
3
4
- 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;

应用太多你难道要一个个手动改? no no no! 上脚本


0x01 自动部署管理配置

需要把应用war包传到可下载位置,来用于应用分发,我这里是直接传到了阿里云的oss桶里

1.添加tomcat更新启停控制脚本

需要安装unzip yum -y install unzip

manage.sh需要放在这里,也可以自定义改代码
1
2
3
4
5
6
7
8
9
10
11
war_apps #手动创建用来存放下载好的war包文件
tomcat #CATALINA_HOME
├── bin
├── manage.sh
├── INIT_APPS_FILE #CATALINA_BASE
│   ├── conf
│   ├── logs
│   ├── temp
│   ├── webapps
│   └── work
└── lib

蓝色块需要根据实际情况自定义, 应用名称, 和war包下载地址不需要写,后面的python总控制台会自动分配

manage.sh
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!/bin/sh
# Author: Kionf
# description: 启动tomcat多实例.
# PATH=/opt/op/java/jdk1.8.0_172/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
# 应用名称
app=
# war包下载地址
war_url=
soft_dir="/opt/op"
download_war_file="${soft_dir}/war_apps/${app}.war"
export CATALINA_BASE="${soft_dir}/tomcat/$app"
export CATALINA_HOME="${soft_dir}/tomcat"
export JVM_OPTIONS="-Xms528m -Xmx812m -Xmn328m"
[ -d "${soft_dir}/war_apps" ] || mkdir ${soft_dir}/war_apps
[ `which unzip` ] || yum -y -q install unzip >/dev/null 2>&1
check(){
PID=`ps aux|grep java|grep -w ${CATALINA_BASE}|awk '{print $2}'`
if [ -n "$PID" ];then
echo -e "\033[94m $app is running PID:$PID"
running=`netstat -ntlp|grep $PID|grep 127.0.0.1`
if [ -n "$running" ];then
echo -e "\033[92m $app is provide services\033[0m "
else
echo -e "\033[93m $app is running but not provide services\033[0m"
fi
return 0
else
echo -e "\033[91m $app is dead\033[0m "
return 1
fi
}
start() {
check
if [ $? -eq 1 ];then
echo -e "\033[94m Start $app \033[0m"
$CATALINA_HOME/bin/startup.sh >/dev/null 2>&1
fi
}
stop() {
check
if [ $? -eq 0 ];then
echo -e "\033[94m Stop $app\033[0m"
$CATALINA_HOME/bin/shutdown.sh >/dev/null 2>&1
kill -9 $PID
fi
}
update() {
echo "下载文件"
wget ${war_url} -O ${download_war_file} > /dev/null 2>&1
if [ $? -eq 0 ];then
cd ${CATALINA_BASE}/webapps/*/; unzip -q -o ${download_war_file} >/dev/null 2>&1
fi
}
log() {
tailf ${CATALINA_BASE}/logs/catalina.out
}
if [ $# != "0" ];then
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
check
;;
upgrade)
stop
update
start
;;
log)
log
;;
*)
echo $"Usage: $0 {start|stop|restart|status|upgrade|log}"
exit 1
;;
esac
else
start
log
fi

2.添加总控制台脚本

我就放在了/usr/local/bin下, chmod +x /usr/local/bin/tomcat_manager 蓝色部分需要根据自己需求更改 (支持python2)

/usr/local/bin/tomcat_manager
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2018/5/23 15:18
# @Author : Kionf
# @FileName: tomcat_manager.py
#
# 初始配置并管理单例tomcat多应用
#
import os
import subprocess
import sys
import shutil
# PATH = os.getcwd()
PATH = "/opt/op/tomcat" #Tomcat目录
shell_script = os.path.join(PATH, "manage.sh") #更新启停管理脚本
INIT_FILES = os.path.join(PATH, "INIT_APPS_FILE")
bucket = "https://oss.aliyuncs.com/tomcat_app/" # webapp下载地址
config_data = {
# 应用名: [ServerPort, ConnectPort, AJPPort, RedirectPort, ]
'Application': ['8201', '8101', '8301', '8401', 'BaseApplication.war'],
'BaseNotify_Service': ['8202', '8102', '8302', '8402', 'BaseNotify_Service.war'],
'BaseUserCenter_Service': ['8203', '8103', '8303', '8403', 'BaseUserCenter_Service.war'],
}
def customize_print(msg, stat=0):
if stat == 1:
print("\033[91m [ERROR]: %s \033[0m" % msg)
elif stat == 0:
print("\033[92m [INFO]: %s \033[0m" % msg)
elif stat == 2:
print("\033[93m [DEBUG]: %s \033[0m" % msg)
class TomcatAppsManage:
def __init__(self, webapp):
self.name = webapp
self.app_config = config_data[self.name]
self.manage_shell_file = os.path.join(PATH, self.name, self.name)
self.server_port, self.conn_port, self.ajp_port, self.redirect_port, self.app_war_name = self.app_config
self.app_download_url = bucket + self.app_war_name
self.config_file = os.path.join(PATH, self.name, 'conf/server.xml')
self.webapp_dir = os.path.join(PATH, self.name)
def create_app(self):
"""
创建app
:return:
"""
if not os.path.exists(self.webapp_dir):
customize_print("创建APP: %s" % self.name)
shutil.copytree(INIT_FILES, self.webapp_dir)
os.mkdir(os.path.join(self.webapp_dir, "webapps", self.name.lower()))
def config_app_port(self):
customize_print("正在修改APP:%s 配置" % self.name)
change_port = {
'ServerPort': "sed -i s'#Server port=\"[0-9]*\"#Server port=\"" + self.server_port + "\"#'g " + self.config_file,
'ConnPort': "sed -i s'#Connector port=\"[0-9]*\" protocol=\"HTTP/1.1\"#Connector port=\"" + self.conn_port + "\" protocol=\"HTTP/1.1\"#'g " + self.config_file,
'RedirectPort': "sed -i s'#redirectPort=\"[0-9]*\"#redirectPort=\"" + self.redirect_port + "\"#'g " + self.config_file,
'AjpPort': "sed -i s'#Connector port=\"[0-9]*\" protocol=\"AJP/1.3\"#Connector port=\"" + self.ajp_port + "\" protocol=\"AJP/1.3\"#'g " + self.config_file,
}
for port in change_port.keys():
# customize_print("修改 %s 端口" % port)
os.system(change_port[port])
def config_app_manage_shell(self):
customize_print("%s 添加管理脚本" % self.name)
copy_shell_script = 'cp -f ' + shell_script + ' ' + self.manage_shell_file
os.system(copy_shell_script)
config_script_app_name = "sed -i 's/app=/app=\"" + self.name + "\"/' " + self.manage_shell_file
os.system(config_script_app_name)
config_script_war_url = "sed -i 's#war_url=#war_url=\"" + self.app_download_url + "\"#' " + self.manage_shell_file
os.system(config_script_war_url)
def status_app(self):
"""
:return: 0提供服务,1停止,2未提供服务
"""
try:
result = subprocess.check_output(['sh', self.manage_shell_file, 'status'])
except subprocess.CalledProcessError as e:
result = e.output
if 'run' in result:
if 'is provide services' in result:
customize_print("应用 %s 成功启动并提供服务" % self.name)
return 0
elif 'but' in result:
customize_print("应用 %s 进程存在但未提供服务" % self.name, 2)
return 2
else:
customize_print("应用 %s 以停止" % self.name, 1)
return 1
def manage(self, operate):
os.system('sh %s %s' % (self.manage_shell_file, operate))
def init(self):
self.create_app()
self.config_app_port()
self.config_app_manage_shell()
self.manage("upgrade")
self.manage("stop")
def restart(self):
self.manage("stop")
self.manage("start")
def start(self):
self.manage("start")
def stop(self):
self.manage("stop")
def log(self):
self.manage("log")
def upgrade(self):
self.lock_config_file()
self.manage("upgrade")
def lock_config_file(self):
cmd = 'find ' + self.webapp_dir + ' -name db*properties -o -name config_base_*|xargs chattr +i >/dev/null 2>&1'
customize_print("锁配置文件", 2)
os.system(cmd)
def unlock_config_file(self):
cmd = 'find ' + self.webapp_dir + ' -name db*properties -o -name config_base_*|xargs chattr -i >/dev/null 2>&1'
customize_print("解锁配置文件", 2)
os.system(cmd)
def dash_board(apps, operate):
"""
主管理程序,调用
:param operate: 应用操作
:param apps: apps 为list
"""
for app in apps:
app_obj = TomcatAppsManage(app)
main_dict = {
"init": app_obj.init,
"shell": app_obj.config_app_manage_shell,
"status": app_obj.status_app,
"start": app_obj.start,
"stop": app_obj.stop,
"restart": app_obj.restart,
"upgrade": app_obj.upgrade,
"log": app_obj.log,
"lock": app_obj.lock_config_file,
"unlock": app_obj.unlock_config_file,
}
try:
main_dict[operate]()
except KeyError as e:
customize_print(help_msg)
help_msg = """
使用方法:
1 log
all status
管理应用编号 操作
操作:
lock 锁配置文件
unlock 解锁配置文件
init 配置tomcat监听端口
shell 配置webapp控制脚本
status,start,restart, log,upgrade,stop 应用操作
"""
def main():
app_list = []
for index, app_name in enumerate(config_data, 1):
print "\033[94m %s: %s \033[0m" % (index, app_name)
app_list.append(app_name)
choice = raw_input("输入要管理的服务: ")
try:
app_index = choice.split()[0]
operate = choice.split()[1]
if app_index.isdigit():
app_index = int(app_index)
if len(app_list) >= app_index > 0:
app_name = app_list[app_index - 1]
dash_board(app_name.split(), operate)
elif app_index == "all":
dash_board(app_list, operate)
except ValueError and IndexError:
customize_print("参数输入错误", 1)
customize_print(help_msg)
if __name__ == '__main__':
try:
dash_board(sys.argv[1].split(), sys.argv[2])
except IndexError:
try:
while True:
main()
except KeyboardInterrupt:
customize_print("Bye!")

0x02 开始初始化部署

执行tomcat_manager

kiong

all init 自动初始化部署所有项目, 其他具体使用方法见帮助信息