shell脚本

使用实例:

  1. sh boot.sh restart
  2. sh boot.sh start
  3. sh boot.sh stop
  4. sh boot.sh status

boot 脚本内容:
**

默认jar路径和boot路径保持一致,如果不一致,自己cd啊。

  1. #!/bin/bash
  2. #jar包名称初始化,不用手动设置
  3. APP_NAME=
  4. # 切换目录
  5. cd `dirname $0` || exit
  6. cd ..
  7. #查找jar包
  8. for item in *.jar; do
  9. fileName=$item
  10. if [ -f "$fileName" ] && [ "${fileName##*.}" = jar ]; then
  11. APP_NAME=$fileName
  12. break
  13. fi
  14. done
  15. if [ ! "$APP_NAME" ]; then
  16. echo 未找到jar
  17. exit 1
  18. fi
  19. STDOUT_FILE=/dev/null
  20. # 判断java是否存在
  21. BITS=$(java -version 2>&1 | grep -i 64-bit)
  22. if [ -z "$BITS" ]; then
  23. echo 未安装JDK8
  24. exit 1
  25. fi
  26. # 解锁更多参数、
  27. JAVA_OPTS=" -XX:+UnlockExperimentalVMOptions"
  28. # 内存配置,监视程序,然后根据实际情况进行调整,元空间默认20兆左右
  29. # -Xms8g -Xmx8g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m
  30. JAVA_OPTS="$JAVA_OPTS -server -Xms8g -Xmx8g"
  31. # 垃圾收集器、设置分层编译、
  32. JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:+TieredCompilation"
  33. # 自定义配置文件和lib目录,多个目录用冒号分割
  34. # 已修改为分离 lib和 resource,所以 Dloader.path暂时不用
  35. JAVA_OPTS="$JAVA_OPTS -Dloader.path=config -Djava.io.tmpdir=. "
  36. # 服务器模式、兼容IPV4、编码(避免乱码)、禁止代码调用gc、
  37. JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8 -XX:+DisableExplicitGC"
  38. # gc 日志,滚动打印,5份,每份20M
  39. JAVA_OPTS="$JAVA_OPTS -Xloggc:log/gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause "
  40. # OOM日志
  41. JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=log/heap_dump"
  42. # java调试
  43. if [ "$2" = "debug" ]; then
  44. JAVA_OPTS="$JAVA_OPTS -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8081 "
  45. fi
  46. # 使用说明,用来提示输入参数
  47. usage() {
  48. echo "Usage: sh boot [APP_NAME] [start|stop|restart|status]"
  49. exit 1
  50. }
  51. # 检查程序是否在运行
  52. is_exist() {
  53. # 获取PID
  54. PID=$(ps -ef | grep ${APP_NAME} | grep -v $0 | grep -v grep | awk '{print $2}')
  55. # -z "${pid}"判断pid是否存在,如果不存在返回1,存在返回0
  56. if [ -z "${PID}" ]; then
  57. # 如果进程不存在返回1
  58. return 1
  59. else
  60. # 进程存在返回0
  61. return 0
  62. fi
  63. }
  64. # 定义启动程序函数
  65. start() {
  66. is_exist
  67. if [ $? -eq "0" ]; then
  68. echo "${APP_NAME} is already running, PID=${PID}"
  69. else
  70. rm -rf tomcat.*
  71. nohup java -jar $JAVA_OPTS ${APP_NAME} >>${STDOUT_FILE} 2>&1 &
  72. PID=$(echo $!)
  73. echo "${APP_NAME} start success, PID=$!"
  74. fi
  75. }
  76. # docker_start 前台运行
  77. docker_start() {
  78. is_exist
  79. if [ $? -eq "0" ]; then
  80. echo "${APP_NAME} is already running, PID=${PID}"
  81. else
  82. java -jar $JAVA_OPTS ${APP_NAME} >>${STDOUT_FILE} 2>&1
  83. PID=$(echo $!)
  84. echo "${APP_NAME} start success, PID=$!"
  85. fi
  86. }
  87. # 停止进程函数
  88. stop() {
  89. is_exist
  90. if [ $? -eq "0" ]; then
  91. kill -9 "${PID}"
  92. # 检测是否停止
  93. COUNT=1
  94. while [ $COUNT -eq 1 ]; do
  95. echo -e ".\c"
  96. sleep 1
  97. is_exist
  98. if [ -z "${PID}" ]; then
  99. COUNT=0
  100. echo "${APP_NAME} process stop"
  101. fi
  102. done
  103. # 删除临时文件
  104. rm -rf ./tomcat.*
  105. else
  106. echo "There is not the process of ${APP_NAME}"
  107. fi
  108. }
  109. # 重启进程函数
  110. restart() {
  111. stop
  112. start
  113. }
  114. # 查看进程状态
  115. status() {
  116. is_exist
  117. if [ $? -eq "0" ]; then
  118. echo "${APP_NAME} is running, PID=${PID}"
  119. else
  120. echo "There is not the process of ${APP_NAME}"
  121. fi
  122. }
  123. case $1 in
  124. "start")
  125. start
  126. ;;
  127. "docker_start")
  128. start
  129. ;;
  130. "stop")
  131. stop
  132. ;;
  133. "restart")
  134. restart
  135. ;;
  136. "status")
  137. status
  138. ;;
  139. *)
  140. usage
  141. ;;
  142. esac
  143. exit 0

