提交 b719ccea authored 作者: 陈泽健's avatar 陈泽健

feat(deploy): 新增自动化部署脚本模块化功能,将主服务部署函数拆分独立出来

- 创建了新的主服务部署脚本auto_deploy_services.sh
- 实现了Docker、Java、Python等多种服务的部署函数
- 添加了语音服务、无纸化信令、电子桌牌等专用部署模块
- 设计了模块化的部署流程和交互式菜单选择功能
- 建立了完整的错误处理和日志记录机制
- 编写了详细的PRD需求文档规范
上级 252db49a
# 主脚本模块化拆分主服务部署
## 代码路径
- 需调用代码路径:[自动化部署脚本/x86架构/新统一平台/auto_deploy_services.sh]
- 主脚本:[自动化部署脚本/x86架构/新统一平台/new_auto.sh]
## 功能需求
### 功能目标
**目标:** 当前主脚本代码量过于庞大,不利于维护,现需将主脚本中的相关部署函数独立出来,通过在主脚本中调用`auto_deploy_services.sh`。不要影响原有函数的部署逻辑。
### 需求描述
#### 调用逻辑
- 调用方式:
- 在主脚本中source导入`auto_deploy_services.sh`,然后调用`deploy_services`函数
```bash
# 在主脚本中导入主服务部署脚本(已有source导入,无需重复)
# source "$SCRIPT_DIR/auto_deploy_services.sh"
# 调用主服务部署脚本
deploy_services
```
- 接收脚本执行的返回参数,并使用log函数打印日志
- 0:主服务部署成功,使用`log "INFO"`打印日志
- 1:主服务部署失败,使用`log "ERROR"`打印错误日志,打印具体哪些服务部署失败,哪些成功,使用`return 1`退出当前操作
- 执行时机:
- 在主脚本中`getLatestVersion`之前执行;
#### 脚本设计要求
- 主入口函数:
-`auto_deploy_services.sh`中使用函数`deploy_services()`
- 主入口函数负责:
- 初始化变量(sudoset/SUDO)
- 通过交互式菜单(whiptail)让用户选择要部署的服务
- 调用对应的部署函数
- 返回部署结果
- log函数依赖:
- 脚本中的log函数与主脚本保持一致
- 在主脚本中先source导入`auto_deploy_services.sh`,再调用`deploy_services`函数
- 变量初始化:
-`deploy_services`函数中初始化以下变量:
- `sudoset`:sudo命令前缀(根据用户权限判断)
- `SUDO`:sudo命令(兼容不同函数中的变量名)
## 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
\ No newline at end of file
# 主脚本模块化拆分主服务部署计划执行文档
## 需求来源
- 需求文档:`Docs/PRD/自动化部署脚本/新统一平台/需求文档/_PRD_主脚本模块化拆分主服务部署_需求文档.md`
---
## 实现计划
### 1. 代码结构设计
```bash
auto_deploy_services.sh
├── docker_x86() # Docker安装
├── java_x86() # Java容器部署
├── python_x86() # Python容器部署
├── python_voice_x86() # Python语音后端部署
├── iListen_x86() # iListen语音服务部署
├── paperless_x86() # 无纸化信令服务部署
├── cardtable_x86() # 电子桌牌服务部署
└── deploy_services() # 主入口函数(交互式选择)
├── 初始化变量(sudoset/SUDO)
├── 显示交互式菜单(whiptail)
├── 调用选中的部署函数
└── 返回部署结果
```
### 2. 实现步骤
- [ ] 在auto_deploy_services.sh的deploy_services函数开头增加变量初始化
- [ ] 在主脚本new_auto.sh中source导入auto_deploy_services.sh
- [ ] 删除主脚本中的deploy_services函数定义
- [ ] 确认调用位置(getLatestVersion之前)
### 3. 技术要点
#### 3.1 变量初始化
在deploy_services函数开头增加:
```bash
# 初始化sudo相关变量
if [[ $(id -u) -ne 0 ]]; then
sudoset="sudo"
SUDO="sudo"
else
sudoset=""
SUDO=""
fi
```
#### 3.2 主脚本调用方式
```bash
# 导入主服务部署脚本
source "$SCRIPT_DIR/auto_deploy_services.sh"
# 调用部署函数(交互式选择)
deploy_services
```
### 4. 函数位置
- auto_deploy_services.sh:deploy_services函数(已存在,需增加变量初始化)
- new_auto.sh:删除第1234行开始的deploy_services函数定义
- new_auto.sh:在已有source导入区域添加auto_deploy_services.sh导入
### 5. 返回值定义
| 返回值 | 含义 | 处理方式 |
|--------|------|----------|
| 0 | 部署成功 | 继续执行 |
| 1 | 部署失败/用户取消 | 退出或继续 |
### 6. 执行流程
```
source导入 → deploy_services(交互式菜单)→ 调用选中的部署函数 → getLatestVersion
```
### 7. 已迁移的部署函数
| 函数名 | 功能 |
|--------|------|
| docker_x86 | Docker安装 |
| java_x86 | Java容器部署 |
| python_x86 | Python容器部署 |
| python_voice_x86 | Python语音后端部署 |
| iListen_x86 | iListen语音服务部署 |
| paperless_x86 | 无纸化信令服务部署 |
| cardtable_x86 | 电子桌牌服务部署 |
---
## 代码修改
### 修改文件
1. `自动化部署脚本/x86架构/新统一平台/auto_deploy_services.sh` - 增加变量初始化
2. `自动化部署脚本/x86架构/新统一平台/new_auto.sh` - 添加source导入,删除函数定义
---
## 测试计划
- [ ] 测试交互式菜单显示
- [ ] 测试单个服务部署
- [ ] 测试多个服务部署
- [ ] 测试用户取消场景
- [ ] 测试部署失败场景
---
## 优化功能回填
> 本章节用于记录实现过程中发现的优化点和改进措施
| 日期 | 优化项 | 状态 | 备注 |
|------|--------|------|------|
| - | - | - | - |
#==============================================================#
# 函数名: docker_x86
# 功能: 检查并安装 Docker(x86_64 离线安装)
# 说明: 用于在无网络或受限环境中自动部署 Docker 引擎
# 若 Docker 已安装则跳过;否则从本地 tar 包离线安装
# 安装内容包括:
# - 解压 docker 二进制文件到 /usr/bin
# - 配置 systemd 服务文件
# - 启动并设置开机自启
# 作者: [ubains]
# 日期: $(date +%Y-%m-%d)
#--------------------------------------------------------------#
# 参数: 无
# 返回: 0: 成功(已安装或跳过)
# 1: 安装失败
#--------------------------------------------------------------#
# 依赖: tar, systemctl, sudo(通过 $sudoset)
# 注意: 请确保以下资源已提前上传:
# - /data/temp/docker-20.10.7.tgz
# - /data/temp/docker.service
#==============================================================#
function docker_x86() {
log "INFO" "=================================================================="
log "INFO" "开始检查并安装 Docker (x86_64 离线模式)"
log "INFO" "=================================================================="
# ------------------- 定义变量 -------------------
local docker_version="29.1.3"
local temp_dir="/data/temp"
local tar_file="${temp_dir}/docker-${docker_version}.tgz"
local service_file="${temp_dir}/docker.service"
local docker_bin="/usr/bin/docker"
# ------------------- 检查 Docker 是否已安装 -------------------
log "INFO" "🔍 正在检查 Docker 是否已安装..."
if command -v docker >/dev/null 2>&1; then
local version=$(docker --version 2>&1)
log "INFO" "✅ Docker 已安装: $version"
log "INFO" "💡 若需重装,请先手动卸载。"
return 0
else
log "WARN" "❌ Docker 未安装,准备从离线包安装..."
fi
# ------------------- 检查依赖和文件是否存在 -------------------
log "INFO" "🔧 检查安装依赖和文件..."
if [[ ! -f "$tar_file" ]]; then
log "ERROR" "⛔ Docker 离线包不存在: $tar_file"
log "ERROR" "请将 docker-${docker_version}.tgz 上传至 $temp_dir 目录"
return 1
fi
if [[ ! -f "$service_file" ]]; then
log "ERROR" "⛔ Docker systemd 服务文件不存在: $service_file"
log "ERROR" "请将 docker.service 配置文件上传至 $temp_dir 目录"
return 1
fi
# ------------------- 开始安装 Docker -------------------
log "INFO" "📥 开始解压 Docker ${docker_version} ..."
if $sudoset tar -xzf "$tar_file" -C "$temp_dir"; then
log "INFO" "✅ 解压成功"
else
log "ERROR" "⛔ 解压失败,请检查压缩包完整性"
return 1
fi
log "INFO" "📦 安装 Docker 二进制文件到 /usr/bin/ ..."
if $sudoset cp "$temp_dir/docker"/* /usr/bin/ && $sudoset chmod +x /usr/bin/docker*; then
log "INFO" "✅ Docker 核心命令安装完成"
else
log "ERROR" "⛔ Docker 二进制文件复制失败"
return 1
fi
# ------------------- 配置 systemd 服务 -------------------
log "INFO" "⚙️ 配置 Docker systemd 服务 ..."
$sudoset rm -f /etc/systemd/system/docker.service
if $sudoset cp "$service_file" /etc/systemd/system/docker.service; then
$sudoset chmod 644 /etc/systemd/system/docker.service
log "INFO" "✅ 服务文件已部署"
else
log "ERROR" "⛔ 服务文件复制失败"
return 1
fi
# ------------------- 启动 Docker 服务 -------------------
log "INFO" "🚀 正在启动 Docker 服务 ..."
$sudoset systemctl daemon-reload
if $sudoset systemctl start docker; then
log "INFO" "✅ Docker 服务启动成功"
else
log "ERROR" "⛔ Docker 启动失败,请检查日志: journalctl -u docker"
return 1
fi
if $sudoset systemctl enable docker.service; then
log "INFO" "✅ Docker 已设置为开机自启"
else
log "WARN" "⚠️ 设置开机自启失败,可能影响后续使用"
fi
# ------------------- 验证安装 -------------------
log "INFO" "🔍 验证 Docker 安装结果..."
if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
log "INFO" "🎉 Docker 安装并启动成功!版本信息:"
docker --version
return 0
else
log "ERROR" "⛔ Docker 安装后验证失败,请手动排查"
return 1
fi
}
# java容器部署
function java_x86()
{
log "INFO" "=================================================================="
log "INFO" "开始部署 Java 服务 (Docker 版, x86)"
log "INFO" "=================================================================="
# ------------------- 定义变量 -------------------
local container_name="ujava2"
local image_tar="/data/temp/java1.8.0_472.tar.gz"
local image_name="139.9.60.86:5000/ujava:v6"
local image_id="a8ba5fa12b8e"
# 主机目录映射
local host_api="/data/services/api"
local host_web="/data/services/web"
local host_nginx_log="/data/middleware/nginx/nginx_log"
local host_fdfs_data="/data/storage/storage/data"
# 定义挂载映射
# 1. 定义卷挂载映射 (-v)
local volume_args=(
"-v $host_api:/var/www/java/api"
"-v $host_web:/var/www/java/web"
"-v $host_nginx_log:/usr/local/nginx/logs"
"-v /etc/localtime:/etc/localtime:ro"
"-v $host_fdfs_data:/var/fdfs/storage/data"
)
# 端口映射(可根据需要增减)
local port_args=(
"-p 8085:8085"
"-p 8993:8993" "-p 8994:8994" "-p 8995:8995"
"-p 8999:8999"
"-p 8719:8719" "-p 8720:8720"
"-p 9204:9204" "-p 9200:9200" "-p 9201:9201" "-p 9903:9903"
"-p 9904:9904" "-p 9905:9905" "-p 9906:9906" "-p 9907:9907"
"-p 9908:9908" "-p 9909:9909" "-p 9910:9910" "-p 9911:9911"
"-p 9912:9912" "-p 9913:9913" "-p 9914:9914" "-p 9915:9915"
"-p 9916:9916" "-p 9917:9917" "-p 9918:9918" "-p 9919:9919"
"-p 9920:9920" "-p 30880:30880" "-p 30881:30881" "-p 30882:30882"
"-p 30883:30883" "-p 30884:30884"
)
# ------------------- 检查容器是否已运行 -------------------
log "INFO" "🔍 检查 Java 容器是否已运行..."
if $sudoset docker ps --format '{{.Names}}' | grep -wq "^$container_name$"; then
log "WARN" "✅ 容器 '$container_name' 已在运行。自动退出部署操作!!!"
return 0
fi
# ------------------- 检查镜像是否存在 -------------------
log "INFO" "🔍 检查 Java 镜像是否存在..."
if $sudoset docker images --format '{{.Repository}}:{{.Tag}}' | grep -wq "$image_name"; then
log "WARN" "✅ 镜像 $image_name 已存在。"
else
log "INFO" "❌ 镜像 $image_name 不存在,开始加载离线包..."
if [[ ! -f "$image_tar" ]]; then
log "ERROR" "⛔ 镜像文件不存在: $image_tar"
return 1
fi
if $sudoset docker load -i "$image_tar"; then
log "INFO" "🎉 镜像加载成功"
else
log "ERROR" "⛔ 镜像加载失败,请检查文件完整性"
return 1
fi
fi
# ------------------- 启动 Java 容器 -------------------
log "INFO" "🚀 正在启动 Java 容器: $container_name ..."
# $sudoset docker run -itd --privileged -v /data/services/api:/var/www/java/api -v /data/services/web:/var/www/java/web -v /data/middleware/nginx/nginx_log:/usr/local/nginx/logs -v /etc/localtime:/etc/localtime:ro -v /data/storage/storage/data:/var/fdfs/storage/data "${port_args[@]}" --restart=always --mac-address="02:42:ac:11:00:02" --name ujava2 $image_name /var/www/java/api/start.sh
$sudoset docker run -itd \
--privileged \
--entrypoint /bin/bash \
--restart=always \
--name "$container_name" \
--mac-address="02:42:ac:11:00:02" \
"${volume_args[@]}" \
"${port_args[@]}" \
"$image_name" \
/var/www/java/api/start.sh
if [ $? -ne 0 ]; then
log "ERROR" "⛔ 容器启动失败"
return 1
fi
log "INFO" "✅ Java 容器启动成功,等待初始化..."
sleep 8
# ------------------- 验证容器状态 -------------------
if $sudoset docker ps --format '{{.Names}}' | grep -wq "^$container_name$"; then
log "INFO" "🎉 Java 服务部署完成!"
$sudoset docker ps --filter "name=$container_name" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
else
log "ERROR" "⛔ 容器启动后未运行,请检查日志: docker logs $container_name"
return 1
fi
return 0
}
# python容器部署
function python_x86() {
log "INFO" "=================================================================="
log "INFO" "开始部署 Python 容器 (upython) - x86"
log "INFO" "=================================================================="
# ------------------- 定义变量 -------------------
local image_tar="/data/temp/python_v15.tar.gz"
local image_tag="139.9.60.86:5000/upython:v15"
local container_name="upython"
local host_api_dir="/data/services/api/python-cmdb"
local container_start_cmd="/var/www/html/start.sh"
# ------------------- 检查容器是否已存在 -------------------
if $sudoset docker ps -a --format '{{.Names}}' | grep -wq "^$container_name$"; then
# 容器已存在
if $sudoset docker ps --format '{{.Names}}' | grep -wq "^$container_name$"; then
log "WARN" "✅ 容器 '$container_name' 已在运行。自动退出部署操作!!!"
return 0
else
log "WARN" "🔄 容器 '$container_name' 存在但未运行,正在启动..."
$sudoset docker start "$container_name"
sleep 3
if $sudoset docker ps --format '{{.Names}}' | grep -wq "^$container_name$"; then
log "INFO" "✅ 容器 '$container_name' 已成功启动"
return 0
else
log "ERROR" "⛔ 容器启动失败,请检查日志: docker logs $container_name"
return 1
fi
fi
fi
# ------------------- 检查挂载目录 -------------------
if [[ ! -d "$host_api_dir" ]]; then
log "ERROR" "⛔ 应用目录不存在: $host_api_dir,请先上传代码"
return 1
fi
if [[ ! -f "$host_api_dir/start.sh" ]]; then
log "ERROR" "⛔ 启动脚本缺失: $host_api_dir/start.sh"
return 1
fi
# ------------------- 加载镜像 -------------------
if $sudoset docker images --format '{{.Repository}}:{{.Tag}}' | grep -Fq "$image_tag"; then
log "INFO" "✅ 镜像 $image_tag 已存在,跳过加载"
else
log "INFO" "📦 正在从离线包加载镜像: $image_tar"
if [[ -f "$image_tar" ]]; then
$sudoset docker load -i "$image_tar"
if [[ $? -ne 0 ]]; then
log "ERROR" "⛔ 镜像加载失败,请检查文件完整性: $image_tar"
return 1
fi
log "INFO" "🎉 镜像加载成功: $image_tag"
else
log "ERROR" "⛔ 镜像文件不存在: $image_tar"
return 1
fi
fi
# ------------------- 启动新容器 -------------------
log "INFO" "🚀 正在创建并启动容器 '$container_name'..."
$sudoset docker run -d \
--name "$container_name" \
--restart=always \
--mac-address="02:42:ac:11:00:07" \
--privileged \
-p 8000:8000 \
-p 8002:8002 \
-v "$host_api_dir:/var/www/html" \
-v "/etc/localtime:/etc/localtime:ro" \
-v /usr/share/zoneinfo:/usr/share/zoneinfo:ro \
"$image_tag" \
"$container_start_cmd"
if [[ $? -ne 0 ]]; then
log "ERROR" "⛔ 容器创建失败,请检查参数或资源"
return 1
fi
log "INFO" "✅ 容器 '$container_name' 创建并启动成功"
# ------------------- 状态验证 -------------------
sleep 3
if $sudoset docker ps --format '{{.Names}}' | grep -wq "^$container_name$"; then
log "INFO" "🟢 Python 服务运行中 → 访问端口: 8000, 8002"
else
log "ERROR" "⛔ 容器启动后退出,请查看日志: docker logs $container_name"
return 1
fi
return 0
}
#x86架构python播放器系统安装
function python_player_x86() {
echo -e "\033[36m* 正在检查Python服务是否安装......\033[0m"
# 检查Docker镜像和容器状态
local image_exists=$(docker images | grep -q python && echo "true" || echo "false")
local container_running=$(docker ps | grep -q uplayer && echo "true" || echo "false")
local player_dir="/var/www/player"
local source_player_dir="/home/player_auto_install/player"
local docker_image_path="/home/player_auto_install/server_bag/upython_player.tar.gz"
local start_script="/var/www/player/start.sh"
if [[ "$image_exists" == "true" && "$container_running" == "true" ]]; then
echo -e "\033[32m* 检查到Python已安装!正在安装下一个服务....\033[0m"
return 0
else
echo -e "\033[33m* 检查到Python服务未安装,正在安装服务....\033[0m"
# 加载Docker镜像并验证其存在
if [ ! -f "$docker_image_path" ]; then
echo -e "\033[31m* 错误: Docker镜像文件 $docker_image_path 不存在。\033[0m"
return 1
fi
if ! docker load -i "$docker_image_path"; then
echo -e "\033[31m* 加载Docker镜像失败。\033[0m"
return 1
fi
# 标记Docker镜像
if ! docker tag e449dd1ea3af 139.9.60.86:5000/upython:v11; then
echo -e "\033[31m* 标记Docker镜像失败。\033[0m"
return 1
fi
# 检查player目录是否存在,如果不存在则复制
if [ ! -d "$source_player_dir" ]; then
echo -e "\033[31m* 错误: 源目录 $source_player_dir 不存在。\033[0m"
return 1
fi
if [ ! -d "$player_dir" ]; then
mkdir -p /var/www/player
if ! cp -rp "$source_player_dir" /var/www/; then
echo -e "\033[31m* 复制player目录失败。\033[0m"
return 1
else
echo -e "\033[32m* 成功复制 player 目录。\033[0m"
chmod_files=(
"$player_dir/start.sh"
"$player_dir/manage.py"
"$player_dir/uuwsgi.ini"
"$player_dir/uplayer"
"$player_dir/UbainsDevOps"
)
chmod 755 -R "${chmod_files[@]}"
fi
else
echo -e "\033[32m* 目录 $player_dir 已存在,跳过复制。\033[0m"
fi
# 确认启动脚本存在
if [ ! -f "$start_script" ]; then
echo -e "\033[31m* 错误: 启动脚本 $start_script 不存在。\033[0m"
return 1
fi
# 启动容器,并指定固定的MAC地址
if ! docker run -itd \
--mac-address="02:42:ac:12:00:05" \
-p 18082:8082 -p 11883:1883 -p 8000:8000 -p 9001:9001 -p 8002:8002\
-v /var/www/player:/var/www/html \
-v /etc/localtime:/etc/localtime:ro \
-v /usr/share/zoneinfo:/usr/share/zoneinfo:ro \
--restart=always \
--privileged \
--name=uplayer \
139.9.60.86:5000/upython:v11 \
/root/start.sh; then
echo -e "\033[31m* 启动Python容器失败。\033[0m"
return 1
else
echo -e "\033[32m* Python服务安装完成并启动成功!\033[0m"
fi
fi
}
# ========================================
# 🐍 函数:python_voice_x86
# 描述:部署 upython 容器服务(语音平台后端)
# 功能:
# - 检查是否已有 upython_voice 容器运行
# - 若无,则加载镜像、打标签并启动容器
# - 挂载新路径(生产环境路径)
# - 端口映射:8003:8000, 8004:8002, 8080:8080
# - 固定 MAC 地址
# ========================================
function python_voice_x86() {
log "INFO" "=================================================================="
log "INFO" "开始部署 Python_voice 容器 (upython_voice) - x86"
log "INFO" "=================================================================="
local service_name="Python 语音后端服务"
local container_name="upython_voice"
local image_tar="/data/offline_auto_unifiedPlatform/data/temp/uvoice3.tar.gz"
local source_image_id="2a69026b2899"
local target_image_tag="139.9.60.86:5000/upython:v13"
# ✅ 更新为实际的生产挂载路径
local mounts=(
"/data/services/api/python-voice:/var/www/html/api"
"/usr/share/zoneinfo:/usr/share/zoneinfo:ro"
"/data/services/web/pc/pc-vue2-voice:/var/www/html/web"
"/data/third_party/iFlyTrans/iflytek/iListen/voicePath:/home/iflytek/iListen/voicePath"
"/data/third_party/iFlyTrans/iflytek/lingtOnlineHZ/online/:/home/iflytek/lingtOnlineHZ/online"
"/data/third_party/iFlyTrans/ubains/lingtOnlineHZ/online:/home/ubains/lingtOnlineHZ/online"
"/data/third_party/iFlyTrans/iflytek/huiyi/:/home/iflytek/huiyi/"
"/data/services/api/python-voice/start.sh:/root/start.sh" # 添加到这里
)
log "INFO" "=================================================="
log "INFO" "🚀 正在部署:$service_name"
log "INFO" "容器名称: $container_name"
log "INFO" "镜像文件: $image_tar"
log "INFO" "=================================================="
# 1. 检查容器是否已在运行
if docker ps --format '{{.Names}}' | grep -qw "^$container_name$"; then
log "WARN" "✅ 容器 '$container_name' 已在运行,退出自动部署!!!"
return 0
fi
# 2. 检查容器是否已存在(即使未运行)
if docker ps -a --format '{{.Names}}' | grep -qw "^$container_name$"; then
log "WARN" "⛔ 容器 '$container_name' 已存在,退出自动部署!!!"
return 0
fi
# 赋予启动脚本执行权限
local host_start_script="/data/services/api/python-voice/start.sh"
if [ -f "$host_start_script" ]; then
log "INFO" "🔧 修复宿主机启动脚本权限..."
chmod +x "$host_start_script"
log "INFO" "✅ 宿主机脚本权限已修复: $host_start_script"
else
log "WARN" "⚠️ 宿主机启动脚本不存在: $host_start_script"
fi
# 3. 检查目标镜像是否存在
if docker images --format '{{.Repository}}:{{.Tag}}' | grep -qw "^$target_image_tag$"; then
log "WARN" "✅ 镜像已存在: $target_image_tag"
else
# 4. 检查镜像压缩包是否存在
if [ ! -f "$image_tar" ]; then
log "INFO" "❌ 镜像文件不存在: $image_tar"
return 1
fi
log "INFO" "🐳 正在加载 upython 镜像..."
if ! docker load -i "$image_tar"; then
log "ERROR" "❌ 镜像加载失败,请检查文件完整性"
return 1
fi
log "INFO" "✅ 镜像加载完成"
fi
# 5. 构建挂载参数 - 正确的方式
local mount_args=()
for mount in "${mounts[@]}"; do
mount_args+=("-v")
mount_args+=("$mount")
done
# 6. 启动容器
log "INFO" "🚀 正在启动容器 '$container_name'..."
docker run -itd \
--name "$container_name" \
--mac-address="02:42:ac:11:00:24" \
--restart=always \
-p 8003:8000 \
-p 8004:8002 \
-p 8080:8080 \
"${mount_args[@]}" \
"$target_image_tag"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 容器启动失败,请检查端口占用或权限问题"
return 1
fi
# 7. 验证容器状态
sleep 3
if docker ps --format '{{.Names}}' | grep -qw "^$container_name$"; then
local cid=$(docker ps --filter "name=$container_name" --format "{{.ID}}")
log "INFO" "✅ 容器启动成功!"
log "INFO" "🏷 名称: $container_name"
log "INFO" "🔢 ID: $cid"
log "INFO" "🌐 端口: 8003→8000, 8004→8002, 8080→8080"
log "INFO" "📁 共挂载 ${#mounts[@]} 个目录"
else
log "ERROR" "❌ 容器启动后退出,请执行 'docker logs $container_name' 查看日志"
return 1
fi
log "INFO" "🎉 $service_name 部署成功!"
return 0
}
# ========================================
# ☕ 函数:iListen_x86
# 描述:部署 iListen Java 语音服务(科大讯飞语音识别核心服务)
# 功能:
# - 卸载 OpenJDK 11
# - 安装 JDK 8u361
# - 配置 Java 环境变量
# - 复制依赖库文件与程序
# - 启动 iListen 服务
# 依赖:
# - 离线包路径: /data/offline_auto_unifiedPlatform/data/temp/iFlyTrans_server_bag/
# - 服务路径: /data/third_party/iFlyTrans/iflytek/iListen
# ========================================
function iListen_x86() {
local service_name="iListen 语音服务"
local source_bag="/data/offline_auto_unifiedPlatform/data/temp/iFlyTrans_server_bag"
local jdk_tar="jdk-8u361-linux-x64.tar.gz"
local deploy_path="/opt/deploy"
local java_install_dir="$deploy_path/java"
local jdk_home="$java_install_dir/jdk1.8.0_361"
local iflytek_home="/data/third_party/iFlyTrans/iflytek"
local lib64_dest="/usr/lib64"
local lib_dest="/usr/lib"
log "INFO" "=================================================="
log "INFO" "🚀 正在部署:$service_name"
log "INFO" " 源文件目录: $source_bag"
log "INFO" " 服务安装路径: $iflytek_home"
log "INFO" "=================================================="
# --- 1. 检查服务是否已部署(✅ 改为检查目录和脚本存在,而非 Java)---
local service_dir="$iflytek_home/iListen"
local restart_script="$service_dir/restart.sh"
if [[ -d "$service_dir" ]] && [[ -f "$restart_script" ]]; then
log "INFO" "✅ 检测到 $service_name 已部署,跳过安装,准备启动..."
cd "$service_dir" || {
log "ERROR" "❌ 无法进入服务目录: $service_dir"
return 1
}
log "INFO" "▶️ 正在启动 iListen 服务..."
nohup ./restart.sh > nohup.out 2>&1 &
sleep 10
if pgrep -f "iListen" > /dev/null; then
log "INFO" "✅ iListen 服务已启动(PID: $(pgrep -f iListen | head -n1))"
else
log "WARN" "⚠️ 服务启动但未检测到进程,请检查日志: $service_dir/nohup.out"
fi
log "INFO" "🎉 $service_name 部署成功!"
return 0
fi
# 2. 卸载旧版 OpenJDK(避免冲突)
log "INFO" "🔧 正在卸载旧版 OpenJDK..."
yum -y remove java-11-openjdk* > /dev/null 2>&1 || true
log "INFO" "✅ OpenJDK 卸载完成(如存在)"
# 3. 检查依赖文件是否存在
if [ ! -f "$source_bag/$jdk_tar" ]; then
log "ERROR" "❌ JDK 安装包不存在: $source_bag/$jdk_tar"
return 1
fi
if [ ! -d "$source_bag/lib" ] || [ ! -d "$source_bag/usrlib" ] || [ ! -d "$source_bag/iflytek" ]; then
log "ERROR" "❌ 源文件目录缺失,请检查: $source_bag"
return 1
fi
# 4. 创建部署目录
mkdir -p "$deploy_path" "$java_install_dir"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 无法创建部署目录: $deploy_path"
return 1
fi
log "INFO" "✅ 创建部署目录: $deploy_path"
# 5. 复制并解压 JDK
log "INFO" "📦 复制 JDK 安装包..."
cp "$source_bag/$jdk_tar" "$deploy_path/"
cd "$deploy_path" || {
log "ERROR" "❌ 无法进入目录: $deploy_path"
return 1
}
log "INFO" "🗜️ 正在解压 JDK..."
tar -xzf "$jdk_tar" -C "$java_install_dir"
if [ $? -ne 0 ]; then
log "ERROR" "❌ JDK 解压失败,请检查压缩包完整性"
return 1
fi
log "INFO" "✅ JDK 解压完成: $jdk_home"
# 6. 配置 Java 环境变量(✅ 按你原来的方式,不做任何改动)
log "INFO" "🛠️ 配置 Java 环境变量..."
cat >> /etc/profile << 'EOF'
#set java environment
JAVA_HOME=$JAVA_HOME
CLASSPATH=.:$JAVA_HOME/lib/tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
EOF
# 替换占位符为实际路径
sed -i "s|\$JAVA_HOME|$jdk_home|g" /etc/profile
# 立即在当前会话中生效
export JAVA_HOME="$jdk_home"
export CLASSPATH=".:$JAVA_HOME/lib/tools.jar"
export PATH="$JAVA_HOME/bin:$PATH"
# 验证 Java 安装
if java -version >/dev/null 2>&1; then
log "INFO" "✅ Java 环境配置成功: $(java -version 2>&1 | head -n1)"
else
log "ERROR" "❌ Java 环境配置失败,请检查路径或权限"
return 1
fi
# 7. 复制库文件和程序
log "INFO" "📤 正在复制依赖库和程序文件..."
cp -r "$source_bag/lib/"* "$lib64_dest"/ && echo "✅ 已复制 lib → /usr/lib64"
cp -r "$source_bag/usrlib/"* "$lib_dest"/ && echo "✅ 已复制 usrlib → /usr/lib"
if [ -d "/iflytek" ]; then
rm -rf "/iflytek"
fi
cp -r "$source_bag/iflytek" / && echo "✅ 已复制 iflytek 主程序到根目录"
mkdir -p "$(dirname "$iflytek_home")"
if [ ! -L "$iflytek_home" ] && [ ! -d "$iflytek_home" ]; then
ln -s "/iflytek" "$iflytek_home"
echo "✅ 创建软链接: $iflytek_home → /iflytek"
fi
log "INFO" "✅ 所有文件复制完成"
# 8. 启动服务
log "INFO" "▶️ 正在启动 iListen 服务..."
cd "$iflytek_home/iListen" || {
log "ERROR" "❌ 无法进入服务目录: $iflytek_home/iListen"
return 1
}
nohup ./restart.sh > nohup.out 2>&1 &
sleep 2
if pgrep -f "iListen" > /dev/null; then
log "INFO" "✅ iListen 服务已启动(PID: $(pgrep -f iListen | head -n1))"
else
log "WARN" "⚠️ 服务启动但未检测到进程,建议检查日志: $iflytek_home/iListen/nohup.out"
fi
log "INFO" "🎉 $service_name 部署成功!"
return 0
}
# 无纸化信令服务部署
function paperless_x86() {
log "INFO" "=================================================================="
log "INFO" "开始部署 Paperless 服务 (x86)"
log "INFO" "=================================================================="
# --- 配置参数 ---
local container_name="paperless"
local image_tar="/data/offline_auto_unifiedPlatform/data/temp/paperless.tar"
local image_tag="paperless:v1"
local host_data_dir="/data/third_party/paperless"
local start_script_host="$host_data_dir/start.sh"
local port_http="62121"
local port_nginx="62122"
local mac_address="02:42:ac:11:00:09"
# 判断是否需要 sudo
local SUDO=""
if [[ $(id -u) -ne 0 ]]; then
if command -v sudo >/dev/null; then
SUDO="sudo"
else
log "ERROR" "当前不是 root 用户,且未安装 sudo,无法继续"
return 1
fi
fi
# ------------------- 检查容器是否存在(关键变更)-------------------
log "INFO" "🔍 检查容器 '$container_name' 是否已存在..."
if $SUDO docker ps -a --format '{{.Names}}' | grep -qw "$container_name"; then
log "WARN" "⛔ 容器 '$container_name' 已存在(无论运行与否),自动退出部署操作!!!"
log "WARN" "如需重新部署,请先手动删除容器:docker rm -f $container_name"
return 0
else
log "INFO" "✅ 容器 '$container_name' 不存在,可以安全部署"
fi
# ------------------- 检查本地必要文件 -------------------
log "INFO" "🔍 检查本地部署文件..."
if [[ ! -f "$image_tar" ]]; then
log "ERROR" "缺少镜像文件: $image_tar"
return 1
fi
log "INFO" "✅ 本地所需文件检查通过"
# ------------------- 检查目标目录是否存在 -------------------
log "INFO" "🔍 检查目标目录 $host_data_dir 是否存在..."
if [[ ! -d "$host_data_dir" ]]; then
log "ERROR" "⛔ 目标目录不存在: $host_data_dir"
log "ERROR" "请确保 /data/third_party/paperless 目录已提前部署好"
return 1
else
log "INFO" "✅ 目标目录 $host_data_dir 存在,继续部署"
fi
# 确保关键脚本存在并有执行权限
if [[ ! -f "$start_script_host" ]]; then
log "ERROR" "⛔ 启动脚本不存在: $start_script_host"
return 1
fi
$SUDO chmod +x "$start_script_host" "$host_data_dir/run.sh" 2>/dev/null
log "INFO" "🔧 已设置脚本执行权限"
# ------------------- 检查镜像是否已加载 -------------------
log "INFO" "🔍 检查镜像 $image_tag 是否已存在..."
if $SUDO docker images --format '{{.Repository}}:{{.Tag}}' | grep -Fxq "$image_tag"; then
log "INFO" "✅ 镜像 $image_tag 已存在"
else
log "INFO" "🔄 加载镜像 $image_tar..."
if $SUDO docker load -i "$image_tar"; then
log "INFO" "🎉 镜像加载成功"
else
log "ERROR" "镜像加载失败,请检查文件完整性"
return 1
fi
fi
# ------------------- 启动容器 -------------------
log "INFO" "🚀 正在启动容器 '$container_name'..."
$SUDO docker run \
-itd \
--privileged \
--name "$container_name" \
--mac-address="$mac_address" \
-p "${port_http}:${port_http}" \
-p "${port_nginx}:${port_nginx}" \
-v "$start_script_host:/root/start.sh" \
-v "$host_data_dir:/var/www/paperless" \
-v "/etc/localtime:/etc/localtime:ro" \
--restart=always \
"$image_tag" \
/root/start.sh
if [[ $? -ne 0 ]]; then
log "ERROR" "⛔ 容器启动失败"
return 1
fi
# ------------------- 验证容器是否正常运行 -------------------
sleep 5
if $SUDO docker ps --format '{{.Names}}' | grep -qw "$container_name"; then
log "INFO" "✅ 容器启动成功"
else
log "ERROR" "⛔ 容器启动失败或立即退出"
log "ERROR" "📄 查看日志: docker logs $container_name"
$SUDO docker logs "$container_name"
return 1
fi
return 0
}
# 电子桌牌服务部署
function cardtable_x86() {
local service_name="电子桌牌服务 (cardtable)"
local container_name="cardtable"
local image_tar="/data/offline_auto_unifiedPlatform/data/temp/uos-cardtable.tar" # 建议统一放 /data/temp
local image_tag="uos-cardtable:v1"
local work_dir="/data/third_party/wifi-local"
local db_dir="$work_dir/db"
log "INFO" "=================================================================="
log "INFO" "📦 正在部署:$service_name"
log "INFO" " 容器名称: $container_name"
log "INFO" " 镜像文件: $image_tar"
log "INFO" " 工作目录: $work_dir"
log "INFO" "=================================================================="
# 1. 检查镜像压缩包是否存在
if [ ! -f "$image_tar" ]; then
log "ERROR" "❌ 镜像文件不存在: $image_tar"
log "ERROR" "💡 请确认已上传镜像至 /data/temp/ 目录"
return 1
fi
log "INFO" "✅ 镜像文件已找到: $image_tar"
# 2. 加载 Docker 镜像
log "INFO" "🐳 正在加载 Docker 镜像..."
docker load -i "$image_tar"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 镜像加载失败,请检查文件完整性或 Docker 服务状态"
return 1
fi
log "INFO" "✅ 镜像加载成功: $image_tag"
# 3. 检查工作目录是否存在
if [ ! -d "$work_dir" ]; then
log "ERROR" "❌ 工作目录不存在: $work_dir"
log "ERROR" "💡 请先创建目录并放入配置文件"
return 1
fi
log "INFO" "✅ 工作目录已存在: $work_dir"
# 4. 设置文件权限(config、脚本、数据库组件)
log "INFO" "🔐 正在设置文件执行权限..."
chmod 755 "$work_dir/config.ini" "$work_dir/startDB.sh" "$work_dir/wifi"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 权限设置失败:$work_dir 下的文件"
return 1
fi
chmod 755 "$db_dir/mongo" "$db_dir/mongo.config" "$db_dir/mongod"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 权限设置失败:$db_dir 下的 MongoDB 组件"
return 1
fi
log "INFO" "✅ 文件权限设置完成"
# 5. 检查容器是否已存在,若存在则先停止并删除
if docker ps -a --format '{{.Names}}' | grep -qw "^$container_name$"; then
log "WARN" "🔄 检测到已有容器 '$container_name',自动退出部署操作!!!"
return 0
fi
# 6. 创建并运行新容器(使用 host 网络)
log "INFO" "🚀 正在创建并启动容器 '$container_name'..."
docker run -itd \
--name="$container_name" \
--privileged \
--network=host \
--restart=always \
-v "$work_dir:/home/wifi-local" \
"$image_tag" \
/root/start.sh
if [ $? -ne 0 ]; then
log "ERROR" "❌ 容器启动失败,请检查镜像、网络或挂载权限"
return 1
fi
# 7. 验证容器是否正常运行
sleep 3
if docker ps --format '{{.Names}}' | grep -qw "^$container_name$"; then
local container_id=$(docker ps --filter "name=$container_name" --format "{{.ID}}")
log "INFO" "✅ 容器启动成功!"
log "INFO" " 🏷 名称: $container_name"
log "INFO" " 🔢 ID: $container_id"
log "INFO" " 🌐 网络模式: host"
log "INFO" " 📁 挂载: $work_dir → /home/wifi-local"
log "INFO" " 🔁 重启策略: always"
else
log "ERROR" "❌ 容器启动后立即退出,请使用 'docker logs $container_name' 查看日志"
return 1
fi
return 0
}
#-------------------------------服务部署选择-start--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function deploy_services() {
local IP=$(hostname -I | awk '{print $1}' | cut -d' ' -f1)
# ========================================
# 🧩 定义服务映射表:支持多个函数
# 格式:[编号]="函数1 函数2 ..."(用空格分隔)
# ========================================
declare -A SERVICE_MAP=(
[1]="java_x86"
[2]="python_x86"
[3]="iListen_x86 python_voice_x86" # 👈 重点:语音系统 = 多个函数
[4]="paperless_x86"
[5]="cardtable_x86"
)
declare -A SERVICE_LABEL=(
[1]="预定系统"
[2]="运维集控系统"
[3]="语音转录系统"
[4]="无纸化信令服务"
[5]="电子桌牌服务"
)
declare -A SERVICE_DESC=(
[1]="Java 后端服务"
[2]="Python 运维控制平台"
[3]="语音识别引擎 + 转录后端"
[4]="Paperless 信令转发"
[5]="电子桌牌通信服务"
)
log "INFO" "🔍 正在检查 SERVICE_MAP 中引用的所有函数..."
local all_funcs=()
for func_list in "${SERVICE_MAP[@]}"; do
for func_name in $func_list; do # 注意:这里不要加引号,让其展开
all_funcs+=("$func_name")
done
done
local missing=0 total=0
for func_name in "${all_funcs[@]}" ; do
((total++))
if declare -f "$func_name" > /dev/null 2>&1; then
log "INFO" "✅ 函数已定义: $func_name"
else
log "ERROR" "❌ 函数未定义: $func_name"
((missing++))
fi
done
if [ $missing -ne 0 ]; then
log "ERROR" "⛔ 缺少 $missing 个函数,无法继续部署。"
return 1
fi
# 构建 whiptail 选项
local options=()
for i in {1..5}; do
options+=(
"$i"
"${SERVICE_LABEL[$i]} (${SERVICE_DESC[$i]})"
"off"
)
done
# 显示多选菜单(第一级界面)
local choices
choices=$(whiptail --title "🔹 服务部署中心" \
--backtitle "当前服务器 IP: $IP" \
--checklist "\n请选择要部署的服务(使用空格勾选,支持多选):" \
18 80 6 \
"${options[@]}" \
3>&1 1>&2 2>&3)
# 第一级界面取消:退出整个部署操作
if [ $? -ne 0 ]; then
log "INFO" "用户在第一级界面取消部署"
whiptail --title "↩️ 退出部署" --msgbox "已取消服务部署操作。" 8 40
return 1 # 返回1表示用户主动取消
fi
if [ -z "$choices" ]; then
if whiptail --title "ℹ️ 提示" --yesno "未选择任何服务,是否重新选择?" 10 50; then
# 用户选择重新选择,递归调用
deploy_services
return $?
else
# 用户选择退出
whiptail --title "↩️ 退出部署" --msgbox "已取消服务部署操作。" 8 40
return 1
fi
fi
# 去除多余引号,确保是干净的数字序列
choices=$(echo "$choices" | sed 's/"//g' | xargs)
# 显示用户选择的服务
local selected_list=""
for choice in $choices; do
if [[ -n "${SERVICE_LABEL[$choice]}" ]]; then
selected_list+="${SERVICE_LABEL[$choice]}\n"
else
log "ERROR" "⚠️ 未知服务编号: $choice"
fi
done
# 确认部署(第二级界面)
if ! whiptail --title "✅ 确认部署" \
--yesno "您选择了以下服务进行部署:\n\n${selected_list}\n是否确认开始部署?" \
14 60; then
log "INFO" "用户在第二级界面取消,返回服务选择界面"
whiptail --title "🔄 重新选择" --msgbox "将返回服务选择界面..." 8 40
# 第二级取消:递归调用返回第一级界面
deploy_services
return $?
fi
whiptail --title "🚀 开始部署" --msgbox "正在启动部署流程,请查看终端日志..." 10 50
# --- 开始部署 ---
local success_count=0
local total_count=0
for choice in $choices; do
if ! [[ "$choice" =~ ^[1-5]$ ]]; then
log "ERROR" "⚠️ 无效选项: $choice"
continue
fi
local func_list="${SERVICE_MAP[$choice]}"
local label="${SERVICE_LABEL[$choice]}"
if [[ -z "$label" ]]; then
log "ERROR" "⚠️ 未知服务编号: $choice"
continue
fi
log "INFO" "=================================================================="
log "INFO" "🚀 正在部署: $label"
log "INFO" "=================================================================="
# 👇 执行该服务关联的每一个函数
local service_success=true
for func_name in $func_list; do # 注意:不要加引号
if declare -f "$func_name" > /dev/null; then
log "INFO" "▶️ 执行函数: $func_name"
"$func_name"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 函数执行失败: $func_name"
service_success=false
break # 可选:是否继续执行下一个函数?
else
log "INFO" "✅ $func_name 执行成功"
fi
else
log "ERROR" "❌ 未找到函数: $func_name"
service_success=false
break
fi
done
if [ "$service_success" = true ]; then
log "INFO" "✅ $label 部署成功"
((success_count++))
else
log "ERROR" "❌ $label 部署失败"
whiptail --title "❌ 部署失败" \
--msgbox "服务 [$label] 部署失败,请检查日志后重试。" \
12 60 || echo "警告:无法显示弹窗"
fi
done
# 最终统计
local fail_count=$(( $(echo $choices | wc -w) - success_count ))
log "INFO" "=================================================="
log "INFO" "🎯 部署完成:成功 $success_count 个服务,失败 $fail_count 个"
log "INFO" "=================================================="
return $(( fail_count > 0 ? 1 : 0 ))
}
#-------------------------------服务部署选择-end--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
......@@ -72,6 +72,14 @@ else
exit 1
fi
# 导入主服务部署脚本
if [[ -f "$SCRIPT_DIR/auto_deploy_services.sh" ]]; then
source "$SCRIPT_DIR/auto_deploy_services.sh"
else
log "ERROR" "主服务部署脚本不存在: $SCRIPT_DIR/auto_deploy_services.sh"
exit 1
fi
#------------------------------检测模块-----------------------------------------------------
......@@ -510,570 +518,402 @@ function firewalldjava() {
}
#------------------------------开放防火墙端口-end------------------------------------------------------------------------------------------------------------------------
#x86架构ntp安装
function ntp_x86()
{
# 判断是否为centos7 否则跳出函数
if [ ! -f /etc/redhat-release ]; then
log "ERROR" "当前系统不是CentOS 7,无法安装NTP服务"
return 1
fi
log "INFO" "检查ntp服务......"
$sudoset systemctl status ntpd |grep running
#ps -aux | grep ntp
if [ $? -eq 0 ]; then
log "INFO" "检查到ntp已安装!"
else
log "WARN" "检查到ntp未安装,正在安装..."
$sudoset cd $auto_java/server_bag/ntp
$sudoset rpm -Uvh *.rpm --nodeps --force
$sudoset systemctl enable ntpd
$sudoset systemctl enable ntpdate
$sudoset systemctl start ntpd
$sudoset systemctl status ntpd
$sudoset mv /etc/ntp.conf /etc/ntp.confbak
$sudoset cp $auto_java/server_bag/ntp/ntp.conf /etc/
$sudoset systemctl restart ntpd
$sudoset systemctl disable chronyd
log "INFO" "完成ntp服务的安装"
fi
}
#------------------------------服务安装-start------------------------------------------------------------------------------------------------------------------------
#==============================================================#
# 函数名: docker_x86
# 功能: 检查并安装 Docker(x86_64 离线安装)
# 说明: 用于在无网络或受限环境中自动部署 Docker 引擎
# 若 Docker 已安装则跳过;否则从本地 tar 包离线安装
# 安装内容包括:
# - 解压 docker 二进制文件到 /usr/bin
# - 配置 systemd 服务文件
# - 启动并设置开机自启
# 作者: [ubains]
# 日期: $(date +%Y-%m-%d)
#--------------------------------------------------------------#
# 参数: 无
# 返回: 0: 成功(已安装或跳过)
# 1: 安装失败
#--------------------------------------------------------------#
# 依赖: tar, systemctl, sudo(通过 $sudoset)
# 注意: 请确保以下资源已提前上传:
# - /data/temp/docker-20.10.7.tgz
# - /data/temp/docker.service
#==============================================================#
function docker_x86() {
log "INFO" "=================================================================="
log "INFO" "开始检查并安装 Docker (x86_64 离线模式)"
log "INFO" "=================================================================="
#x86架构统信、麒麟系统的ntp安装
function ntp_uos() {
# 判断如果是centos7就退出安装
if [ -f /etc/redhat-release ]; then
log "ERROR" "当前系统是CentOS 7,已经安装NTP服务,无需安装chrony服务"
return 1
fi
# ------------------- 定义变量 -------------------
local docker_version="29.1.3"
local temp_dir="/data/temp"
local tar_file="${temp_dir}/docker-${docker_version}.tgz"
local service_file="${temp_dir}/docker.service"
local docker_bin="/usr/bin/docker"
# ------------------- 检查 Docker 是否已安装 -------------------
log "INFO" "🔍 正在检查 Docker 是否已安装..."
if command -v docker >/dev/null 2>&1; then
local version=$(docker --version 2>&1)
log "INFO" "✅ Docker 已安装: $version"
log "INFO" "💡 若需重装,请先手动卸载。"
# 判断文件是否存在ntp1.aliyun.com地址
if grep -q "ntp1.aliyun.com" /etc/chrony.conf; then
log "INFO" "NTP配置文件中已存在ntp1.aliyun.com地址,无需重复添加"
return 0
else
log "WARN" "❌ Docker 未安装,准备从离线包安装..."
fi
# ------------------- 检查依赖和文件是否存在 -------------------
log "INFO" "🔧 检查安装依赖和文件..."
local config_dir="/data/temp/ntp"
local backup="/etc/chrony.confbak"
local target="/etc/chrony.conf"
if [[ ! -f "$tar_file" ]]; then
log "ERROR" "⛔ Docker 离线包不存在: $tar_file"
log "ERROR" "请将 docker-${docker_version}.tgz 上传至 $temp_dir 目录"
return 1
fi
# 切换目录(不需要 sudo)
cd "$config_dir" || { echo "无法进入目录: $config_dir"; return 1; }
if [[ ! -f "$service_file" ]]; then
log "ERROR" "⛔ Docker systemd 服务文件不存在: $service_file"
log "ERROR" "请将 docker.service 配置文件上传至 $temp_dir 目录"
return 1
# 备份原有配置
if [ -f "$target" ]; then
log "INFO" "正在备份旧配置文件到 $backup"
sudo cp "$target" "$backup"
fi
# ------------------- 开始安装 Docker -------------------
log "INFO" "📥 开始解压 Docker ${docker_version} ..."
if $sudoset tar -xzf "$tar_file" -C "$temp_dir"; then
log "INFO" "✅ 解压成功"
# 检查是否可以通外网,可以则配置外网的ntp服务器地址,不可以则询问是否有企业ntp服务器地址
if ! ping -c 1 ntp1.aliyun.com &> /dev/null; then
log "ERROR" "无法连接到外网NTP服务器 ntp1.aliyun.com,请检查网络连接"
read -p "是否有企业NTP服务器地址?(y/n): " yn
if [[ -z "$yn" || "$yn" =~ ^[yY]$ ]]; then
read -p "请输入企业NTP服务器地址: " custom_ntp
echo "server $custom_ntp iburst" | sudo tee -a "$target"
echo "allow all" | sudo tee -a "$target"
else
log "ERROR" "没有可用的NTP服务器地址,配置默认地址,请联系管理员"
echo "server ntp1.aliyun.com iburst" | sudo tee -a "$target"
echo "allow all" | sudo tee -a "$target"
fi
else
log "ERROR" "⛔ 解压失败,请检查压缩包完整性"
return 1
log "INFO" "可以连接到外网NTP服务器 ntp1.aliyun.com,继续配置"
# 如果可以连接到外网NTP服务器,则继续添加默认的NTP服务器地址
echo "server ntp1.aliyun.com iburst" | sudo tee -a "$target"
echo "server ntp2.aliyun.com iburst" | sudo tee -a "$target"
echo "server ntp3.aliyun.com iburst" | sudo tee -a "$target"
echo "allow all" | sudo tee -a "$target"
fi
log "INFO" "📦 安装 Docker 二进制文件到 /usr/bin/ ..."
if $sudoset cp "$temp_dir/docker"/* /usr/bin/ && $sudoset chmod +x /usr/bin/docker*; then
log "INFO" "✅ Docker 核心命令安装完成"
else
log "ERROR" "⛔ Docker 二进制文件复制失败"
return 1
fi
# ------------------- 配置 systemd 服务 -------------------
log "INFO" "⚙️ 配置 Docker systemd 服务 ..."
# 输出同步地址到日志
log "INFO" "正在写入同步地址到 $target"
$sudoset rm -f /etc/systemd/system/docker.service
if $sudoset cp "$service_file" /etc/systemd/system/docker.service; then
$sudoset chmod 644 /etc/systemd/system/docker.service
log "INFO" "✅ 服务文件已部署"
else
log "ERROR" "⛔ 服务文件复制失败"
return 1
fi
# 重启服务
log "INFO" "正在重启 chronyd 服务..."
sudo systemctl daemon-reload
sudo systemctl restart chronyd
sudo systemctl enable chronyd
sudo systemctl status chronyd
# ------------------- 启动 Docker 服务 -------------------
log "INFO" "🚀 正在启动 Docker 服务 ..."
log "INFO" "chronyd 服务已重启并设置为开机自启"
}
# ========================================
# 🔧 函数:malan
# 描述:配置 malan 服务自启动(写入 /etc/rc.local)
# 功能:
# - 检查 /etc/rc.local 文件是否存在
# - 检查是否已存在 malan 启动命令(避免重复添加)
# - 将启动命令写入 /etc/rc.local
# - 确保文件有执行权限
# ========================================
function malan() {
local rc_local="/etc/rc.local"
local service_dir="/data/middleware/monitor"
local startup_cmd="cd /data/middleware/monitor/ && nohup ./malan &"
$sudoset systemctl daemon-reload
log "INFO" "=================================================="
log "INFO" "🔧 正在配置 malan 服务自启动"
log "INFO" " 服务目录: $service_dir"
log "INFO" "=================================================="
if $sudoset systemctl start docker; then
log "INFO" "✅ Docker 服务启动成功"
else
log "ERROR" "⛔ Docker 启动失败,请检查日志: journalctl -u docker"
return 1
# 1. 检查服务目录是否存在
if [ ! -d "$service_dir" ]; then
log "WARN" "⚠️ 服务目录不存在: $service_dir"
log "WARN" " 将尝试创建目录..."
mkdir -p "$service_dir" 2>/dev/null || {
log "ERROR" "❌ 无法创建目录: $service_dir"
return 1
}
log "INFO" "✅ 目录已创建: $service_dir"
fi
if $sudoset systemctl enable docker.service; then
log "INFO" "✅ Docker 已设置为开机自启"
# 2. 检查 malan 可执行文件是否存在
if [ ! -f "$service_dir/malan" ]; then
log "WARN" "⚠️ malan 可执行文件不存在: $service_dir/malan"
log "WARN" " 将继续配置自启动,但请确保文件已部署"
else
log "WARN" "⚠️ 设置开机自启失败,可能影响后续使用"
# 确保文件有执行权限
if [ ! -x "$service_dir/malan" ]; then
log "INFO" "🔧 正在为 malan 添加执行权限..."
chmod +x "$service_dir/malan" 2>/dev/null || {
log "WARN" "⚠️ 无法添加执行权限,可能需要 root 权限"
}
fi
log "INFO" "✅ malan 文件检查通过"
fi
# ------------------- 验证安装 -------------------
log "INFO" "🔍 验证 Docker 安装结果..."
if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
log "INFO" "🎉 Docker 安装并启动成功!版本信息:"
docker --version
return 0
else
log "ERROR" "⛔ Docker 安装后验证失败,请手动排查"
return 1
# 3. 检查 /etc/rc.local 文件是否存在
if [ ! -f "$rc_local" ]; then
log "INFO" "📁 rc.local 文件不存在,正在创建..."
touch "$rc_local" 2>/dev/null || {
log "ERROR" "❌ 无法创建 $rc_local,请检查权限"
return 1
}
# 添加 shebang 行(如果文件为空)
echo "#!/bin/bash" > "$rc_local"
log "INFO" "✅ rc.local 文件已创建"
fi
}
function java_x86()
{
log "INFO" "=================================================================="
log "INFO" "开始部署 Java 服务 (Docker 版, x86)"
log "INFO" "=================================================================="
# 确保 rc.local 有执行权限
if [ ! -x "$rc_local" ]; then
log "INFO" "🔧 正在为 rc.local 添加执行权限..."
chmod +x "$rc_local" 2>/dev/null || {
log "WARN" "⚠️ 无法添加执行权限,可能需要 root 权限"
}
fi
# ------------------- 定义变量 -------------------
local container_name="ujava2"
local image_tar="/data/temp/java1.8.0_472.tar.gz"
local image_name="139.9.60.86:5000/ujava:v6"
local image_id="a8ba5fa12b8e"
# 主机目录映射
local host_api="/data/services/api"
local host_web="/data/services/web"
local host_nginx_log="/data/middleware/nginx/nginx_log"
local host_fdfs_data="/data/storage/storage/data"
# 定义挂载映射
# 1. 定义卷挂载映射 (-v)
local volume_args=(
"-v $host_api:/var/www/java/api"
"-v $host_web:/var/www/java/web"
"-v $host_nginx_log:/usr/local/nginx/logs"
"-v /etc/localtime:/etc/localtime:ro"
"-v $host_fdfs_data:/var/fdfs/storage/data"
)
# 端口映射(可根据需要增减)
local port_args=(
"-p 8085:8085"
"-p 8993:8993" "-p 8994:8994" "-p 8995:8995"
"-p 8999:8999"
"-p 8719:8719" "-p 8720:8720"
"-p 9204:9204" "-p 9200:9200" "-p 9201:9201" "-p 9903:9903"
"-p 9904:9904" "-p 9905:9905" "-p 9906:9906" "-p 9907:9907"
"-p 9908:9908" "-p 9909:9909" "-p 9910:9910" "-p 9911:9911"
"-p 9912:9912" "-p 9913:9913" "-p 9914:9914" "-p 9915:9915"
"-p 9916:9916" "-p 9917:9917" "-p 9918:9918" "-p 9919:9919"
"-p 9920:9920" "-p 30880:30880" "-p 30881:30881" "-p 30882:30882"
"-p 30883:30883" "-p 30884:30884"
)
# ------------------- 检查容器是否已运行 -------------------
log "INFO" "🔍 检查 Java 容器是否已运行..."
if $sudoset docker ps --format '{{.Names}}' | grep -wq "^$container_name$"; then
log "WARN" "✅ 容器 '$container_name' 已在运行。自动退出部署操作!!!"
# 4. 检查是否已经存在相同的启动命令
if grep -Fq "cd /data/middleware/monitor/ && nohup ./malan &" "$rc_local" 2>/dev/null; then
log "INFO" "✅ malan 自启动配置已存在,跳过添加"
return 0
fi
# ------------------- 检查镜像是否存在 -------------------
log "INFO" "🔍 检查 Java 镜像是否存在..."
if $sudoset docker images --format '{{.Repository}}:{{.Tag}}' | grep -wq "$image_name"; then
log "WARN" "✅ 镜像 $image_name 已存在。"
else
log "INFO" "❌ 镜像 $image_name 不存在,开始加载离线包..."
if [[ ! -f "$image_tar" ]]; then
log "ERROR" "⛔ 镜像文件不存在: $image_tar"
return 1
fi
if $sudoset docker load -i "$image_tar"; then
log "INFO" "🎉 镜像加载成功"
# 5. 备份 rc.local
if [ -f "$rc_local" ]; then
local backup_file="${rc_local}.backup.$(date +%Y%m%d_%H%M%S)"
cp "$rc_local" "$backup_file" 2>/dev/null
if [ $? -eq 0 ]; then
log "INFO" "✅ 已备份 rc.local 文件: $backup_file"
else
log "ERROR" "⛔ 镜像加载失败,请检查文件完整性"
return 1
log "WARN" "⚠️ 备份 rc.local 失败,继续执行"
fi
fi
# ------------------- 启动 Java 容器 -------------------
log "INFO" "🚀 正在启动 Java 容器: $container_name ..."
# $sudoset docker run -itd --privileged -v /data/services/api:/var/www/java/api -v /data/services/web:/var/www/java/web -v /data/middleware/nginx/nginx_log:/usr/local/nginx/logs -v /etc/localtime:/etc/localtime:ro -v /data/storage/storage/data:/var/fdfs/storage/data "${port_args[@]}" --restart=always --mac-address="02:42:ac:11:00:02" --name ujava2 $image_name /var/www/java/api/start.sh
$sudoset docker run -itd \
--privileged \
--entrypoint /bin/bash \
--restart=always \
--name "$container_name" \
--mac-address="02:42:ac:11:00:02" \
"${volume_args[@]}" \
"${port_args[@]}" \
"$image_name" \
/var/www/java/api/start.sh
# 6. 添加启动命令到 rc.local
log "INFO" "📝 正在添加 malan 启动命令到 $rc_local"
if [ $? -ne 0 ]; then
log "ERROR" "⛔ 容器启动失败"
return 1
# 确保文件末尾有换行符
if [ -s "$rc_local" ] && [ "$(tail -c 1 "$rc_local")" != "" ]; then
echo "" >> "$rc_local"
fi
log "INFO" "✅ Java 容器启动成功,等待初始化..."
sleep 8
# 添加注释和启动命令
echo "# Auto-start malan service - $(date '+%Y-%m-%d %H:%M:%S')" >> "$rc_local"
echo "$startup_cmd" >> "$rc_local"
# ------------------- 验证容器状态 -------------------
if $sudoset docker ps --format '{{.Names}}' | grep -wq "^$container_name$"; then
log "INFO" "🎉 Java 服务部署完成!"
$sudoset docker ps --filter "name=$container_name" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
if [ $? -eq 0 ]; then
log "INFO" "✅ malan 自启动配置已添加到 $rc_local"
log "INFO" " 启动命令: $startup_cmd"
else
log "ERROR" "⛔ 容器启动后未运行,请检查日志: docker logs $container_name"
log "ERROR" "❌ 写入 $rc_local 失败,请检查权限"
return 1
fi
# 7. 验证写入的内容
if grep -Fq "cd /data/middleware/monitor/ && nohup ./malan &" "$rc_local" 2>/dev/null; then
log "INFO" "✅ 配置验证成功"
else
log "WARN" "⚠️ 配置验证失败,请手动检查 $rc_local"
fi
log "INFO" "=================================================="
log "INFO" "🎉 malan 自启动配置完成!"
log "INFO" " 配置文件: $rc_local"
log "INFO" " 提示: 系统重启后 malan 服务将自动启动"
log "INFO" "=================================================="
return 0
}
function python_x86() {
log "INFO" "=================================================================="
log "INFO" "开始部署 Python 容器 (upython) - x86"
log "INFO" "=================================================================="
# ------------------- 定义变量 -------------------
local image_tar="/data/temp/python_v15.tar.gz"
local image_tag="139.9.60.86:5000/upython:v15"
local container_name="upython"
local host_api_dir="/data/services/api/python-cmdb"
local container_start_cmd="/var/www/html/start.sh"
# ------------------- 检查容器是否已存在 -------------------
if $sudoset docker ps -a --format '{{.Names}}' | grep -wq "^$container_name$"; then
# 容器已存在
if $sudoset docker ps --format '{{.Names}}' | grep -wq "^$container_name$"; then
log "WARN" "✅ 容器 '$container_name' 已在运行。自动退出部署操作!!!"
return 0
else
log "WARN" "🔄 容器 '$container_name' 存在但未运行,正在启动..."
$sudoset docker start "$container_name"
sleep 3
if $sudoset docker ps --format '{{.Names}}' | grep -wq "^$container_name$"; then
log "INFO" "✅ 容器 '$container_name' 已成功启动"
return 0
else
log "ERROR" "⛔ 容器启动失败,请检查日志: docker logs $container_name"
return 1
fi
fi
# ========================================
# 🚀 函数:start_java_meeting_service
# 描述:启动对外服务并将服务写入服务器自启动
# 功能:
# - 检查Java环境是否部署成功
# - 启动java-meeting-extapi服务
# - 检查服务进程是否启动成功
# - 将启动命令写入/etc/rc.d/rc.local实现自启动
# ========================================
function start_java_meeting_service() {
local service_dir="/data/services/api/java-meeting/java-meeting-extapi"
local run_script="$service_dir/run.sh"
local log_file="$service_dir/logs/ubains-INFO-AND-ERROR.log"
local rc_local="/etc/rc.d/rc.local"
local service_name="java-meeting-extapi"
log "INFO" "=================================================="
log "INFO" "🚀 正在启动对外服务: $service_name"
log "INFO" " 服务目录: $service_dir"
log "INFO" "=================================================="
# 1. 检查Java环境是否部署成功
log "INFO" "🔍 正在检查Java环境..."
source /etc/profile 2>/dev/null || . /etc/profile 2>/dev/null
source /etc/profile
if ! java -version >/dev/null 2>&1; then
log "ERROR" "❌ Java环境未部署或配置失败"
log "ERROR" " 请先执行 deploy_jdk_host 函数部署JDK"
log "ERROR" " 或手动执行: source /etc/profile"
return 1
fi
# ------------------- 检查挂载目录 -------------------
if [[ ! -d "$host_api_dir" ]]; then
log "ERROR" "⛔ 应用目录不存在: $host_api_dir,请先上传代码"
local java_version=$(java -version 2>&1 | head -n1)
log "INFO" "✅ Java环境检查通过: $java_version"
# 2. 检查服务目录和脚本是否存在
if [ ! -d "$service_dir" ]; then
log "ERROR" "❌ 服务目录不存在: $service_dir"
return 1
fi
if [[ ! -f "$host_api_dir/start.sh" ]]; then
log "ERROR" "⛔ 启动脚本缺失: $host_api_dir/start.sh"
if [ ! -f "$run_script" ]; then
log "ERROR" "❌ 启动脚本不存在: $run_script"
return 1
fi
# ------------------- 加载镜像 -------------------
if $sudoset docker images --format '{{.Repository}}:{{.Tag}}' | grep -Fq "$image_tag"; then
log "INFO" "✅ 镜像 $image_tag 已存在,跳过加载"
else
log "INFO" "📦 正在从离线包加载镜像: $image_tar"
if [[ -f "$image_tar" ]]; then
$sudoset docker load -i "$image_tar"
if [[ $? -ne 0 ]]; then
log "ERROR" "⛔ 镜像加载失败,请检查文件完整性: $image_tar"
return 1
fi
log "INFO" "🎉 镜像加载成功: $image_tag"
else
log "ERROR" "⛔ 镜像文件不存在: $image_tar"
return 1
fi
fi
# ------------------- 启动新容器 -------------------
log "INFO" "🚀 正在创建并启动容器 '$container_name'..."
$sudoset docker run -d \
--name "$container_name" \
--restart=always \
--mac-address="02:42:ac:11:00:07" \
--privileged \
-p 8000:8000 \
-p 8002:8002 \
-v "$host_api_dir:/var/www/html" \
-v "/etc/localtime:/etc/localtime:ro" \
-v /usr/share/zoneinfo:/usr/share/zoneinfo:ro \
"$image_tag" \
"$container_start_cmd"
if [[ $? -ne 0 ]]; then
log "ERROR" "⛔ 容器创建失败,请检查参数或资源"
return 1
# 确保脚本有执行权限
if [ ! -x "$run_script" ]; then
log "INFO" "🔧 正在为启动脚本添加执行权限..."
chmod +x "$run_script"
fi
log "INFO" "✅ 容器 '$container_name' 创建并启动成功"
log "INFO" "✅ 服务目录和脚本检查通过"
# ------------------- 状态验证 -------------------
sleep 3
if $sudoset docker ps --format '{{.Names}}' | grep -wq "^$container_name$"; then
log "INFO" "🟢 Python 服务运行中 → 访问端口: 8000, 8002"
else
log "ERROR" "⛔ 容器启动后退出,请查看日志: docker logs $container_name"
# 3. 检查服务是否已经在运行
cd "$service_dir" || {
log "ERROR" "❌ 无法进入服务目录: $service_dir"
return 1
fi
return 0
}
#播放器系统
#x86架构python安装
function python_player_x86() {
echo -e "\033[36m* 正在检查Python服务是否安装......\033[0m"
# 检查Docker镜像和容器状态
local image_exists=$(docker images | grep -q python && echo "true" || echo "false")
local container_running=$(docker ps | grep -q uplayer && echo "true" || echo "false")
local player_dir="/var/www/player"
local source_player_dir="/home/player_auto_install/player"
local docker_image_path="/home/player_auto_install/server_bag/upython_player.tar.gz"
local start_script="/var/www/player/start.sh"
if [[ "$image_exists" == "true" && "$container_running" == "true" ]]; then
echo -e "\033[32m* 检查到Python已安装!正在安装下一个服务....\033[0m"
return 0
else
echo -e "\033[33m* 检查到Python服务未安装,正在安装服务....\033[0m"
# 加载Docker镜像并验证其存在
if [ ! -f "$docker_image_path" ]; then
echo -e "\033[31m* 错误: Docker镜像文件 $docker_image_path 不存在。\033[0m"
return 1
fi
if ! docker load -i "$docker_image_path"; then
echo -e "\033[31m* 加载Docker镜像失败。\033[0m"
return 1
fi
# 标记Docker镜像
if ! docker tag e449dd1ea3af 139.9.60.86:5000/upython:v11; then
echo -e "\033[31m* 标记Docker镜像失败。\033[0m"
return 1
fi
# 检查player目录是否存在,如果不存在则复制
if [ ! -d "$source_player_dir" ]; then
echo -e "\033[31m* 错误: 源目录 $source_player_dir 不存在。\033[0m"
return 1
fi
if [ ! -d "$player_dir" ]; then
mkdir -p /var/www/player
if ! cp -rp "$source_player_dir" /var/www/; then
echo -e "\033[31m* 复制player目录失败。\033[0m"
return 1
else
echo -e "\033[32m* 成功复制 player 目录。\033[0m"
chmod_files=(
"$player_dir/start.sh"
"$player_dir/manage.py"
"$player_dir/uuwsgi.ini"
"$player_dir/uplayer"
"$player_dir/UbainsDevOps"
)
chmod 755 -R "${chmod_files[@]}"
fi
else
echo -e "\033[32m* 目录 $player_dir 已存在,跳过复制。\033[0m"
fi
}
# 确认启动脚本存在
if [ ! -f "$start_script" ]; then
echo -e "\033[31m* 错误: 启动脚本 $start_script 不存在。\033[0m"
return 1
fi
# 启动容器,并指定固定的MAC地址
if ! docker run -itd \
--mac-address="02:42:ac:12:00:05" \
-p 18082:8082 -p 11883:1883 -p 8000:8000 -p 9001:9001 -p 8002:8002\
-v /var/www/player:/var/www/html \
-v /etc/localtime:/etc/localtime:ro \
-v /usr/share/zoneinfo:/usr/share/zoneinfo:ro \
--restart=always \
--privileged \
--name=uplayer \
139.9.60.86:5000/upython:v11 \
/root/start.sh; then
echo -e "\033[31m* 启动Python容器失败。\033[0m"
return 1
else
echo -e "\033[32m* Python服务安装完成并启动成功!\033[0m"
fi
# 尝试通过进程名或日志判断服务是否已运行
local process_count=$(pgrep -f "java-meeting-extapi\|run.sh" 2>/dev/null | wc -l)
if [ "$process_count" -gt 0 ]; then
log "WARN" "⚠️ 检测到服务可能已在运行(进程数: $process_count)"
log "INFO" " 将尝试重新启动服务"
fi
}
#x86架构ntp安装
function ntp_x86()
{
# 判断是否为centos7 否则跳出函数
if [ ! -f /etc/redhat-release ]; then
log "ERROR" "当前系统不是CentOS 7,无法安装NTP服务"
return 1
fi
log "INFO" "检查ntp服务......"
$sudoset systemctl status ntpd |grep running
#ps -aux | grep ntp
if [ $? -eq 0 ]; then
log "INFO" "检查到ntp已安装!"
else
log "WARN" "检查到ntp未安装,正在安装..."
$sudoset cd $auto_java/server_bag/ntp
$sudoset rpm -Uvh *.rpm --nodeps --force
$sudoset systemctl enable ntpd
$sudoset systemctl enable ntpdate
$sudoset systemctl start ntpd
$sudoset systemctl status ntpd
$sudoset mv /etc/ntp.conf /etc/ntp.confbak
$sudoset cp $auto_java/server_bag/ntp/ntp.conf /etc/
$sudoset systemctl restart ntpd
$sudoset systemctl disable chronyd
log "INFO" "完成ntp服务的安装"
fi
}
# 4. 启动服务
log "INFO" "▶️ 正在启动服务..."
# ========================================
# 🐍 函数:python_voice_x86
# 描述:部署 upython 容器服务(语音平台后端)
# 功能:
# - 检查是否已有 upython_voice 容器运行
# - 若无,则加载镜像、打标签并启动容器
# - 挂载新路径(生产环境路径)
# - 端口映射:8003:8000, 8004:8002, 8080:8080
# - 固定 MAC 地址
# ========================================
function python_voice_x86() {
log "INFO" "=================================================================="
log "INFO" "开始部署 Python_voice 容器 (upython_voice) - x86"
log "INFO" "=================================================================="
# 确保日志目录存在
mkdir -p "$(dirname "$log_file")"
local service_name="Python 语音后端服务"
local container_name="upython_voice"
local image_tar="/data/offline_auto_unifiedPlatform/data/temp/uvoice3.tar.gz"
local source_image_id="2a69026b2899"
local target_image_tag="139.9.60.86:5000/upython:v13"
# ✅ 更新为实际的生产挂载路径
local mounts=(
"/data/services/api/python-voice:/var/www/html/api"
"/usr/share/zoneinfo:/usr/share/zoneinfo:ro"
"/data/services/web/pc/pc-vue2-voice:/var/www/html/web"
"/data/third_party/iFlyTrans/iflytek/iListen/voicePath:/home/iflytek/iListen/voicePath"
"/data/third_party/iFlyTrans/iflytek/lingtOnlineHZ/online/:/home/iflytek/lingtOnlineHZ/online"
"/data/third_party/iFlyTrans/ubains/lingtOnlineHZ/online:/home/ubains/lingtOnlineHZ/online"
"/data/third_party/iFlyTrans/iflytek/huiyi/:/home/iflytek/huiyi/"
"/data/services/api/python-voice/start.sh:/root/start.sh" # 添加到这里
)
# 执行启动命令:./run.sh
log "INFO" "📝 执行启动命令: ./run.sh"
./run.sh > "$service_dir/nohup.out" 2>&1 &
local start_pid=$!
log "INFO" "=================================================="
log "INFO" "🚀 正在部署:$service_name"
log "INFO" "容器名称: $container_name"
log "INFO" "镜像文件: $image_tar"
log "INFO" "=================================================="
# 等待几秒让服务启动
log "INFO" "⏳ 等待服务启动(5秒)..."
sleep 5
# 1. 检查容器是否已在运行
if docker ps --format '{{.Names}}' | grep -qw "^$container_name$"; then
log "WARN" "✅ 容器 '$container_name' 已在运行,退出自动部署!!!"
return 0
# 执行tail -f查看日志(后台运行,避免阻塞)
log "INFO" "📋 正在查看服务日志: tail -f $log_file"
if [ -f "$log_file" ]; then
# 显示最后20行日志
log "INFO" "📄 最新日志内容(最后20行):"
tail -n 20 "$log_file" 2>/dev/null | while read line; do
log "INFO" " $line"
done
# 后台运行tail -f,输出到nohup
nohup tail -f "$log_file" >> "$service_dir/tail.log" 2>&1 &
log "INFO" "✅ 日志监控已启动(后台运行),实时日志输出到: $service_dir/tail.log"
else
log "WARN" "⚠️ 日志文件尚未创建: $log_file"
log "INFO" " 服务可能正在启动中,请稍后查看日志"
fi
# 2. 检查容器是否已存在(即使未运行)
if docker ps -a --format '{{.Names}}' | grep -qw "^$container_name$"; then
log "WARN" "⛔ 容器 '$container_name' 已存在,退出自动部署!!!"
return 0
# 5. 检查服务进程是否启动成功
log "INFO" "🔍 正在检查服务进程..."
# 检查run.sh进程
local run_pid=$(pgrep -f "run.sh" | head -n1)
if [ -n "$run_pid" ]; then
log "INFO" "✅ 启动脚本进程已运行(PID: $run_pid)"
else
log "WARN" "⚠️ 未检测到启动脚本进程,服务可能启动失败"
fi
# 赋予启动脚本执行权限
local host_start_script="/data/services/api/python-voice/start.sh"
if [ -f "$host_start_script" ]; then
log "INFO" "🔧 修复宿主机启动脚本权限..."
chmod +x "$host_start_script"
log "INFO" "✅ 宿主机脚本权限已修复: $host_start_script"
# 检查Java进程(通过服务目录或进程名)
local java_pids=$(pgrep -f "java.*$service_dir\|java-meeting-extapi" 2>/dev/null)
if [ -n "$java_pids" ]; then
log "INFO" "✅ Java服务进程已启动"
echo "$java_pids" | while read pid; do
log "INFO" " PID: $pid"
done
else
log "WARN" "⚠️ 宿主机启动脚本不存在: $host_start_script"
log "WARN" "⚠️ 未检测到Java服务进程,请检查日志: $log_file"
log "WARN" " 或查看: $service_dir/nohup.out"
fi
# 3. 检查目标镜像是否存在
if docker images --format '{{.Repository}}:{{.Tag}}' | grep -qw "^$target_image_tag$"; then
log "WARN" "✅ 镜像已存在: $target_image_tag"
# 检查日志文件是否存在(服务启动后会创建日志文件)
if [ -f "$log_file" ]; then
log "INFO" "✅ 日志文件已创建: $log_file"
# 显示最后几行日志
log "INFO" "📋 最新日志内容:"
tail -n 10 "$log_file" 2>/dev/null | while read line; do
log "INFO" " $line"
done
else
# 4. 检查镜像压缩包是否存在
if [ ! -f "$image_tar" ]; then
log "INFO" "❌ 镜像文件不存在: $image_tar"
return 1
fi
log "WARN" "⚠️ 日志文件尚未创建,服务可能正在启动中"
fi
log "INFO" "🐳 正在加载 upython 镜像..."
if ! docker load -i "$image_tar"; then
log "ERROR" "❌ 镜像加载失败,请检查文件完整性"
return 1
fi
log "INFO" "✅ 镜像加载完成"
# 6. 将启动命令写入/etc/rc.d/rc.local实现自启动
log "INFO" "📝 正在配置服务自启动..."
# 检查rc.local文件是否存在
if [ ! -f "$rc_local" ]; then
log "INFO" "📁 rc.local文件不存在,正在创建..."
sudo touch "$rc_local"
sudo chmod +x "$rc_local"
fi
# 5. 构建挂载参数 - 正确的方式
local mount_args=()
for mount in "${mounts[@]}"; do
mount_args+=("-v")
mount_args+=("$mount")
done
# 构建启动命令(按照用户要求:cd目录,执行run.sh,tail -f日志)
# 注意:在rc.local中,tail -f会阻塞,所以使用后台运行
local startup_cmd="cd $service_dir && ./run.sh > $service_dir/nohup.out 2>&1 &"
local tail_cmd="tail -f $log_file >> $service_dir/tail.log 2>&1 &"
# 6. 启动容器
log "INFO" "🚀 正在启动容器 '$container_name'..."
docker run -itd \
--name "$container_name" \
--mac-address="02:42:ac:11:00:24" \
--restart=always \
-p 8003:8000 \
-p 8004:8002 \
-p 8080:8080 \
"${mount_args[@]}" \
"$target_image_tag"
# 检查是否已经存在相同的启动命令
if grep -q "$service_dir.*run.sh" "$rc_local" 2>/dev/null; then
log "INFO" "✅ 自启动配置已存在,跳过添加"
else
# 备份rc.local
if [ -f "$rc_local" ]; then
sudo cp "$rc_local" "${rc_local}.backup.$(date +%Y%m%d_%H%M%S)" 2>/dev/null
log "INFO" "✅ 已备份rc.local文件"
fi
if [ $? -ne 0 ]; then
log "ERROR" "❌ 容器启动失败,请检查端口占用或权限问题"
return 1
fi
# 添加启动命令到rc.local
log "INFO" "📝 正在添加启动命令到 $rc_local"
echo "" | sudo tee -a "$rc_local" > /dev/null
echo "# Auto-start java-meeting-extapi service - $(date '+%Y-%m-%d %H:%M:%S')" | sudo tee -a "$rc_local" > /dev/null
echo "cd $service_dir && ./run.sh > $service_dir/nohup.out 2>&1 &" | sudo tee -a "$rc_local" > /dev/null
echo "tail -f $log_file >> $service_dir/tail.log 2>&1 &" | sudo tee -a "$rc_local" > /dev/null
# 7. 验证容器状态
sleep 3
if docker ps --format '{{.Names}}' | grep -qw "^$container_name$"; then
local cid=$(docker ps --filter "name=$container_name" --format "{{.ID}}")
log "INFO" "✅ 容器启动成功!"
log "INFO" "🏷 名称: $container_name"
log "INFO" "🔢 ID: $cid"
log "INFO" "🌐 端口: 8003→8000, 8004→8002, 8080→8080"
log "INFO" "📁 共挂载 ${#mounts[@]} 个目录"
else
log "ERROR" "❌ 容器启动后退出,请执行 'docker logs $container_name' 查看日志"
return 1
# 确保rc.local有执行权限
sudo chmod +x "$rc_local" 2>/dev/null
log "INFO" "✅ 自启动配置已添加到 $rc_local"
log "INFO" " 启动命令: cd $service_dir && ./run.sh"
log "INFO" " 日志监控: tail -f $log_file"
fi
log "INFO" "🎉 $service_name 部署成功!"
log "INFO" "=================================================="
log "INFO" "🎉 服务启动流程完成!"
log "INFO" " 服务目录: $service_dir"
log "INFO" " 日志文件: $log_file"
log "INFO" " 自启动配置: $rc_local"
log "INFO" " 提示: 可以使用 'tail -f $log_file' 查看实时日志"
log "INFO" "=================================================="
return 0
}
#部署宿主机java服务
# ========================================
# ☕ 函数:deploy_jdk_host
......@@ -1090,42 +930,42 @@ function python_voice_x86() {
function deploy_jdk_host() {
local jdk_tar_path="/data/temp/jdk-8u472-linux-x64.tar.gz"
local install_base_dir="${2:-/opt/java}"
log "INFO" "=================================================="
log "INFO" "☕ 正在部署宿主机JDK"
log "INFO" " JDK安装包: $jdk_tar_path"
log "INFO" " 安装目录: $install_base_dir"
log "INFO" "=================================================="
# 1. 检查JDK安装包是否存在
if [ -z "$jdk_tar_path" ]; then
log "ERROR" "❌ 未指定JDK安装包路径"
log "INFO" "用法: deploy_jdk_host <jdk_tar.gz路径> [安装目录]"
return 1
fi
if [ ! -f "$jdk_tar_path" ]; then
log "ERROR" "❌ JDK安装包不存在: $jdk_tar_path"
return 1
fi
# 检查是否为tar.gz格式
if [[ ! "$jdk_tar_path" =~ \.tar\.gz$ ]]; then
log "ERROR" "❌ 文件格式错误,需要tar.gz格式: $jdk_tar_path"
return 1
fi
log "INFO" "✅ JDK安装包检查通过"
# 2. 检查是否已安装JDK,并进行备份
local old_java_home=""
local old_java_version=""
local backup_dir="/opt/java_backup_$(date +%Y%m%d_%H%M%S)"
if command -v java &> /dev/null; then
old_java_version=$(java -version 2>&1 | head -n1)
log "INFO" "📋 检测到系统已安装Java: $old_java_version"
# 获取旧的JAVA_HOME
if [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ]; then
old_java_home="$JAVA_HOME"
......@@ -1138,7 +978,7 @@ function deploy_jdk_host() {
old_java_home=$(dirname "$(dirname "$java_path")" 2>/dev/null)
fi
fi
# 备份旧的JDK目录
if [ -n "$old_java_home" ] && [ -d "$old_java_home" ] && [ "$old_java_home" != "$install_base_dir" ]; then
log "INFO" "💾 正在备份旧JDK目录: $old_java_home"
......@@ -1152,7 +992,7 @@ function deploy_jdk_host() {
fi
fi
fi
# 备份/etc/profile中的Java配置
log "INFO" "💾 正在备份/etc/profile中的Java配置..."
mkdir -p "$backup_dir"
......@@ -1162,7 +1002,7 @@ function deploy_jdk_host() {
log "INFO" "✅ /etc/profile已备份到: $backup_dir/profile.backup"
fi
fi
# 记录旧Java信息到备份目录
if [ -d "$backup_dir" ]; then
{
......@@ -1171,10 +1011,10 @@ function deploy_jdk_host() {
echo "旧JAVA_HOME: $old_java_home"
} > "$backup_dir/old_java_info.txt" 2>/dev/null
fi
log "INFO" "🔄 将自动更新Java环境..."
fi
# 3. 创建安装目录
mkdir -p "$install_base_dir"
if [ $? -ne 0 ]; then
......@@ -1182,14 +1022,14 @@ function deploy_jdk_host() {
return 1
fi
log "INFO" "✅ 创建安装目录: $install_base_dir"
# 4. 解压JDK
log "INFO" "🗜️ 正在解压JDK安装包..."
cd "$install_base_dir" || {
log "ERROR" "❌ 无法进入目录: $install_base_dir"
return 1
}
# 解压到当前目录
tar -xzf "$jdk_tar_path" -C "$install_base_dir"
if [ $? -ne 0 ]; then
......@@ -1197,7 +1037,7 @@ function deploy_jdk_host() {
return 1
fi
log "INFO" "✅ JDK解压完成"
# 5. 查找解压后的JDK目录(通常是jdk8u472-b08或类似格式)
local jdk_dir=$(find "$install_base_dir" -maxdepth 1 -type d -name "jdk*" | head -n1)
if [ -z "$jdk_dir" ]; then
......@@ -1205,22 +1045,22 @@ function deploy_jdk_host() {
log "INFO" "请检查解压后的目录结构"
return 1
fi
local jdk_home="$jdk_dir"
local jdk_name=$(basename "$jdk_dir")
log "INFO" "✅ 找到JDK目录: $jdk_name"
log "INFO" " JDK_HOME: $jdk_home"
# 6. 检查JDK目录结构是否完整
if [ ! -d "$jdk_home/bin" ] || [ ! -f "$jdk_home/bin/java" ]; then
log "ERROR" "❌ JDK目录结构不完整,缺少bin/java文件"
return 1
fi
log "INFO" "✅ JDK目录结构检查通过"
# 7. 配置Java环境变量
log "INFO" "🛠️ 正在配置Java环境变量..."
# 检查/etc/profile中是否已存在JAVA_HOME配置,并备份后注释掉
if grep -q "JAVA_HOME\|#set java environment" /etc/profile; then
log "INFO" "📋 检测到/etc/profile中已存在JAVA_HOME配置,将注释旧配置并添加新配置"
......@@ -1230,7 +1070,7 @@ function deploy_jdk_host() {
cp /etc/profile "$backup_dir/profile.backup" 2>/dev/null
log "INFO" "✅ /etc/profile已备份到: $backup_dir/profile.backup"
fi
# 使用awk来注释掉Java配置块(更可靠,处理多行块)
awk '
BEGIN { in_java_block = 0 }
......@@ -1273,7 +1113,7 @@ function deploy_jdk_host() {
log "WARN" "⚠️ 注释旧配置时出现问题,继续安装"
fi
fi
# 添加新的Java环境变量配置
cat >> /etc/profile << EOF
......@@ -1283,9 +1123,9 @@ CLASSPATH=.:\$JAVA_HOME/lib/tools.jar
PATH=\$JAVA_HOME/bin:\$PATH
export JAVA_HOME CLASSPATH PATH
EOF
log "INFO" "✅ Java环境变量已写入 /etc/profile"
# 8. 立即在当前会话中生效
log "INFO" "🔄 正在重新加载 /etc/profile 使环境变量生效..."
source /etc/profile 2>/dev/null || . /etc/profile 2>/dev/null
......@@ -1298,9 +1138,9 @@ EOF
export CLASSPATH=".:$JAVA_HOME/lib/tools.jar"
export PATH="$JAVA_HOME/bin:$PATH"
fi
log "INFO" "✅ 环境变量已在当前会话中生效"
# 9. 验证Java安装
log "INFO" "🔍 正在验证Java安装..."
if java -version >/dev/null 2>&1; then
......@@ -1315,795 +1155,14 @@ EOF
log "INFO" " 请手动执行: source /etc/profile"
return 1
fi
log "INFO" "=================================================="
log "INFO" "🎉 JDK部署成功!"
log "INFO" " 安装路径: $jdk_home"
log "INFO" " 环境变量已配置到 /etc/profile"
log "INFO" " 提示: 新开终端或执行 'source /etc/profile' 使环境变量生效"
log "INFO" "=================================================="
return 0
}
# ========================================
# 🚀 函数:start_java_meeting_service
# 描述:启动对外服务并将服务写入服务器自启动
# 功能:
# - 检查Java环境是否部署成功
# - 启动java-meeting-extapi服务
# - 检查服务进程是否启动成功
# - 将启动命令写入/etc/rc.d/rc.local实现自启动
# ========================================
function start_java_meeting_service() {
local service_dir="/data/services/api/java-meeting/java-meeting-extapi"
local run_script="$service_dir/run.sh"
local log_file="$service_dir/logs/ubains-INFO-AND-ERROR.log"
local rc_local="/etc/rc.d/rc.local"
local service_name="java-meeting-extapi"
log "INFO" "=================================================="
log "INFO" "🚀 正在启动对外服务: $service_name"
log "INFO" " 服务目录: $service_dir"
log "INFO" "=================================================="
# 1. 检查Java环境是否部署成功
log "INFO" "🔍 正在检查Java环境..."
source /etc/profile 2>/dev/null || . /etc/profile 2>/dev/null
source /etc/profile
if ! java -version >/dev/null 2>&1; then
log "ERROR" "❌ Java环境未部署或配置失败"
log "ERROR" " 请先执行 deploy_jdk_host 函数部署JDK"
log "ERROR" " 或手动执行: source /etc/profile"
return 1
fi
local java_version=$(java -version 2>&1 | head -n1)
log "INFO" "✅ Java环境检查通过: $java_version"
# 2. 检查服务目录和脚本是否存在
if [ ! -d "$service_dir" ]; then
log "ERROR" "❌ 服务目录不存在: $service_dir"
return 1
fi
if [ ! -f "$run_script" ]; then
log "ERROR" "❌ 启动脚本不存在: $run_script"
return 1
fi
# 确保脚本有执行权限
if [ ! -x "$run_script" ]; then
log "INFO" "🔧 正在为启动脚本添加执行权限..."
chmod +x "$run_script"
fi
log "INFO" "✅ 服务目录和脚本检查通过"
# 3. 检查服务是否已经在运行
cd "$service_dir" || {
log "ERROR" "❌ 无法进入服务目录: $service_dir"
return 1
}
# 尝试通过进程名或日志判断服务是否已运行
local process_count=$(pgrep -f "java-meeting-extapi\|run.sh" 2>/dev/null | wc -l)
if [ "$process_count" -gt 0 ]; then
log "WARN" "⚠️ 检测到服务可能已在运行(进程数: $process_count)"
log "INFO" " 将尝试重新启动服务"
fi
# 4. 启动服务
log "INFO" "▶️ 正在启动服务..."
# 确保日志目录存在
mkdir -p "$(dirname "$log_file")"
# 执行启动命令:./run.sh
log "INFO" "📝 执行启动命令: ./run.sh"
./run.sh > "$service_dir/nohup.out" 2>&1 &
local start_pid=$!
# 等待几秒让服务启动
log "INFO" "⏳ 等待服务启动(5秒)..."
sleep 5
# 执行tail -f查看日志(后台运行,避免阻塞)
log "INFO" "📋 正在查看服务日志: tail -f $log_file"
if [ -f "$log_file" ]; then
# 显示最后20行日志
log "INFO" "📄 最新日志内容(最后20行):"
tail -n 20 "$log_file" 2>/dev/null | while read line; do
log "INFO" " $line"
done
# 后台运行tail -f,输出到nohup
nohup tail -f "$log_file" >> "$service_dir/tail.log" 2>&1 &
log "INFO" "✅ 日志监控已启动(后台运行),实时日志输出到: $service_dir/tail.log"
else
log "WARN" "⚠️ 日志文件尚未创建: $log_file"
log "INFO" " 服务可能正在启动中,请稍后查看日志"
fi
# 5. 检查服务进程是否启动成功
log "INFO" "🔍 正在检查服务进程..."
# 检查run.sh进程
local run_pid=$(pgrep -f "run.sh" | head -n1)
if [ -n "$run_pid" ]; then
log "INFO" "✅ 启动脚本进程已运行(PID: $run_pid)"
else
log "WARN" "⚠️ 未检测到启动脚本进程,服务可能启动失败"
fi
# 检查Java进程(通过服务目录或进程名)
local java_pids=$(pgrep -f "java.*$service_dir\|java-meeting-extapi" 2>/dev/null)
if [ -n "$java_pids" ]; then
log "INFO" "✅ Java服务进程已启动"
echo "$java_pids" | while read pid; do
log "INFO" " PID: $pid"
done
else
log "WARN" "⚠️ 未检测到Java服务进程,请检查日志: $log_file"
log "WARN" " 或查看: $service_dir/nohup.out"
fi
# 检查日志文件是否存在(服务启动后会创建日志文件)
if [ -f "$log_file" ]; then
log "INFO" "✅ 日志文件已创建: $log_file"
# 显示最后几行日志
log "INFO" "📋 最新日志内容:"
tail -n 10 "$log_file" 2>/dev/null | while read line; do
log "INFO" " $line"
done
else
log "WARN" "⚠️ 日志文件尚未创建,服务可能正在启动中"
fi
# 6. 将启动命令写入/etc/rc.d/rc.local实现自启动
log "INFO" "📝 正在配置服务自启动..."
# 检查rc.local文件是否存在
if [ ! -f "$rc_local" ]; then
log "INFO" "📁 rc.local文件不存在,正在创建..."
sudo touch "$rc_local"
sudo chmod +x "$rc_local"
fi
# 构建启动命令(按照用户要求:cd目录,执行run.sh,tail -f日志)
# 注意:在rc.local中,tail -f会阻塞,所以使用后台运行
local startup_cmd="cd $service_dir && ./run.sh > $service_dir/nohup.out 2>&1 &"
local tail_cmd="tail -f $log_file >> $service_dir/tail.log 2>&1 &"
# 检查是否已经存在相同的启动命令
if grep -q "$service_dir.*run.sh" "$rc_local" 2>/dev/null; then
log "INFO" "✅ 自启动配置已存在,跳过添加"
else
# 备份rc.local
if [ -f "$rc_local" ]; then
sudo cp "$rc_local" "${rc_local}.backup.$(date +%Y%m%d_%H%M%S)" 2>/dev/null
log "INFO" "✅ 已备份rc.local文件"
fi
# 添加启动命令到rc.local
log "INFO" "📝 正在添加启动命令到 $rc_local"
echo "" | sudo tee -a "$rc_local" > /dev/null
echo "# Auto-start java-meeting-extapi service - $(date '+%Y-%m-%d %H:%M:%S')" | sudo tee -a "$rc_local" > /dev/null
echo "cd $service_dir && ./run.sh > $service_dir/nohup.out 2>&1 &" | sudo tee -a "$rc_local" > /dev/null
echo "tail -f $log_file >> $service_dir/tail.log 2>&1 &" | sudo tee -a "$rc_local" > /dev/null
# 确保rc.local有执行权限
sudo chmod +x "$rc_local" 2>/dev/null
log "INFO" "✅ 自启动配置已添加到 $rc_local"
log "INFO" " 启动命令: cd $service_dir && ./run.sh"
log "INFO" " 日志监控: tail -f $log_file"
fi
log "INFO" "=================================================="
log "INFO" "🎉 服务启动流程完成!"
log "INFO" " 服务目录: $service_dir"
log "INFO" " 日志文件: $log_file"
log "INFO" " 自启动配置: $rc_local"
log "INFO" " 提示: 可以使用 'tail -f $log_file' 查看实时日志"
log "INFO" "=================================================="
return 0
}
# ========================================
# 🔧 函数:malan
# 描述:配置 malan 服务自启动(写入 /etc/rc.local)
# 功能:
# - 检查 /etc/rc.local 文件是否存在
# - 检查是否已存在 malan 启动命令(避免重复添加)
# - 将启动命令写入 /etc/rc.local
# - 确保文件有执行权限
# ========================================
function malan() {
local rc_local="/etc/rc.local"
local service_dir="/data/middleware/monitor"
local startup_cmd="cd /data/middleware/monitor/ && nohup ./malan &"
log "INFO" "=================================================="
log "INFO" "🔧 正在配置 malan 服务自启动"
log "INFO" " 服务目录: $service_dir"
log "INFO" "=================================================="
# 1. 检查服务目录是否存在
if [ ! -d "$service_dir" ]; then
log "WARN" "⚠️ 服务目录不存在: $service_dir"
log "WARN" " 将尝试创建目录..."
mkdir -p "$service_dir" 2>/dev/null || {
log "ERROR" "❌ 无法创建目录: $service_dir"
return 1
}
log "INFO" "✅ 目录已创建: $service_dir"
fi
# 2. 检查 malan 可执行文件是否存在
if [ ! -f "$service_dir/malan" ]; then
log "WARN" "⚠️ malan 可执行文件不存在: $service_dir/malan"
log "WARN" " 将继续配置自启动,但请确保文件已部署"
else
# 确保文件有执行权限
if [ ! -x "$service_dir/malan" ]; then
log "INFO" "🔧 正在为 malan 添加执行权限..."
chmod +x "$service_dir/malan" 2>/dev/null || {
log "WARN" "⚠️ 无法添加执行权限,可能需要 root 权限"
}
fi
log "INFO" "✅ malan 文件检查通过"
fi
# 3. 检查 /etc/rc.local 文件是否存在
if [ ! -f "$rc_local" ]; then
log "INFO" "📁 rc.local 文件不存在,正在创建..."
touch "$rc_local" 2>/dev/null || {
log "ERROR" "❌ 无法创建 $rc_local,请检查权限"
return 1
}
# 添加 shebang 行(如果文件为空)
echo "#!/bin/bash" > "$rc_local"
log "INFO" "✅ rc.local 文件已创建"
fi
# 确保 rc.local 有执行权限
if [ ! -x "$rc_local" ]; then
log "INFO" "🔧 正在为 rc.local 添加执行权限..."
chmod +x "$rc_local" 2>/dev/null || {
log "WARN" "⚠️ 无法添加执行权限,可能需要 root 权限"
}
fi
# 4. 检查是否已经存在相同的启动命令
if grep -Fq "cd /data/middleware/monitor/ && nohup ./malan &" "$rc_local" 2>/dev/null; then
log "INFO" "✅ malan 自启动配置已存在,跳过添加"
return 0
fi
# 5. 备份 rc.local
if [ -f "$rc_local" ]; then
local backup_file="${rc_local}.backup.$(date +%Y%m%d_%H%M%S)"
cp "$rc_local" "$backup_file" 2>/dev/null
if [ $? -eq 0 ]; then
log "INFO" "✅ 已备份 rc.local 文件: $backup_file"
else
log "WARN" "⚠️ 备份 rc.local 失败,继续执行"
fi
fi
# 6. 添加启动命令到 rc.local
log "INFO" "📝 正在添加 malan 启动命令到 $rc_local"
# 确保文件末尾有换行符
if [ -s "$rc_local" ] && [ "$(tail -c 1 "$rc_local")" != "" ]; then
echo "" >> "$rc_local"
fi
# 添加注释和启动命令
echo "# Auto-start malan service - $(date '+%Y-%m-%d %H:%M:%S')" >> "$rc_local"
echo "$startup_cmd" >> "$rc_local"
if [ $? -eq 0 ]; then
log "INFO" "✅ malan 自启动配置已添加到 $rc_local"
log "INFO" " 启动命令: $startup_cmd"
else
log "ERROR" "❌ 写入 $rc_local 失败,请检查权限"
return 1
fi
# 7. 验证写入的内容
if grep -Fq "cd /data/middleware/monitor/ && nohup ./malan &" "$rc_local" 2>/dev/null; then
log "INFO" "✅ 配置验证成功"
else
log "WARN" "⚠️ 配置验证失败,请手动检查 $rc_local"
fi
log "INFO" "=================================================="
log "INFO" "🎉 malan 自启动配置完成!"
log "INFO" " 配置文件: $rc_local"
log "INFO" " 提示: 系统重启后 malan 服务将自动启动"
log "INFO" "=================================================="
return 0
}
#x86架构统信、麒麟系统的ntp安装
function ntp_uos() {
# 判断如果是centos7就退出安装
if [ -f /etc/redhat-release ]; then
log "ERROR" "当前系统是CentOS 7,已经安装NTP服务,无需安装chrony服务"
return 1
fi
# 判断文件是否存在ntp1.aliyun.com地址
if grep -q "ntp1.aliyun.com" /etc/chrony.conf; then
log "INFO" "NTP配置文件中已存在ntp1.aliyun.com地址,无需重复添加"
return 0
fi
local config_dir="/data/temp/ntp"
local backup="/etc/chrony.confbak"
local target="/etc/chrony.conf"
# 切换目录(不需要 sudo)
cd "$config_dir" || { echo "无法进入目录: $config_dir"; return 1; }
# 备份原有配置
if [ -f "$target" ]; then
log "INFO" "正在备份旧配置文件到 $backup"
sudo cp "$target" "$backup"
fi
# 检查是否可以通外网,可以则配置外网的ntp服务器地址,不可以则询问是否有企业ntp服务器地址
if ! ping -c 1 ntp1.aliyun.com &> /dev/null; then
log "ERROR" "无法连接到外网NTP服务器 ntp1.aliyun.com,请检查网络连接"
read -p "是否有企业NTP服务器地址?(y/n): " yn
if [[ -z "$yn" || "$yn" =~ ^[yY]$ ]]; then
read -p "请输入企业NTP服务器地址: " custom_ntp
echo "server $custom_ntp iburst" | sudo tee -a "$target"
echo "allow all" | sudo tee -a "$target"
else
log "ERROR" "没有可用的NTP服务器地址,配置默认地址,请联系管理员"
echo "server ntp1.aliyun.com iburst" | sudo tee -a "$target"
echo "allow all" | sudo tee -a "$target"
fi
else
log "INFO" "可以连接到外网NTP服务器 ntp1.aliyun.com,继续配置"
# 如果可以连接到外网NTP服务器,则继续添加默认的NTP服务器地址
echo "server ntp1.aliyun.com iburst" | sudo tee -a "$target"
echo "server ntp2.aliyun.com iburst" | sudo tee -a "$target"
echo "server ntp3.aliyun.com iburst" | sudo tee -a "$target"
echo "allow all" | sudo tee -a "$target"
fi
# 输出同步地址到日志
log "INFO" "正在写入同步地址到 $target"
# 重启服务
log "INFO" "正在重启 chronyd 服务..."
sudo systemctl daemon-reload
sudo systemctl restart chronyd
sudo systemctl enable chronyd
sudo systemctl status chronyd
log "INFO" "chronyd 服务已重启并设置为开机自启"
}
# ========================================
# ☕ 函数:iListen_x86
# 描述:部署 iListen Java 语音服务(科大讯飞语音识别核心服务)
# 功能:
# - 卸载 OpenJDK 11
# - 安装 JDK 8u361
# - 配置 Java 环境变量
# - 复制依赖库文件与程序
# - 启动 iListen 服务
# 依赖:
# - 离线包路径: /data/offline_auto_unifiedPlatform/data/temp/iFlyTrans_server_bag/
# - 服务路径: /data/third_party/iFlyTrans/iflytek/iListen
# ========================================
function iListen_x86() {
local service_name="iListen 语音服务"
local source_bag="/data/offline_auto_unifiedPlatform/data/temp/iFlyTrans_server_bag"
local jdk_tar="jdk-8u361-linux-x64.tar.gz"
local deploy_path="/opt/deploy"
local java_install_dir="$deploy_path/java"
local jdk_home="$java_install_dir/jdk1.8.0_361"
local iflytek_home="/data/third_party/iFlyTrans/iflytek"
local lib64_dest="/usr/lib64"
local lib_dest="/usr/lib"
log "INFO" "=================================================="
log "INFO" "🚀 正在部署:$service_name"
log "INFO" " 源文件目录: $source_bag"
log "INFO" " 服务安装路径: $iflytek_home"
log "INFO" "=================================================="
# --- 1. 检查服务是否已部署(✅ 改为检查目录和脚本存在,而非 Java)---
local service_dir="$iflytek_home/iListen"
local restart_script="$service_dir/restart.sh"
if [[ -d "$service_dir" ]] && [[ -f "$restart_script" ]]; then
log "INFO" "✅ 检测到 $service_name 已部署,跳过安装,准备启动..."
cd "$service_dir" || {
log "ERROR" "❌ 无法进入服务目录: $service_dir"
return 1
}
log "INFO" "▶️ 正在启动 iListen 服务..."
nohup ./restart.sh > nohup.out 2>&1 &
sleep 10
if pgrep -f "iListen" > /dev/null; then
log "INFO" "✅ iListen 服务已启动(PID: $(pgrep -f iListen | head -n1))"
else
log "WARN" "⚠️ 服务启动但未检测到进程,请检查日志: $service_dir/nohup.out"
fi
log "INFO" "🎉 $service_name 部署成功!"
return 0
fi
# 2. 卸载旧版 OpenJDK(避免冲突)
log "INFO" "🔧 正在卸载旧版 OpenJDK..."
yum -y remove java-11-openjdk* > /dev/null 2>&1 || true
log "INFO" "✅ OpenJDK 卸载完成(如存在)"
# 3. 检查依赖文件是否存在
if [ ! -f "$source_bag/$jdk_tar" ]; then
log "ERROR" "❌ JDK 安装包不存在: $source_bag/$jdk_tar"
return 1
fi
if [ ! -d "$source_bag/lib" ] || [ ! -d "$source_bag/usrlib" ] || [ ! -d "$source_bag/iflytek" ]; then
log "ERROR" "❌ 源文件目录缺失,请检查: $source_bag"
return 1
fi
# 4. 创建部署目录
mkdir -p "$deploy_path" "$java_install_dir"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 无法创建部署目录: $deploy_path"
return 1
fi
log "INFO" "✅ 创建部署目录: $deploy_path"
# 5. 复制并解压 JDK
log "INFO" "📦 复制 JDK 安装包..."
cp "$source_bag/$jdk_tar" "$deploy_path/"
cd "$deploy_path" || {
log "ERROR" "❌ 无法进入目录: $deploy_path"
return 1
}
log "INFO" "🗜️ 正在解压 JDK..."
tar -xzf "$jdk_tar" -C "$java_install_dir"
if [ $? -ne 0 ]; then
log "ERROR" "❌ JDK 解压失败,请检查压缩包完整性"
return 1
fi
log "INFO" "✅ JDK 解压完成: $jdk_home"
# 6. 配置 Java 环境变量(✅ 按你原来的方式,不做任何改动)
log "INFO" "🛠️ 配置 Java 环境变量..."
cat >> /etc/profile << 'EOF'
#set java environment
JAVA_HOME=$JAVA_HOME
CLASSPATH=.:$JAVA_HOME/lib/tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
EOF
# 替换占位符为实际路径
sed -i "s|\$JAVA_HOME|$jdk_home|g" /etc/profile
# 立即在当前会话中生效
export JAVA_HOME="$jdk_home"
export CLASSPATH=".:$JAVA_HOME/lib/tools.jar"
export PATH="$JAVA_HOME/bin:$PATH"
# 验证 Java 安装
if java -version >/dev/null 2>&1; then
log "INFO" "✅ Java 环境配置成功: $(java -version 2>&1 | head -n1)"
else
log "ERROR" "❌ Java 环境配置失败,请检查路径或权限"
return 1
fi
# 7. 复制库文件和程序
log "INFO" "📤 正在复制依赖库和程序文件..."
cp -r "$source_bag/lib/"* "$lib64_dest"/ && echo "✅ 已复制 lib → /usr/lib64"
cp -r "$source_bag/usrlib/"* "$lib_dest"/ && echo "✅ 已复制 usrlib → /usr/lib"
if [ -d "/iflytek" ]; then
rm -rf "/iflytek"
fi
cp -r "$source_bag/iflytek" / && echo "✅ 已复制 iflytek 主程序到根目录"
mkdir -p "$(dirname "$iflytek_home")"
if [ ! -L "$iflytek_home" ] && [ ! -d "$iflytek_home" ]; then
ln -s "/iflytek" "$iflytek_home"
echo "✅ 创建软链接: $iflytek_home → /iflytek"
fi
log "INFO" "✅ 所有文件复制完成"
# 8. 启动服务
log "INFO" "▶️ 正在启动 iListen 服务..."
cd "$iflytek_home/iListen" || {
log "ERROR" "❌ 无法进入服务目录: $iflytek_home/iListen"
return 1
}
nohup ./restart.sh > nohup.out 2>&1 &
sleep 2
if pgrep -f "iListen" > /dev/null; then
log "INFO" "✅ iListen 服务已启动(PID: $(pgrep -f iListen | head -n1))"
else
log "WARN" "⚠️ 服务启动但未检测到进程,建议检查日志: $iflytek_home/iListen/nohup.out"
fi
log "INFO" "🎉 $service_name 部署成功!"
return 0
}
function getLatestVersion() {
log "INFO" "检查中间件最新版本信息"
#判断是否能够访问外网,不能就跳过联网检查
if ! curl -s --head "https://www.baidu.com" | grep "200 OK" > /dev/null; then
log "WARN" "无法访问外网,跳过最新版本检查"
return
fi
#todo:如果访问不到,就跳过,后面改成用自己的接口服务
log "INFO" "准备获取最新版本信息"
latest_nginx_version=$(curl -s "https://nginx.org/en/download.html" | grep -oP 'nginx-\K[0-9]+\.[0-9]+\.[0-9]+' | head -n 1)
latest_redis_version=$(curl -s "https://api.github.com/repos/redis/redis/releases/latest" | \
grep -m 1 '"tag_name"' | \
grep -oP '[0-9]+\.[0-9]+\.[0-9]+' )
latest_mysql_version=$(curl -s https://repo.mysql.com/yum/mysql-8.0-community/el/7/x86_64/ \
| grep -oP 'mysql-community-server-[0-9]+\.[0-9]+\.[0-9]+' \
| sort -V \
| tail -n 1 \
| grep -oP '[0-9]+\.[0-9]+\.[0-9]+'
)
log "INFO" "最新版本信息获取成功"
log "INFO" "准备获取本地版本信息"
current_nginx_version=$(docker exec ujava2 sh -c "/usr/local/nginx/sbin/nginx -v " 2>&1 | grep -oP 'nginx/\K[0-9\.]+')
current_redis_version=$(docker exec uredis sh -c "redis-server --version " 2>&1 | grep -oP 'Redis server v=\K[0-9\.]+')
current_mysql_version=$(docker exec umysql sh -c "mysql --version " 2>&1 | grep -oP 'mysql Ver \K[0-9\.]+')
log "INFO" "本地版本信息获取成功, 准备进行版本比较"
#比较不同的版本情况,不一样的给出告警提示
if [ "$latest_nginx_version" != "$current_nginx_version" ]; then
log "WARN" "Nginx版本不一致,最新版本: $latest_nginx_version, 当前版本: $current_nginx_version"
else
log "INFO" "Nginx版本一致,当前版本: $current_nginx_version"
fi
if [ "$latest_redis_version" != "$current_redis_version" ]; then
log "WARN" "Redis版本不一致,最新版本: $latest_redis_version, 当前版本: $current_redis_version"
else
log "INFO" "Redis版本一致,当前版本: $current_redis_version"
fi
if [ "$latest_mysql_version" != "$current_mysql_version" ]; then
log "WARN" "MySQL版本不一致,最新版本: $latest_mysql_version, 当前版本: $current_mysql_version"
else
log "INFO" "MySQL版本一致,当前版本: $current_mysql_version"
fi
log "INFO" "版本检查完成"
}
# 无纸化信令服务部署
function paperless_x86() {
log "INFO" "=================================================================="
log "INFO" "开始部署 Paperless 服务 (x86)"
log "INFO" "=================================================================="
# --- 配置参数 ---
local container_name="paperless"
local image_tar="/data/offline_auto_unifiedPlatform/data/temp/paperless.tar"
local image_tag="paperless:v1"
local host_data_dir="/data/third_party/paperless"
local start_script_host="$host_data_dir/start.sh"
local port_http="62121"
local port_nginx="62122"
local mac_address="02:42:ac:11:00:09"
# 判断是否需要 sudo
local SUDO=""
if [[ $(id -u) -ne 0 ]]; then
if command -v sudo >/dev/null; then
SUDO="sudo"
else
log "ERROR" "当前不是 root 用户,且未安装 sudo,无法继续"
return 1
fi
fi
# ------------------- 检查容器是否存在(关键变更)-------------------
log "INFO" "🔍 检查容器 '$container_name' 是否已存在..."
if $SUDO docker ps -a --format '{{.Names}}' | grep -qw "$container_name"; then
log "WARN" "⛔ 容器 '$container_name' 已存在(无论运行与否),自动退出部署操作!!!"
log "WARN" "如需重新部署,请先手动删除容器:docker rm -f $container_name"
return 0
else
log "INFO" "✅ 容器 '$container_name' 不存在,可以安全部署"
fi
# ------------------- 检查本地必要文件 -------------------
log "INFO" "🔍 检查本地部署文件..."
if [[ ! -f "$image_tar" ]]; then
log "ERROR" "缺少镜像文件: $image_tar"
return 1
fi
log "INFO" "✅ 本地所需文件检查通过"
# ------------------- 检查目标目录是否存在 -------------------
log "INFO" "🔍 检查目标目录 $host_data_dir 是否存在..."
if [[ ! -d "$host_data_dir" ]]; then
log "ERROR" "⛔ 目标目录不存在: $host_data_dir"
log "ERROR" "请确保 /data/third_party/paperless 目录已提前部署好"
return 1
else
log "INFO" "✅ 目标目录 $host_data_dir 存在,继续部署"
fi
# 确保关键脚本存在并有执行权限
if [[ ! -f "$start_script_host" ]]; then
log "ERROR" "⛔ 启动脚本不存在: $start_script_host"
return 1
fi
$SUDO chmod +x "$start_script_host" "$host_data_dir/run.sh" 2>/dev/null
log "INFO" "🔧 已设置脚本执行权限"
# ------------------- 检查镜像是否已加载 -------------------
log "INFO" "🔍 检查镜像 $image_tag 是否已存在..."
if $SUDO docker images --format '{{.Repository}}:{{.Tag}}' | grep -Fxq "$image_tag"; then
log "INFO" "✅ 镜像 $image_tag 已存在"
else
log "INFO" "🔄 加载镜像 $image_tar..."
if $SUDO docker load -i "$image_tar"; then
log "INFO" "🎉 镜像加载成功"
else
log "ERROR" "镜像加载失败,请检查文件完整性"
return 1
fi
fi
# ------------------- 启动容器 -------------------
log "INFO" "🚀 正在启动容器 '$container_name'..."
$SUDO docker run \
-itd \
--privileged \
--name "$container_name" \
--mac-address="$mac_address" \
-p "${port_http}:${port_http}" \
-p "${port_nginx}:${port_nginx}" \
-v "$start_script_host:/root/start.sh" \
-v "$host_data_dir:/var/www/paperless" \
-v "/etc/localtime:/etc/localtime:ro" \
--restart=always \
"$image_tag" \
/root/start.sh
if [[ $? -ne 0 ]]; then
log "ERROR" "⛔ 容器启动失败"
return 1
fi
# ------------------- 验证容器是否正常运行 -------------------
sleep 5
if $SUDO docker ps --format '{{.Names}}' | grep -qw "$container_name"; then
log "INFO" "✅ 容器启动成功"
else
log "ERROR" "⛔ 容器启动失败或立即退出"
log "ERROR" "📄 查看日志: docker logs $container_name"
$SUDO docker logs "$container_name"
return 1
fi
return 0
}
function cardtable_x86() {
local service_name="电子桌牌服务 (cardtable)"
local container_name="cardtable"
local image_tar="/data/offline_auto_unifiedPlatform/data/temp/uos-cardtable.tar" # 建议统一放 /data/temp
local image_tag="uos-cardtable:v1"
local work_dir="/data/third_party/wifi-local"
local db_dir="$work_dir/db"
log "INFO" "=================================================================="
log "INFO" "📦 正在部署:$service_name"
log "INFO" " 容器名称: $container_name"
log "INFO" " 镜像文件: $image_tar"
log "INFO" " 工作目录: $work_dir"
log "INFO" "=================================================================="
# 1. 检查镜像压缩包是否存在
if [ ! -f "$image_tar" ]; then
log "ERROR" "❌ 镜像文件不存在: $image_tar"
log "ERROR" "💡 请确认已上传镜像至 /data/temp/ 目录"
return 1
fi
log "INFO" "✅ 镜像文件已找到: $image_tar"
# 2. 加载 Docker 镜像
log "INFO" "🐳 正在加载 Docker 镜像..."
docker load -i "$image_tar"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 镜像加载失败,请检查文件完整性或 Docker 服务状态"
return 1
fi
log "INFO" "✅ 镜像加载成功: $image_tag"
# 3. 检查工作目录是否存在
if [ ! -d "$work_dir" ]; then
log "ERROR" "❌ 工作目录不存在: $work_dir"
log "ERROR" "💡 请先创建目录并放入配置文件"
return 1
fi
log "INFO" "✅ 工作目录已存在: $work_dir"
# 4. 设置文件权限(config、脚本、数据库组件)
log "INFO" "🔐 正在设置文件执行权限..."
chmod 755 "$work_dir/config.ini" "$work_dir/startDB.sh" "$work_dir/wifi"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 权限设置失败:$work_dir 下的文件"
return 1
fi
chmod 755 "$db_dir/mongo" "$db_dir/mongo.config" "$db_dir/mongod"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 权限设置失败:$db_dir 下的 MongoDB 组件"
return 1
fi
log "INFO" "✅ 文件权限设置完成"
# 5. 检查容器是否已存在,若存在则先停止并删除
if docker ps -a --format '{{.Names}}' | grep -qw "^$container_name$"; then
log "WARN" "🔄 检测到已有容器 '$container_name',自动退出部署操作!!!"
return 0
fi
# 6. 创建并运行新容器(使用 host 网络)
log "INFO" "🚀 正在创建并启动容器 '$container_name'..."
docker run -itd \
--name="$container_name" \
--privileged \
--network=host \
--restart=always \
-v "$work_dir:/home/wifi-local" \
"$image_tag" \
/root/start.sh
if [ $? -ne 0 ]; then
log "ERROR" "❌ 容器启动失败,请检查镜像、网络或挂载权限"
return 1
fi
# 7. 验证容器是否正常运行
sleep 3
if docker ps --format '{{.Names}}' | grep -qw "^$container_name$"; then
local container_id=$(docker ps --filter "name=$container_name" --format "{{.ID}}")
log "INFO" "✅ 容器启动成功!"
log "INFO" " 🏷 名称: $container_name"
log "INFO" " 🔢 ID: $container_id"
log "INFO" " 🌐 网络模式: host"
log "INFO" " 📁 挂载: $work_dir → /home/wifi-local"
log "INFO" " 🔁 重启策略: always"
else
log "ERROR" "❌ 容器启动后立即退出,请使用 'docker logs $container_name' 查看日志"
return 1
fi
return 0
}
......@@ -2179,190 +1238,6 @@ function server_ip()
}
#-------------------------------获取服务器的ip-end-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#-------------------------------服务部署选择-start--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function deploy_services() {
local IP=$(hostname -I | awk '{print $1}' | cut -d' ' -f1)
# ========================================
# 🧩 定义服务映射表:支持多个函数
# 格式:[编号]="函数1 函数2 ..."(用空格分隔)
# ========================================
declare -A SERVICE_MAP=(
[1]="java_x86"
[2]="python_x86"
[3]="iListen_x86 python_voice_x86" # 👈 重点:语音系统 = 多个函数
[4]="paperless_x86"
[5]="cardtable_x86"
)
declare -A SERVICE_LABEL=(
[1]="预定系统"
[2]="运维集控系统"
[3]="语音转录系统"
[4]="无纸化信令服务"
[5]="电子桌牌服务"
)
declare -A SERVICE_DESC=(
[1]="Java 后端服务"
[2]="Python 运维控制平台"
[3]="语音识别引擎 + 转录后端"
[4]="Paperless 信令转发"
[5]="电子桌牌通信服务"
)
log "INFO" "🔍 正在检查 SERVICE_MAP 中引用的所有函数..."
local all_funcs=()
for func_list in "${SERVICE_MAP[@]}"; do
for func_name in $func_list; do # 注意:这里不要加引号,让其展开
all_funcs+=("$func_name")
done
done
local missing=0 total=0
for func_name in "${all_funcs[@]}" ; do
((total++))
if declare -f "$func_name" > /dev/null 2>&1; then
log "INFO" "✅ 函数已定义: $func_name"
else
log "ERROR" "❌ 函数未定义: $func_name"
((missing++))
fi
done
if [ $missing -ne 0 ]; then
log "ERROR" "⛔ 缺少 $missing 个函数,无法继续部署。"
return 1
fi
# 构建 whiptail 选项
local options=()
for i in {1..5}; do
options+=(
"$i"
"${SERVICE_LABEL[$i]} (${SERVICE_DESC[$i]})"
"off"
)
done
# 显示多选菜单(第一级界面)
local choices
choices=$(whiptail --title "🔹 服务部署中心" \
--backtitle "当前服务器 IP: $IP" \
--checklist "\n请选择要部署的服务(使用空格勾选,支持多选):" \
18 80 6 \
"${options[@]}" \
3>&1 1>&2 2>&3)
# 第一级界面取消:退出整个部署操作
if [ $? -ne 0 ]; then
log "INFO" "用户在第一级界面取消部署"
whiptail --title "↩️ 退出部署" --msgbox "已取消服务部署操作。" 8 40
return 1 # 返回1表示用户主动取消
fi
if [ -z "$choices" ]; then
if whiptail --title "ℹ️ 提示" --yesno "未选择任何服务,是否重新选择?" 10 50; then
# 用户选择重新选择,递归调用
deploy_services
return $?
else
# 用户选择退出
whiptail --title "↩️ 退出部署" --msgbox "已取消服务部署操作。" 8 40
return 1
fi
fi
# 去除多余引号,确保是干净的数字序列
choices=$(echo "$choices" | sed 's/"//g' | xargs)
# 显示用户选择的服务
local selected_list=""
for choice in $choices; do
if [[ -n "${SERVICE_LABEL[$choice]}" ]]; then
selected_list+="${SERVICE_LABEL[$choice]}\n"
else
log "ERROR" "⚠️ 未知服务编号: $choice"
fi
done
# 确认部署(第二级界面)
if ! whiptail --title "✅ 确认部署" \
--yesno "您选择了以下服务进行部署:\n\n${selected_list}\n是否确认开始部署?" \
14 60; then
log "INFO" "用户在第二级界面取消,返回服务选择界面"
whiptail --title "🔄 重新选择" --msgbox "将返回服务选择界面..." 8 40
# 第二级取消:递归调用返回第一级界面
deploy_services
return $?
fi
whiptail --title "🚀 开始部署" --msgbox "正在启动部署流程,请查看终端日志..." 10 50
# --- 开始部署 ---
local success_count=0
local total_count=0
for choice in $choices; do
if ! [[ "$choice" =~ ^[1-5]$ ]]; then
log "ERROR" "⚠️ 无效选项: $choice"
continue
fi
local func_list="${SERVICE_MAP[$choice]}"
local label="${SERVICE_LABEL[$choice]}"
if [[ -z "$label" ]]; then
log "ERROR" "⚠️ 未知服务编号: $choice"
continue
fi
log "INFO" "=================================================================="
log "INFO" "🚀 正在部署: $label"
log "INFO" "=================================================================="
# 👇 执行该服务关联的每一个函数
local service_success=true
for func_name in $func_list; do # 注意:不要加引号
if declare -f "$func_name" > /dev/null; then
log "INFO" "▶️ 执行函数: $func_name"
"$func_name"
if [ $? -ne 0 ]; then
log "ERROR" "❌ 函数执行失败: $func_name"
service_success=false
break # 可选:是否继续执行下一个函数?
else
log "INFO" "✅ $func_name 执行成功"
fi
else
log "ERROR" "❌ 未找到函数: $func_name"
service_success=false
break
fi
done
if [ "$service_success" = true ]; then
log "INFO" "✅ $label 部署成功"
((success_count++))
else
log "ERROR" "❌ $label 部署失败"
whiptail --title "❌ 部署失败" \
--msgbox "服务 [$label] 部署失败,请检查日志后重试。" \
12 60 || echo "警告:无法显示弹窗"
fi
done
# 最终统计
local fail_count=$(( $(echo $choices | wc -w) - success_count ))
log "INFO" "=================================================="
log "INFO" "🎯 部署完成:成功 $success_count 个服务,失败 $fail_count 个"
log "INFO" "=================================================="
return $(( fail_count > 0 ? 1 : 0 ))
}
#-------------------------------服务部署选择-end--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#-------------------------------部署系统-------------------------------
log "INFO" "\033[36m
---------------------------------------------开始部署系统---------------------------------------------------
......@@ -2376,8 +1251,6 @@ function deploy_services() {
check_files_upload
#开放防火墙
firewalldjava
# 安装服务
docker_x86
# 部署中间件服务(mysql, redis, emqx, fdfs, ngrok, nacos, nginx)
middleware_type="mysql redis emqx fdfs ngrok nacos nginx" install_middleware
ntp_uos
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论