368 lines
9.9 KiB
Bash
368 lines
9.9 KiB
Bash
#!/bin/bash
|
||
|
||
set -e
|
||
|
||
# =========================================== 基础检查与更新 ===========================================
|
||
SCRIPT_PATH=`pwd`
|
||
|
||
function check() {
|
||
if [ "$(id -u)" -ne 0 ]; then
|
||
echo "请以root权限运行此脚本" >&2
|
||
exit 1
|
||
fi
|
||
|
||
osCheck=`uname -a`
|
||
if [[ $osCheck =~ 'x86_64' ]];then
|
||
architecture="amd64"
|
||
else
|
||
echo "暂不支持的系统架构,选择受支持的系统。"
|
||
exit 1
|
||
fi
|
||
|
||
if [ ! -d "offline_resources" ]; then
|
||
echo "未找到资源目录,请确保offline_resources目录与脚本在同一位置" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
function upgrade() {
|
||
echo "更新系统源"
|
||
sudo apt update -y
|
||
sudo apt upgrade -y
|
||
}
|
||
|
||
# =========================================== Docker与1Panel ===========================================
|
||
|
||
function check_docker_installed() {
|
||
if command -v docker &> /dev/null; then
|
||
echo "Docker 已安装,版本: $(docker --version)"
|
||
return 0
|
||
else
|
||
echo "Docker 未安装"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
function check_1panel_installed() {
|
||
if systemctl status 1panel-core &> /dev/null; then
|
||
echo "1Panel 已安装,状态: $(systemctl is-active 1panel-core)"
|
||
return 0
|
||
else
|
||
echo "1Panel 未安装"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
function install_docker() {
|
||
if check_docker_installed; then
|
||
echo "Docker 已经安装,跳过安装步骤"
|
||
return 0
|
||
fi
|
||
|
||
echo && echo "正在安装依赖包和Docker..." && echo
|
||
dpkg -i debs/*.deb || apt-get -f install -y
|
||
|
||
echo && echo "启动Docker服务..." && echo
|
||
systemctl start docker
|
||
systemctl enable docker
|
||
|
||
echo && echo "安装Docker Compose..." && echo
|
||
cp docker-compose/`ls docker-compose/ | grep docker-compose | head -n 1` /usr/local/bin/docker-compose
|
||
chmod +x /usr/local/bin/docker-compose
|
||
|
||
if check_docker_installed; then
|
||
echo "Docker 安装成功!"
|
||
else
|
||
echo "Docker 安装失败!" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
function install_1panel() {
|
||
if check_1panel_installed; then
|
||
echo "1Panel 已经安装,跳过安装步骤"
|
||
return 0
|
||
fi
|
||
|
||
echo && echo "安装1Panel..." && echo
|
||
|
||
panel_package=$(ls 1panel | grep -G '1panel-v.*\.tar\.gz' | head -n 1)
|
||
if [ -z "${panel_package}" ]; then
|
||
echo "未找到1Panel安装包" >&2
|
||
exit 1
|
||
fi
|
||
|
||
tar -zxvf "1panel/${panel_package}" -C 1panel
|
||
|
||
panel_dir=$(ls -l 1panel | grep '^d' | grep 1panel | awk '{print $NF}' | head -n 1)
|
||
if [ -z "$panel_dir" ]; then
|
||
echo "未找到1Panel解压目录" >&2
|
||
exit 1
|
||
fi
|
||
|
||
chmod u+x "./1panel/$panel_dir/install.sh"
|
||
sudo "./1panel/$panel_dir/install.sh"
|
||
|
||
sleep 3
|
||
if check_1panel_installed; then
|
||
echo "1Panel 安装成功!"
|
||
else
|
||
echo "1Panel 安装失败!" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# =========================================== 通用函数处理 ===========================================
|
||
|
||
# 主函数:空处理
|
||
function process_empty() {
|
||
return 0
|
||
}
|
||
|
||
# 主函数:处理tar文件并执行指定函数
|
||
function process_tar_files() {
|
||
local resource_dir="$1"
|
||
local process_function="$2"
|
||
local file_patterns=("${@:3}")
|
||
|
||
if [ ${#file_patterns[@]} -eq 0 ]; then
|
||
file_patterns=("*.tar")
|
||
fi
|
||
|
||
if [ ! -d "$resource_dir" ]; then
|
||
echo "错误: 目录 $resource_dir 不存在"
|
||
return 1
|
||
fi
|
||
|
||
if ! declare -f "$process_function" > /dev/null; then
|
||
echo "错误: 函数 $process_function 未定义"
|
||
return 1
|
||
fi
|
||
|
||
local file_count=0
|
||
local success_count=0
|
||
local fail_count=0
|
||
|
||
echo "开始在目录 $resource_dir 中查找文件..."
|
||
|
||
for pattern in "${file_patterns[@]}"; do
|
||
echo "搜索模式: $pattern"
|
||
|
||
for tar_file in "$resource_dir"/$pattern; do
|
||
filename=$(basename "$tar_file")
|
||
"$process_function" "$tar_file" "${filename}"
|
||
file_count=$((file_count + 1))
|
||
done
|
||
done
|
||
|
||
echo "=== 处理完成 ==="
|
||
echo "总共找到: $file_count 个文件"
|
||
echo "成功: $success_count"
|
||
echo "失败: $fail_count"
|
||
|
||
if [ $file_count -eq 0 ]; then
|
||
echo "在目录 $resource_dir 中未找到以下模式的文件: ${file_patterns[*]}"
|
||
echo "目录内容:"
|
||
ls -la "$resource_dir/" 2>/dev/null || echo "无法列出目录内容"
|
||
fi
|
||
|
||
return $fail_count
|
||
}
|
||
|
||
# 处理关联数组的函数
|
||
function process_associative_array() {
|
||
# arg1: 默认路径
|
||
# arg2: 执行数组
|
||
# arg3: 自定义初始化函数
|
||
local path="$1"
|
||
local array_name="$2"
|
||
local func_name="$3"
|
||
|
||
eval "local keys=(\"\${!${array_name}[@]}\")"
|
||
for key in "${keys[@]}"; do
|
||
eval "local value=\"\${${array_name}[\$key]}\""
|
||
name=$(echo "${key}" | awk -F. '{if (NF>1) {for(i=1;i<NF;i++) printf "%s%s", $i, (i<NF-1?".":"")}}')
|
||
"${func_name}" "${path}/${name}" "${key}" "${value}"
|
||
done
|
||
}
|
||
|
||
# =========================================== 部署容器 ===========================================
|
||
|
||
function docker_load_tar() {
|
||
# arg1 加载的镜像文件名称
|
||
# arg2 镜像描述
|
||
|
||
SOURCE_FILE=$1
|
||
SOURCE_DESCRIPTION=$2
|
||
|
||
echo "加载 ${SOURCE_DESCRIPTION} 镜像"
|
||
docker load -i ${SOURCE_FILE} || { echo "加载 ${SOURCE_DESCRIPTION} 镜像失败"; exit 1; }
|
||
}
|
||
|
||
function docker_installer() {
|
||
# arg1: 安装到 1panel 的程序目录
|
||
# arg2: 迁移到 1panel 程序目录的压缩文件
|
||
# arg3: 自定义初始化函数(可选)
|
||
|
||
local TARGET_DIR="${1}"
|
||
local SOURCE_FILE="${2}"
|
||
local CUSTOM_INIT_FUNC="${3}"
|
||
local SOURCE_PATH=$(pwd)
|
||
local DEFAULT_DOCKER_COMPOSE="docker-compose.yml"
|
||
local TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||
local BACKUP_DIR="${TARGET_DIR}_backup_${TIMESTAMP}"
|
||
|
||
if [ $# -lt 2 ]; then
|
||
echo "错误:缺少必要参数"
|
||
echo "用法: docker_installer <目标目录> <源压缩文件> [自定义初始化函数]"
|
||
return 1
|
||
fi
|
||
|
||
if [ ! -f "${SOURCE_FILE}" ] || [ ! -r "${SOURCE_FILE}" ]; then
|
||
echo "错误:源文件 ${SOURCE_FILE} 不存在或不可读"
|
||
return 1
|
||
fi
|
||
|
||
if [ ! -d "${TARGET_DIR}" ]; then
|
||
echo "目录 ${TARGET_DIR} 不存在,尝试创建..."
|
||
mkdir -p "${TARGET_DIR}" || {
|
||
echo "无法创建目录 ${TARGET_DIR}"
|
||
return 1
|
||
}
|
||
fi
|
||
|
||
echo "复制文件到 ${TARGET_DIR}"
|
||
cp "${SOURCE_FILE}" "${TARGET_DIR}/" || {
|
||
echo "复制文件失败"
|
||
return 1
|
||
}
|
||
|
||
cd "${TARGET_DIR}" || {
|
||
echo "无法进入目录 ${TARGET_DIR}"
|
||
return 1
|
||
}
|
||
|
||
local FILENAME=$(basename "${SOURCE_FILE}")
|
||
echo "开始解压 ${FILENAME}"
|
||
|
||
case "${FILENAME##*.}" in
|
||
zip)
|
||
unzip -q "${FILENAME}" || {
|
||
echo "解压 ${FILENAME} 失败"
|
||
return 1
|
||
}
|
||
;;
|
||
tar|gz|tgz|bz2)
|
||
tar -xf "${FILENAME}" || {
|
||
echo "解压 ${FILENAME} 失败"
|
||
return 1
|
||
}
|
||
;;
|
||
*)
|
||
echo "不支持的压缩格式: ${FILENAME##*.}"
|
||
return 1
|
||
;;
|
||
esac
|
||
|
||
rm -f "${FILENAME}"
|
||
if [ -n "${CUSTOM_INIT_FUNC}" ]; then
|
||
if type "${CUSTOM_INIT_FUNC}" &>/dev/null; then
|
||
echo "执行自定义初始化函数 ${CUSTOM_INIT_FUNC}"
|
||
${CUSTOM_INIT_FUNC} || {
|
||
echo "自定义初始化函数执行失败"
|
||
return 1
|
||
}
|
||
else
|
||
echo "警告:初始化函数 ${CUSTOM_INIT_FUNC} 不存在,跳过"
|
||
fi
|
||
fi
|
||
|
||
local COMPOSE_FILE="${DEFAULT_DOCKER_COMPOSE}"
|
||
if [ -f "${COMPOSE_FILE}" ]; then
|
||
echo "在 ${TARGET_DIR} 下启动 Docker Compose"
|
||
|
||
if ! command -v docker-compose &>/dev/null; then
|
||
echo "错误:docker-compose 未安装"
|
||
return 1
|
||
fi
|
||
|
||
if ! docker info &>/dev/null; then
|
||
echo "错误:Docker 守护进程未运行"
|
||
return 1
|
||
fi
|
||
|
||
docker-compose up -d || {
|
||
echo "Docker Compose 启动失败"
|
||
return 1
|
||
}
|
||
|
||
echo "Docker Compose 启动成功"
|
||
else
|
||
echo "在 ${TARGET_DIR} 下未找到 ${COMPOSE_FILE}"
|
||
echo "可用文件:"
|
||
ls -la
|
||
return 1
|
||
fi
|
||
|
||
cd "${SOURCE_PATH}" >/dev/null
|
||
|
||
echo && echo "操作完成" && echo
|
||
echo "目标目录: ${TARGET_DIR}"
|
||
if [ -d "${BACKUP_DIR}" ]; then
|
||
echo "备份位置: ${BACKUP_DIR}"
|
||
fi
|
||
}
|
||
|
||
# =========================================== 特殊初始化 ===========================================
|
||
|
||
function init_rocketmq() {
|
||
cd rocketmq
|
||
sh scripts/init.sh || { echo "初始化 init.sh 失败"; exit 1; }
|
||
}
|
||
|
||
|
||
# =========================================== 主流程 ===========================================
|
||
|
||
function main() {
|
||
check
|
||
# upgrade
|
||
|
||
cd ${SCRIPT_PATH}/offline_resources
|
||
install_docker
|
||
install_1panel
|
||
|
||
echo && echo "验证安装结果..."
|
||
echo && echo "Docker版本: $(docker --version)"
|
||
echo && echo "Docker Compose版本: $(docker-compose --version)"
|
||
echo && echo "1Panel状态: $(systemctl status 1panel-core | grep Active)"
|
||
echo && echo
|
||
echo && echo "所有组件安装完成!" && echo && echo
|
||
|
||
|
||
cd ${SCRIPT_PATH}/busicess_resources
|
||
process_tar_files "`pwd`/containers" "docker_load_tar"
|
||
echo && echo "所有镜像安装完成!" && echo && echo
|
||
|
||
NETWORK_NAME="1panel-network"
|
||
|
||
if ! docker network ls | grep -q "$NETWORK_NAME"; then
|
||
echo "网络 $NETWORK_NAME 不存在,正在创建..."
|
||
docker network create "$NETWORK_NAME"
|
||
echo "网络 $NETWORK_NAME 创建成功!"
|
||
fi
|
||
|
||
cd ${SCRIPT_PATH}/busicess_resources/dataset
|
||
declare -A my_assoc_array=(
|
||
["minio.zip"]="process_empty"
|
||
["mysql.zip"]="process_empty"
|
||
["redis.zip"]="process_empty"
|
||
["rocketmq.zip"]="init_rocketmq"
|
||
["portainer-ce.zip"]="process_empty"
|
||
["phpmyadmin.zip"]="process_empty"
|
||
["simulation.zip"]="process_empty"
|
||
)
|
||
process_associative_array "/opt/1panel/apps" my_assoc_array "docker_installer" || { echo "初始化 init.sh 失败"; exit 1; }
|
||
echo && echo "所有容器安装完成!" && echo && echo
|
||
}
|
||
|
||
main |