python脚本

参考:github

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # 脚本用途:上传并部署SpringBoot项目:
  4. # 1. kill 旧的jar进程
  5. # 2. 备份旧文件到jar所在目录下的子目录(目录名:yymmdd),删除nohup文件。
  6. # 备份的文件包括:logs, jar文件, application*
  7. # 3. 上传新的jar,目录下所有文件都会被上传。
  8. # 4. 运行jar包
  9. #
  10. # 注意事项:
  11. #
  12. # 在host_dic中添加部署节点。
  13. # 需要先安装paramiko: pip install paramiko
  14. # 将需要上传的文件放到同一目录, 执行命令(参数为待上传文件的父目录、服务器文件存储目录、待运行的jar):
  15. # 运行命令: python deploy-jar.py local_dir remote_dir jar_name
  16. import paramiko
  17. import time
  18. from multiprocessing import Pool
  19. import os
  20. import sys
  21. # remote host的ssh信息
  22. # host: [username, password, port, server-ip]
  23. host_dic = {
  24. '139.129.1.1': ['root', 'password', 22, "172.18.211.105"],
  25. '139.129.1.2': ['root', 'password', 22, "172.18.211.106"]
  26. }
  27. def run_cmd(ssh_client, cmd):
  28. """
  29. 运行单条命令
  30. :param ssh_client:
  31. :param cmd:
  32. :return:
  33. """
  34. # bash -l -c解释:-l(login)表示bash作为一个login shell;-c(command)表示执行后面字符串内的命令,这样执行的脚本,可以获取到/etc/profile里的全局变量,包括我们搜索命令的目录PATH
  35. print("执行命令: " + cmd)
  36. stdin, stdout, stderr = ssh_client.exec_command(cmd)
  37. error_msg = stderr.read()
  38. if error_msg:
  39. print("run_cmd error: " + error_msg)
  40. result = stdout.read()
  41. print("运行结果: " + result)
  42. return result
  43. def mkdirs(ssh_client, sftp, dir):
  44. """
  45. 创建目录, 如果父目录没有创建, 则创建父目录
  46. :param ssh_client:
  47. :param sftp:
  48. :param dir 远程主机的目录
  49. :return:
  50. """
  51. try:
  52. sftp.stat(dir)
  53. print("directory exist: " + dir)
  54. except IOError:
  55. print("directory not exist, create dir")
  56. cmd = "mkdir -p " + dir
  57. run_cmd(ssh_client, cmd)
  58. def sftp_upload(ssh_client, sftp, local_path, remote_path):
  59. """
  60. 上传本地文件夹下文件到服务器
  61. :param ssh_client:
  62. :param sftp:
  63. :param local_path: 本地文件/文件夹路径, 可以为绝对路径也可以为相对路径
  64. :param remote_path: 远程文件存储路径
  65. :return:
  66. """
  67. try:
  68. if os.path.isdir(local_path): # 判断本地参数是目录还是文件
  69. mkdirs(ssh_client, sftp, remote_path)
  70. for f in os.listdir(local_path): # 遍历本地目录
  71. local_path_tmp = os.path.join(local_path, f)
  72. # 远程服务器为linux
  73. remote_path_tmp = os.path.join(remote_path, f).replace("\\", "/")
  74. sftp_upload(ssh_client, sftp, local_path_tmp, remote_path_tmp)
  75. else:
  76. print("sftp_upload local: " + local_path)
  77. print("sftp_upload remote: " + remote_path)
  78. sftp.put(local_path, remote_path) # 上传文件
  79. except Exception as e:
  80. print("upload exception:", e)
  81. def kill_jar(ssh_client, jar_name):
  82. """
  83. kill正在运行的nziot-api进程
  84. :return:
  85. """
  86. # grep_pid_cmd = "ps -A -o pid,command | grep " + jar_name+ " | grep -v grep | cut -d" " -f 1"
  87. grep_pid_cmd = "ps -ef | grep " + jar_name + " | grep -v grep | awk '{print $2}'"
  88. pid_str = run_cmd(ssh_client, grep_pid_cmd)
  89. if pid_str:
  90. pid_list = pid_str.strip().splitlines()
  91. for pid in pid_list:
  92. print("正在kill进程,进程id:" + pid)
  93. kill_pid_cmd = "kill " + pid
  94. run_cmd(ssh_client, kill_pid_cmd)
  95. else:
  96. print("没有进程在运行。")
  97. def back_old_jar(ssh_client, sftp, parent_dir):
  98. """
  99. 将旧的jar文件移动到新的文件夹,文件夹以日期命名:yymmdd
  100. :param ssh_client:
  101. :param parent_dir: 模块父目录
  102. """
  103. # back_dir = parent_dir + "/" + time.strftime("%Y%m%d");
  104. back_dir = os.path.join(parent_dir, time.strftime("%Y%m%d"))
  105. # 创建目录
  106. mkdirs(ssh_client, sftp, back_dir)
  107. # 备份旧文件
  108. old_files = parent_dir + "/nziot* " + parent_dir + "/application* " + parent_dir + "/logs"
  109. mv_cmd = "mv " + old_files + " -t " + back_dir
  110. run_cmd(ssh_client, mv_cmd)
  111. # 删除nohup
  112. # nohup_path = parent_dir + "/nohup*"
  113. nohup_path = os.path.join(parent_dir, "nohup*")
  114. rm_cmd = "rm -f " + nohup_path
  115. print("删除文件: " + nohup_path)
  116. run_cmd(ssh_client, rm_cmd)
  117. def run_jar(ssh_client, parent_dir, jar_name, config_name):
  118. """
  119. 异步运行nziot-iot进程
  120. :param ssh_client:
  121. :param jar_path:
  122. :return:
  123. """
  124. jar_path = os.path.join(parent_dir, jar_name)
  125. config_path = os.path.join(parent_dir, config_name)
  126. nohup_path = os.path.join(parent_dir, "nohup.out")
  127. # echo -n 不换行输出
  128. echo_cmd = "bash -lc 'echo -n $JAVA_HOME/bin/java -jar " + jar_path + "'"
  129. # echo_cmd = "echo -n $JAVA_HOME/bin/java -jar " + jar_name
  130. # echo_cmd = "echo -n $JAVA_HOME/bin/java -jar " + jar_name
  131. jar_cmd = run_cmd(ssh_client, echo_cmd)
  132. # 进入工作目录
  133. # nohup_cmd = "nohup /usr/java/jdk1.8.0_151/bin/java -jar " + jar_path + " &> " + nohup_path + " &"
  134. cd_cmd = "cd " + parent_dir
  135. nohup_cmd = "nohup " + jar_cmd + " &> " + nohup_path + " &"
  136. # nohup /usr/java/jdk1.8.0_151/bin/java -jar /root/nziot/nziot_api/nziot_api-0.0.6.jar &> /root/nziot/nziot_api/nohup.out &
  137. # print nohup_cmd
  138. run_cmd(ssh_client, cd_cmd + ";" + nohup_cmd)
  139. def replace_line(ssh_client, cfg_path, src_str, dst_str):
  140. """
  141. 将cfg_path文件中的字符串src_str替换为dst_str, 整行替换
  142. """
  143. sed_cmd = "sed -ie 's/%s.*/%s/ ' %s" % (src_str, dst_str, cfg_path)
  144. run_cmd(ssh_client, sed_cmd)
  145. grep_cmd = "grep '%s.*' %s" % (dst_str, cfg_path)
  146. grep_res = run_cmd(ssh_client, grep_cmd)
  147. # if(grep_res.strip('\n') == tartget_str):
  148. # print("在文件 %s 替换 %s 为 %s 成功" % (cfg_path, src_str, dst_str))
  149. # return True
  150. # else:
  151. # print("在文件 %s 替换 %s 为 %s 失败, 配置文件中内容:%s" % (cfg_path, src_str, dst_str, grep_res.strip('\n')))
  152. # return False
  153. def config(ssh_client, cfg_path, server_address):
  154. """
  155. 设置配置文件中的host
  156. """
  157. # 找到匹配的行
  158. print("在 %s 中配置server.address: %s" % (cfg_path, server_address))
  159. # 设置id
  160. src_str = "server.address="
  161. dst_str = src_str + server_address
  162. replace_line(ssh_client, cfg_path, src_str, dst_str)
  163. grep_cmd = "grep '%s.*' %s" % (src_str, cfg_path)
  164. grep_res = run_cmd(ssh_client, grep_cmd)
  165. if (grep_res.strip('\n') == dst_str):
  166. print("配置服务器地址为 %s 成功" % server_address)
  167. return True
  168. else:
  169. print("配置服务器地址为 %s 失败, 配置文件中内容:%s" % (server_address, grep_res.strip('\n')))
  170. return False
  171. def tail_file(ssh_client, file_path, line_num):
  172. """
  173. 查看文件尾部n行
  174. :param file_path: 文件路径
  175. :param line_num: 文件尾部行数
  176. :return:
  177. """
  178. print("查看文件 %s 尾部 %s 行。" % (file_path, line_num))
  179. tail_cmd = "tail -n100 " + file_path
  180. run_cmd(ssh_client, tail_cmd)
  181. def deploy(host, host_info, local_dir, remote_dir, jar_name):
  182. """
  183. 部署nziot-api
  184. :param host:
  185. :param port:
  186. :param username:
  187. :param password:
  188. :return:
  189. """
  190. print("----------%s----------" % host)
  191. username, password, port, server_address = host_info
  192. ssh_client = paramiko.SSHClient()
  193. ssh_client.load_system_host_keys()
  194. ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  195. ssh_client.connect(host, port, username=username, password=password, timeout=5)
  196. sf = paramiko.Transport((host, port))
  197. sf.connect(username=username, password=password)
  198. sftp = paramiko.SFTPClient.from_transport(sf)
  199. # 关闭api进程
  200. kill_jar(ssh_client, jar_name)
  201. # 备份旧文件
  202. back_old_jar(ssh_client, sftp, remote_dir)
  203. # 上传文件
  204. sftp_upload(ssh_client, sftp, local_dir, remote_dir)
  205. # 配置服务器地址
  206. cfg_name = "application-dev.properties"
  207. cfg_path = remote_dir + "/" + cfg_name
  208. config(ssh_client, cfg_path, server_address)
  209. # 运行新进程
  210. remote_dir = remote_dir.replace("\\", "/")
  211. run_jar(ssh_client, remote_dir, jar_name, cfg_name)
  212. # 查看nohup文件
  213. nohup_path = remote_dir + "/nohup.out"
  214. time.sleep(4) # 睡眠4秒
  215. tail_file(ssh_client, nohup_path, 100)
  216. sf.close()
  217. ssh_client.close()
  218. if __name__ == "__main__":
  219. """
  220. sys.argv[1]: local_dir
  221. sys.argv[2]: remote_dir
  222. sys.argv[3]: jar_name
  223. """
  224. local_dir = sys.argv[1]
  225. remote_dir = sys.argv[2]
  226. jar_name = sys.argv[3]
  227. print("local_dir: " + local_dir)
  228. print("remote_dir: " + remote_dir)
  229. pool = Pool(3)
  230. res_list = []
  231. for host, host_info in host_dic.items():
  232. deploy(host, host_info, local_dir, remote_dir, jar_name)