在最近的工作中,我们已经使用阿里云NAS将需要发布的jar包统一上传到NAS中,但是部署的时候还是需要每个服务器去单独启动,比较麻烦。所以准备写一个批量自动部署的脚本。

背景

1.我们使用的Spring Cloud微服务
2.现在服务的部署方式是单独n台服务器部署eureka+nginx+nacos(每台机器配置和服务相同)。单独的m台部署gateway、user等业务服务(每台机器配置和服务相同)。
3.没一个业务服务单独在基础文件夹下新建文件夹,且包含三个文件,一个jar包,对应的Dockerfile,启动的start_xxx.sh

理清思路

1.必须要有基础文件夹路径
2.必须要有m台业务服务器的ssh信息
3.必须要知道所有业务服务的启动sh(启动时)、docker容器名称(重启时)
4.有这这些信息之后,我们可以ssh到对应服务器执行启动/重启指令

实现

前提条件

1.使用jq解析json格式的配置文件(为什么不用yml),安装jq 2.使用sshpass连接服务器(是不是可以用其它免密登录代替),安装sshpass

shell脚本

#/bin/bash

## get param from commond

declare -a params

index=0
for i in "$@"; do
    params[$index]=$i    
    let "index++"
done

startMark="s"

# echo "接收到的指令为 ${params[0]}"

start=0
if [ "${params[0]}" = "$startMark" ] 
then let "start=1" 
fi

## read from config
basePath=$(jq .basePath test.json)

declare -a bizCommond;
declare -a bizValid;

contain=0
bizIndex=0
while read name path containerName port serverName; do
    contain=$(echo "${params[@]}" | grep -wq "$name" &&  echo 1 || echo 0)
    # echo "compare result is $contain"
    if (($contain == 1))
    then
      if (($start == 1))
      then 
        bizCommond[$bizIndex]=$path 
      else  
        bizCommond[$bizIndex]=$containerName
      fi
      bizValid[$bizIndex]=":$port/$serverName/actuator/info"
      let "bizIndex++"
    fi
done < <(cat test.json | jq -r '.biz[]|"\(.name) \(.path) \(.containerName) \(.port) \(.serverName)"')

if (( ${#bizCommond[*]} < 1)) 
then exit 
fi

while read ip port user pass ; do
    echo "连接到$ip部署" 
    for ((i=0; i<${#bizCommond[*]}; i++))
      do
        echo "开始启动"
        if (($start == 1))
        then 
          commond=" cd $basePath && ${bizCommond[$i]} "
        else  
          commond="docker restart ${bizCommond[$i]} "
        fi
        echo "执行启动指令 $commond"
        sshpass -p $pass ssh -p $port $user@$ip "$commond"
        validCommond="curl -I -m 10 -o /dev/null -s -w %{http_code} http://$ip${bizValid[$i]}"
        echo "执行检查指令 $validCommond"
        result=$($validCommond)
        echo "检查结果为:$result"
        while [[ "$result" == "000" ]]; do
          sleep 3
          result=$($validCommond)
          echo "检查结果为:$result"
        done
        echo "启动完成"
        sleep 2
      done	
done < <(cat test.json | jq -r '.machine[]|"\(.ip) \(.port) \(.user) \(.pass)"')

配置文件

{
  "basePath": "/home/app/",
  "biz":
  [
    {
      "name": "x", 
      "path": "./xxx/start_xxx.sh",
      "containerName": "xxx",
      "port": "8010",
      "serverName": "xxx-server"
    },
    {
      "name": "y",
      "path": "./yyy/start_yyy.sh",
      "containerName": "yyy",
      "port": "8100",
      "serverName": "yyy-server"
    }
  ],
  "machine":
    [
      {
        "ip":"192.168.0.105",
        "port": 22,
        "user":"root",
        "pass":"123456"
      }
    ] 
}

json数据释义

{
  "basePath": "/home/app/",  //基础工作目录
  "biz":  // 业务服务配置
  [
    {
      "name": "x",  // 服务别名,在使用命令时匹配名称
      "path": "./xxx/start_xxx.sh",  // 启动执行的脚本
      "containerName": "xxx",  // docker容器名称
      "port": "8010",  // 监听的端口
      "serverName": "xxx-server"  // 服务名称-Spring Boot项目中spring.application.name
    }
  ],
  "machine":  // 部署的服务器
    [
      {
        "ip":"192.168.0.105",  // 服务器ip地址
        "port": 22,  // 服务器ssh端口
        "user":"root",  // 服务器用户名
        "pass":"123456"  // 服务器密码
      }
    ] 
}

使用

## 启动
./xxx.sh s yyy zzz 
## 重启
./xxx.sh r yyy zzz

未竞工作

1.结合Eureka,先将Eureka的状态变为DOWN之后在执行启动/重启
2.校验服务是否启动还需要校验Eureka的状态是否是UP(Eureka的接口是xml的o(╥﹏╥)o)
3.需要在启动服务时传入参数/环境变量还未做

参考

Shell 数组