fix: normalize deploy shell scripts to LF for Linux curl|bash
CRLF line endings broke manage.sh on Ubuntu (set -e and function syntax errors). Add .gitattributes to keep *.sh on LF in git. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
# Shell scripts must use LF (Linux deploy via curl | bash)
|
||||||
|
*.sh text eol=lf
|
||||||
|
|
||||||
|
# Docker / compose
|
||||||
|
Dockerfile text eol=lf
|
||||||
|
docker-compose.yml text eol=lf
|
||||||
|
|
||||||
|
# Default for text
|
||||||
|
* text=auto
|
||||||
+5
-5
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# 兼容入口:转发到 manage.sh
|
# 兼容入口:转发到 manage.sh
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
exec bash "${ROOT}/deploy/manage.sh" "$@"
|
exec bash "${ROOT}/deploy/manage.sh" "$@"
|
||||||
|
|||||||
+358
-358
@@ -1,358 +1,358 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# deploy/lib/common.sh — market_intel 部署公共函数(Docker Compose)
|
# deploy/lib/common.sh — market_intel 部署公共函数(Docker Compose)
|
||||||
# 目标系统: Ubuntu 22.04 LTS
|
# 目标系统: Ubuntu 22.04 LTS
|
||||||
set -e
|
set -e
|
||||||
set -u
|
set -u
|
||||||
if [ -n "${BASH_VERSION:-}" ]; then
|
if [ -n "${BASH_VERSION:-}" ]; then
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
fi
|
fi
|
||||||
|
|
||||||
INSTALL_ROOT="${INSTALL_ROOT:-/opt/market_intel}"
|
INSTALL_ROOT="${INSTALL_ROOT:-/opt/market_intel}"
|
||||||
GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/market_intel.git}"
|
GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/market_intel.git}"
|
||||||
GIT_BRANCH="${GIT_BRANCH:-main}"
|
GIT_BRANCH="${GIT_BRANCH:-main}"
|
||||||
BACKUP_ROOT="${BACKUP_ROOT:-/root/backups/market_intel}"
|
BACKUP_ROOT="${BACKUP_ROOT:-/root/backups/market_intel}"
|
||||||
TZ_NAME="${MI_TZ:-Asia/Shanghai}"
|
TZ_NAME="${MI_TZ:-Asia/Shanghai}"
|
||||||
MI_PORT_DEFAULT="${MI_PORT_DEFAULT:-5170}"
|
MI_PORT_DEFAULT="${MI_PORT_DEFAULT:-5170}"
|
||||||
|
|
||||||
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
DEPLOY_DIR="$(cd "${LIB_DIR}/.." && pwd)"
|
DEPLOY_DIR="$(cd "${LIB_DIR}/.." && pwd)"
|
||||||
REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)"
|
REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)"
|
||||||
|
|
||||||
log() { printf '[%s] %s\n' "$(TZ="${TZ_NAME}" date '+%Y-%m-%d %H:%M:%S')" "$*"; }
|
log() { printf '[%s] %s\n' "$(TZ="${TZ_NAME}" date '+%Y-%m-%d %H:%M:%S')" "$*"; }
|
||||||
step() { echo ""; log "==> $*"; }
|
step() { echo ""; log "==> $*"; }
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
echo "错误: $*" >&2
|
echo "错误: $*" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
require_root() {
|
require_root() {
|
||||||
if [[ "$(id -u)" -ne 0 ]]; then
|
if [[ "$(id -u)" -ne 0 ]]; then
|
||||||
die "请使用 root 执行(推荐: sudo -i 后运行)"
|
die "请使用 root 执行(推荐: sudo -i 后运行)"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_apt_lock_holders() {
|
_apt_lock_holders() {
|
||||||
ps -eo pid,cmd 2>/dev/null | grep -E '[u]nattended-upgr|[a]pt-get|[a]pt |[d]pkg ' | head -n 8 || true
|
ps -eo pid,cmd 2>/dev/null | grep -E '[u]nattended-upgr|[a]pt-get|[a]pt |[d]pkg ' | head -n 8 || true
|
||||||
if command -v fuser >/dev/null 2>&1; then
|
if command -v fuser >/dev/null 2>&1; then
|
||||||
fuser -v /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/lib/apt/lists/lock 2>&1 | head -n 12 || true
|
fuser -v /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/lib/apt/lists/lock 2>&1 | head -n 12 || true
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_stop_auto_apt_for_deploy() {
|
_stop_auto_apt_for_deploy() {
|
||||||
if [[ "${APT_STOP_AUTO:-1}" != "1" ]]; then
|
if [[ "${APT_STOP_AUTO:-1}" != "1" ]]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if command -v systemctl >/dev/null 2>&1; then
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
log "临时停止 unattended-upgrades / apt-daily,避免占锁…"
|
log "临时停止 unattended-upgrades / apt-daily,避免占锁…"
|
||||||
systemctl stop unattended-upgrades.service 2>/dev/null || true
|
systemctl stop unattended-upgrades.service 2>/dev/null || true
|
||||||
systemctl stop apt-daily.service apt-daily-upgrade.service 2>/dev/null || true
|
systemctl stop apt-daily.service apt-daily-upgrade.service 2>/dev/null || true
|
||||||
systemctl kill --kill-who=all unattended-upgrades.service 2>/dev/null || true
|
systemctl kill --kill-who=all unattended-upgrades.service 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
if [[ "${APT_FORCE_UNLOCK:-0}" == "1" ]]; then
|
if [[ "${APT_FORCE_UNLOCK:-0}" == "1" ]]; then
|
||||||
log "APT_FORCE_UNLOCK=1:结束残留 apt/dpkg 进程…"
|
log "APT_FORCE_UNLOCK=1:结束残留 apt/dpkg 进程…"
|
||||||
pkill -9 -x unattended-upgr 2>/dev/null || true
|
pkill -9 -x unattended-upgr 2>/dev/null || true
|
||||||
pkill -9 -x apt-get 2>/dev/null || true
|
pkill -9 -x apt-get 2>/dev/null || true
|
||||||
pkill -9 -x apt 2>/dev/null || true
|
pkill -9 -x apt 2>/dev/null || true
|
||||||
pkill -9 -x dpkg 2>/dev/null || true
|
pkill -9 -x dpkg 2>/dev/null || true
|
||||||
sleep 2
|
sleep 2
|
||||||
dpkg --configure -a 2>/dev/null || true
|
dpkg --configure -a 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_for_apt_lock() {
|
wait_for_apt_lock() {
|
||||||
local max_wait="${1:-600}"
|
local max_wait="${1:-600}"
|
||||||
local waited=0
|
local waited=0
|
||||||
local tried_stop=0
|
local tried_stop=0
|
||||||
if ! command -v apt-get >/dev/null 2>&1; then
|
if ! command -v apt-get >/dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
while true; do
|
while true; do
|
||||||
local busy=0
|
local busy=0
|
||||||
if pgrep -x unattended-upgr >/dev/null 2>&1 \
|
if pgrep -x unattended-upgr >/dev/null 2>&1 \
|
||||||
|| pgrep -x apt-get >/dev/null 2>&1 \
|
|| pgrep -x apt-get >/dev/null 2>&1 \
|
||||||
|| pgrep -x apt >/dev/null 2>&1 \
|
|| pgrep -x apt >/dev/null 2>&1 \
|
||||||
|| pgrep -x dpkg >/dev/null 2>&1; then
|
|| pgrep -x dpkg >/dev/null 2>&1; then
|
||||||
busy=1
|
busy=1
|
||||||
fi
|
fi
|
||||||
if command -v fuser >/dev/null 2>&1; then
|
if command -v fuser >/dev/null 2>&1; then
|
||||||
if fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 \
|
if fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 \
|
||||||
|| fuser /var/lib/dpkg/lock >/dev/null 2>&1 \
|
|| fuser /var/lib/dpkg/lock >/dev/null 2>&1 \
|
||||||
|| fuser /var/lib/apt/lists/lock >/dev/null 2>&1; then
|
|| fuser /var/lib/apt/lists/lock >/dev/null 2>&1; then
|
||||||
busy=1
|
busy=1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ "${busy}" -eq 0 ]]; then
|
if [[ "${busy}" -eq 0 ]]; then
|
||||||
[[ "${waited}" -gt 0 ]] && log "apt 锁已释放,继续安装"
|
[[ "${waited}" -gt 0 ]] && log "apt 锁已释放,继续安装"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if [[ "${waited}" -eq 0 ]]; then
|
if [[ "${waited}" -eq 0 ]]; then
|
||||||
log "检测到 apt/dpkg 正被占用,等待释放…"
|
log "检测到 apt/dpkg 正被占用,等待释放…"
|
||||||
_apt_lock_holders | while IFS= read -r line; do log " ${line}"; done
|
_apt_lock_holders | while IFS= read -r line; do log " ${line}"; done
|
||||||
elif [[ "${tried_stop}" -eq 0 && "${waited}" -ge 15 ]]; then
|
elif [[ "${tried_stop}" -eq 0 && "${waited}" -ge 15 ]]; then
|
||||||
tried_stop=1
|
tried_stop=1
|
||||||
_stop_auto_apt_for_deploy
|
_stop_auto_apt_for_deploy
|
||||||
elif [[ $((waited % 60)) -eq 0 ]]; then
|
elif [[ $((waited % 60)) -eq 0 ]]; then
|
||||||
log "仍在等待 apt 锁…已等 ${waited}s / ${max_wait}s"
|
log "仍在等待 apt 锁…已等 ${waited}s / ${max_wait}s"
|
||||||
fi
|
fi
|
||||||
if [[ "${waited}" -ge "${max_wait}" ]]; then
|
if [[ "${waited}" -ge "${max_wait}" ]]; then
|
||||||
die "等待 apt 锁超时(${max_wait}s)"
|
die "等待 apt 锁超时(${max_wait}s)"
|
||||||
fi
|
fi
|
||||||
sleep 5
|
sleep 5
|
||||||
waited=$((waited + 5))
|
waited=$((waited + 5))
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
apt_update() {
|
apt_update() {
|
||||||
wait_for_apt_lock
|
wait_for_apt_lock
|
||||||
apt-get update -qq
|
apt-get update -qq
|
||||||
}
|
}
|
||||||
|
|
||||||
apt_install() {
|
apt_install() {
|
||||||
wait_for_apt_lock
|
wait_for_apt_lock
|
||||||
apt-get install -y "$@"
|
apt-get install -y "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
detect_server_ip() {
|
detect_server_ip() {
|
||||||
local ip=""
|
local ip=""
|
||||||
if command -v hostname >/dev/null 2>&1; then
|
if command -v hostname >/dev/null 2>&1; then
|
||||||
ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||||
fi
|
fi
|
||||||
[[ -z "${ip}" ]] && ip="127.0.0.1"
|
[[ -z "${ip}" ]] && ip="127.0.0.1"
|
||||||
echo "${ip}"
|
echo "${ip}"
|
||||||
}
|
}
|
||||||
|
|
||||||
cm_read() {
|
cm_read() {
|
||||||
local __var="$1"
|
local __var="$1"
|
||||||
local __prompt="${2:-}"
|
local __prompt="${2:-}"
|
||||||
local __line=""
|
local __line=""
|
||||||
if [[ -n "${__prompt}" ]]; then
|
if [[ -n "${__prompt}" ]]; then
|
||||||
printf '%s' "${__prompt}" >/dev/tty 2>/dev/null || printf '%s' "${__prompt}"
|
printf '%s' "${__prompt}" >/dev/tty 2>/dev/null || printf '%s' "${__prompt}"
|
||||||
fi
|
fi
|
||||||
if [[ -r /dev/tty ]]; then
|
if [[ -r /dev/tty ]]; then
|
||||||
IFS= read -r __line </dev/tty || true
|
IFS= read -r __line </dev/tty || true
|
||||||
else
|
else
|
||||||
IFS= read -r __line || true
|
IFS= read -r __line || true
|
||||||
fi
|
fi
|
||||||
printf -v "${__var}" '%s' "${__line}"
|
printf -v "${__var}" '%s' "${__line}"
|
||||||
}
|
}
|
||||||
|
|
||||||
confirm_yes() {
|
confirm_yes() {
|
||||||
local msg="$1"
|
local msg="$1"
|
||||||
local ans=""
|
local ans=""
|
||||||
cm_read ans "${msg} [y/N] "
|
cm_read ans "${msg} [y/N] "
|
||||||
[[ "${ans}" == [yY] || "${ans}" == [yY][eE][sS] ]]
|
[[ "${ans}" == [yY] || "${ans}" == [yY][eE][sS] ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
repo_ready() {
|
repo_ready() {
|
||||||
[[ -f "${1}/deploy/manage.sh" && -f "${1}/docker-compose.yml" && -d "${1}/deploy/lib" ]]
|
[[ -f "${1}/deploy/manage.sh" && -f "${1}/docker-compose.yml" && -d "${1}/deploy/lib" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve_repo_root() {
|
resolve_repo_root() {
|
||||||
if repo_ready "${INSTALL_ROOT}"; then
|
if repo_ready "${INSTALL_ROOT}"; then
|
||||||
echo "${INSTALL_ROOT}"
|
echo "${INSTALL_ROOT}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if [[ -n "${REPO_ROOT:-}" ]] && repo_ready "${REPO_ROOT}"; then
|
if [[ -n "${REPO_ROOT:-}" ]] && repo_ready "${REPO_ROOT}"; then
|
||||||
echo "${REPO_ROOT}"
|
echo "${REPO_ROOT}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
read_env_value() {
|
read_env_value() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local key="$2"
|
local key="$2"
|
||||||
local val=""
|
local val=""
|
||||||
if [[ -f "${file}" ]]; then
|
if [[ -f "${file}" ]]; then
|
||||||
val="$(grep -E "^${key}=" "${file}" 2>/dev/null | tail -n1 | cut -d= -f2- || true)"
|
val="$(grep -E "^${key}=" "${file}" 2>/dev/null | tail -n1 | cut -d= -f2- || true)"
|
||||||
fi
|
fi
|
||||||
printf '%s' "${val}"
|
printf '%s' "${val}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 已有非空不覆盖;空或缺省则写入/询问
|
# 已有非空不覆盖;空或缺省则写入/询问
|
||||||
ensure_env_key() {
|
ensure_env_key() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local key="$2"
|
local key="$2"
|
||||||
local prompt="$3"
|
local prompt="$3"
|
||||||
local default="$4"
|
local default="$4"
|
||||||
local current
|
local current
|
||||||
current="$(read_env_value "${file}" "${key}")"
|
current="$(read_env_value "${file}" "${key}")"
|
||||||
if [[ -n "${current}" ]]; then
|
if [[ -n "${current}" ]]; then
|
||||||
log "保留 ${key}=***(已有非空值)"
|
log "保留 ${key}=***(已有非空值)"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
local input=""
|
local input=""
|
||||||
if [[ -n "${prompt}" ]]; then
|
if [[ -n "${prompt}" ]]; then
|
||||||
cm_read input "${prompt} [${default}]: "
|
cm_read input "${prompt} [${default}]: "
|
||||||
fi
|
fi
|
||||||
if [[ -z "${input}" ]]; then
|
if [[ -z "${input}" ]]; then
|
||||||
input="${default}"
|
input="${default}"
|
||||||
fi
|
fi
|
||||||
if grep -qE "^${key}=" "${file}" 2>/dev/null; then
|
if grep -qE "^${key}=" "${file}" 2>/dev/null; then
|
||||||
# 替换空值行
|
# 替换空值行
|
||||||
local tmp
|
local tmp
|
||||||
tmp="$(mktemp)"
|
tmp="$(mktemp)"
|
||||||
awk -v k="${key}" -v v="${input}" '
|
awk -v k="${key}" -v v="${input}" '
|
||||||
BEGIN{FS=OFS="="}
|
BEGIN{FS=OFS="="}
|
||||||
$1==k {$0=k"="v}
|
$1==k {$0=k"="v}
|
||||||
{print}
|
{print}
|
||||||
' "${file}" >"${tmp}" && mv "${tmp}" "${file}"
|
' "${file}" >"${tmp}" && mv "${tmp}" "${file}"
|
||||||
else
|
else
|
||||||
printf '%s=%s\n' "${key}" "${input}" >>"${file}"
|
printf '%s=%s\n' "${key}" "${input}" >>"${file}"
|
||||||
fi
|
fi
|
||||||
log "已设置 ${key}"
|
log "已设置 ${key}"
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_dotenv() {
|
ensure_dotenv() {
|
||||||
local root="$1"
|
local root="$1"
|
||||||
local envf="${root}/.env"
|
local envf="${root}/.env"
|
||||||
if [[ ! -f "${envf}" ]]; then
|
if [[ ! -f "${envf}" ]]; then
|
||||||
if [[ -f "${root}/.env.example" ]]; then
|
if [[ -f "${root}/.env.example" ]]; then
|
||||||
cp -a "${root}/.env.example" "${envf}"
|
cp -a "${root}/.env.example" "${envf}"
|
||||||
log "已从 .env.example 生成 .env"
|
log "已从 .env.example 生成 .env"
|
||||||
else
|
else
|
||||||
touch "${envf}"
|
touch "${envf}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
echo "配置 .env(回车采用默认;已有非空值不覆盖)"
|
echo "配置 .env(回车采用默认;已有非空值不覆盖)"
|
||||||
ensure_env_key "${envf}" "MI_PORT" "HTTP 端口" "${MI_PORT_DEFAULT}"
|
ensure_env_key "${envf}" "MI_PORT" "HTTP 端口" "${MI_PORT_DEFAULT}"
|
||||||
ensure_env_key "${envf}" "SAMPLE_INTERVAL_SEC" "采样间隔秒" "30"
|
ensure_env_key "${envf}" "SAMPLE_INTERVAL_SEC" "采样间隔秒" "30"
|
||||||
ensure_env_key "${envf}" "MIN_OPTION_LEVERAGE" "杠杆达标线" "100"
|
ensure_env_key "${envf}" "MIN_OPTION_LEVERAGE" "杠杆达标线" "100"
|
||||||
ensure_env_key "${envf}" "AUTH_SECRET" "鉴权密钥(disabled 关闭)" "change-me"
|
ensure_env_key "${envf}" "AUTH_SECRET" "鉴权密钥(disabled 关闭)" "change-me"
|
||||||
ensure_env_key "${envf}" "ADMIN_PASSWORD" "管理员密码" "admin123"
|
ensure_env_key "${envf}" "ADMIN_PASSWORD" "管理员密码" "admin123"
|
||||||
ensure_env_key "${envf}" "OKX_API_KEY" "OKX API Key(可空)" ""
|
ensure_env_key "${envf}" "OKX_API_KEY" "OKX API Key(可空)" ""
|
||||||
ensure_env_key "${envf}" "OKX_API_SECRET" "OKX API Secret(可空)" ""
|
ensure_env_key "${envf}" "OKX_API_SECRET" "OKX API Secret(可空)" ""
|
||||||
ensure_env_key "${envf}" "OKX_API_PASSPHRASE" "OKX Passphrase(可空)" ""
|
ensure_env_key "${envf}" "OKX_API_PASSPHRASE" "OKX Passphrase(可空)" ""
|
||||||
ensure_env_key "${envf}" "WECOM_ENABLED" "企微告警 1/0" "0"
|
ensure_env_key "${envf}" "WECOM_ENABLED" "企微告警 1/0" "0"
|
||||||
ensure_env_key "${envf}" "WECOM_WEBHOOK_URL" "企微 Webhook(可空)" ""
|
ensure_env_key "${envf}" "WECOM_WEBHOOK_URL" "企微 Webhook(可空)" ""
|
||||||
ensure_env_key "${envf}" "WECOM_MACHINE_NAME" "机器名(可空)" ""
|
ensure_env_key "${envf}" "WECOM_MACHINE_NAME" "机器名(可空)" ""
|
||||||
ensure_env_key "${envf}" "ALERT_FAIL_THRESHOLD" "连续失败告警阈值" "5"
|
ensure_env_key "${envf}" "ALERT_FAIL_THRESHOLD" "连续失败告警阈值" "5"
|
||||||
# 固定库路径(容器内)
|
# 固定库路径(容器内)
|
||||||
if [[ -z "$(read_env_value "${envf}" "MI_DB_PATH")" ]]; then
|
if [[ -z "$(read_env_value "${envf}" "MI_DB_PATH")" ]]; then
|
||||||
ensure_env_key "${envf}" "MI_DB_PATH" "" "/app/data/market_intel.db"
|
ensure_env_key "${envf}" "MI_DB_PATH" "" "/app/data/market_intel.db"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
docker_ok() {
|
docker_ok() {
|
||||||
command -v docker >/dev/null 2>&1 || return 1
|
command -v docker >/dev/null 2>&1 || return 1
|
||||||
docker compose version >/dev/null 2>&1 || return 1
|
docker compose version >/dev/null 2>&1 || return 1
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_docker() {
|
ensure_docker() {
|
||||||
step "环境检测 (Docker / Compose)"
|
step "环境检测 (Docker / Compose)"
|
||||||
if docker_ok; then
|
if docker_ok; then
|
||||||
log "Docker 已就绪: $(docker --version 2>&1)"
|
log "Docker 已就绪: $(docker --version 2>&1)"
|
||||||
log "Compose: $(docker compose version 2>&1)"
|
log "Compose: $(docker compose version 2>&1)"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if ! command -v apt-get >/dev/null 2>&1; then
|
if ! command -v apt-get >/dev/null 2>&1; then
|
||||||
die "未找到 Docker,且无 apt-get,请手动安装 Docker + Compose 插件"
|
die "未找到 Docker,且无 apt-get,请手动安装 Docker + Compose 插件"
|
||||||
fi
|
fi
|
||||||
step "安装 Docker Engine + Compose 插件"
|
step "安装 Docker Engine + Compose 插件"
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
apt_update
|
apt_update
|
||||||
apt_install ca-certificates curl gnupg
|
apt_install ca-certificates curl gnupg
|
||||||
install -m 0755 -d /etc/apt/keyrings
|
install -m 0755 -d /etc/apt/keyrings
|
||||||
if [[ ! -f /etc/apt/keyrings/docker.gpg ]]; then
|
if [[ ! -f /etc/apt/keyrings/docker.gpg ]]; then
|
||||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
chmod a+r /etc/apt/keyrings/docker.gpg
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||||
fi
|
fi
|
||||||
local codename
|
local codename
|
||||||
codename="$(. /etc/os-release && echo "${VERSION_CODENAME}")"
|
codename="$(. /etc/os-release && echo "${VERSION_CODENAME}")"
|
||||||
echo \
|
echo \
|
||||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu ${codename} stable" \
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu ${codename} stable" \
|
||||||
>/etc/apt/sources.list.d/docker.list
|
>/etc/apt/sources.list.d/docker.list
|
||||||
apt_update
|
apt_update
|
||||||
apt_install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
apt_install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||||
systemctl enable --now docker 2>/dev/null || true
|
systemctl enable --now docker 2>/dev/null || true
|
||||||
if ! docker_ok; then
|
if ! docker_ok; then
|
||||||
die "Docker 安装后仍不可用"
|
die "Docker 安装后仍不可用"
|
||||||
fi
|
fi
|
||||||
log "Docker 安装完成"
|
log "Docker 安装完成"
|
||||||
}
|
}
|
||||||
|
|
||||||
compose() {
|
compose() {
|
||||||
local root="${REPO_ROOT:-${INSTALL_ROOT}}"
|
local root="${REPO_ROOT:-${INSTALL_ROOT}}"
|
||||||
(cd "${root}" && docker compose "$@")
|
(cd "${root}" && docker compose "$@")
|
||||||
}
|
}
|
||||||
|
|
||||||
compose_up_build() {
|
compose_up_build() {
|
||||||
step "docker compose up -d --build"
|
step "docker compose up -d --build"
|
||||||
compose up -d --build
|
compose up -d --build
|
||||||
}
|
}
|
||||||
|
|
||||||
compose_stop() {
|
compose_stop() {
|
||||||
require_root
|
require_root
|
||||||
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
||||||
die "未找到安装目录 ${INSTALL_ROOT}"
|
die "未找到安装目录 ${INSTALL_ROOT}"
|
||||||
fi
|
fi
|
||||||
step "停止服务"
|
step "停止服务"
|
||||||
compose stop
|
compose stop
|
||||||
log "已停止"
|
log "已停止"
|
||||||
}
|
}
|
||||||
|
|
||||||
compose_start() {
|
compose_start() {
|
||||||
require_root
|
require_root
|
||||||
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
||||||
die "未找到安装目录 ${INSTALL_ROOT}"
|
die "未找到安装目录 ${INSTALL_ROOT}"
|
||||||
fi
|
fi
|
||||||
step "启动服务"
|
step "启动服务"
|
||||||
compose up -d
|
compose up -d
|
||||||
verify_health || true
|
verify_health || true
|
||||||
}
|
}
|
||||||
|
|
||||||
read_mi_port() {
|
read_mi_port() {
|
||||||
local root="${1:-${REPO_ROOT:-${INSTALL_ROOT}}}"
|
local root="${1:-${REPO_ROOT:-${INSTALL_ROOT}}}"
|
||||||
local p
|
local p
|
||||||
p="$(read_env_value "${root}/.env" "MI_PORT")"
|
p="$(read_env_value "${root}/.env" "MI_PORT")"
|
||||||
if [[ -z "${p}" ]]; then
|
if [[ -z "${p}" ]]; then
|
||||||
p="${MI_PORT_DEFAULT}"
|
p="${MI_PORT_DEFAULT}"
|
||||||
fi
|
fi
|
||||||
echo "${p}"
|
echo "${p}"
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_health() {
|
verify_health() {
|
||||||
local port
|
local port
|
||||||
port="$(read_mi_port)"
|
port="$(read_mi_port)"
|
||||||
local url="http://127.0.0.1:${port}/health"
|
local url="http://127.0.0.1:${port}/health"
|
||||||
step "健康检查 ${url}"
|
step "健康检查 ${url}"
|
||||||
local i
|
local i
|
||||||
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
|
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
|
||||||
if curl -fsS "${url}" >/dev/null 2>&1; then
|
if curl -fsS "${url}" >/dev/null 2>&1; then
|
||||||
log "health OK"
|
log "health OK"
|
||||||
curl -fsS "${url}" || true
|
curl -fsS "${url}" || true
|
||||||
echo ""
|
echo ""
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
log "警告: health 暂未就绪,请检查: docker compose -f ${REPO_ROOT}/docker-compose.yml logs"
|
log "警告: health 暂未就绪,请检查: docker compose -f ${REPO_ROOT}/docker-compose.yml logs"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
show_status() {
|
show_status() {
|
||||||
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
||||||
die "未找到安装目录 ${INSTALL_ROOT}"
|
die "未找到安装目录 ${INSTALL_ROOT}"
|
||||||
fi
|
fi
|
||||||
step "容器状态"
|
step "容器状态"
|
||||||
compose ps || true
|
compose ps || true
|
||||||
verify_health || true
|
verify_health || true
|
||||||
}
|
}
|
||||||
|
|
||||||
print_post_install_guide() {
|
print_post_install_guide() {
|
||||||
local ip port
|
local ip port
|
||||||
ip="$(detect_server_ip)"
|
ip="$(detect_server_ip)"
|
||||||
port="$(read_mi_port)"
|
port="$(read_mi_port)"
|
||||||
echo ""
|
echo ""
|
||||||
echo "══════════════════════════════════════"
|
echo "══════════════════════════════════════"
|
||||||
echo " 比特骆驼行情采集分析 部署完成"
|
echo " 比特骆驼行情采集分析 部署完成"
|
||||||
echo " 目录: ${INSTALL_ROOT}"
|
echo " 目录: ${INSTALL_ROOT}"
|
||||||
echo " 本机: http://${ip}:${port}/health"
|
echo " 本机: http://${ip}:${port}/health"
|
||||||
echo " 看板: http://${ip}:${port}/"
|
echo " 看板: http://${ip}:${port}/"
|
||||||
echo " 管理: bash ${INSTALL_ROOT}/deploy/manage.sh"
|
echo " 管理: bash ${INSTALL_ROOT}/deploy/manage.sh"
|
||||||
echo " 配置: ${INSTALL_ROOT}/.env"
|
echo " 配置: ${INSTALL_ROOT}/.env"
|
||||||
echo "══════════════════════════════════════"
|
echo "══════════════════════════════════════"
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-79
@@ -1,79 +1,79 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# deploy/lib/install.sh — 一键部署 market_intel(Docker Compose)
|
# deploy/lib/install.sh — 一键部署 market_intel(Docker Compose)
|
||||||
set -e
|
set -e
|
||||||
set -u
|
set -u
|
||||||
if [ -n "${BASH_VERSION:-}" ]; then
|
if [ -n "${BASH_VERSION:-}" ]; then
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
fi
|
fi
|
||||||
|
|
||||||
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
# shellcheck source=common.sh
|
# shellcheck source=common.sh
|
||||||
source "${LIB_DIR}/common.sh"
|
source "${LIB_DIR}/common.sh"
|
||||||
|
|
||||||
run_pipeline() {
|
run_pipeline() {
|
||||||
local root="$1"
|
local root="$1"
|
||||||
REPO_ROOT="${root}"
|
REPO_ROOT="${root}"
|
||||||
ensure_dotenv "${root}"
|
ensure_dotenv "${root}"
|
||||||
compose_up_build
|
compose_up_build
|
||||||
verify_health || true
|
verify_health || true
|
||||||
print_post_install_guide
|
print_post_install_guide
|
||||||
}
|
}
|
||||||
|
|
||||||
install_fresh() {
|
install_fresh() {
|
||||||
require_root
|
require_root
|
||||||
step "一键部署 — Docker 环境检测"
|
step "一键部署 — Docker 环境检测"
|
||||||
ensure_docker
|
ensure_docker
|
||||||
# 基础包
|
# 基础包
|
||||||
if ! command -v git >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then
|
if ! command -v git >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
apt_update
|
apt_update
|
||||||
apt_install ca-certificates git curl
|
apt_install ca-certificates git curl
|
||||||
fi
|
fi
|
||||||
step "克隆仓库 → ${INSTALL_ROOT}"
|
step "克隆仓库 → ${INSTALL_ROOT}"
|
||||||
if [[ -d "${INSTALL_ROOT}" ]]; then
|
if [[ -d "${INSTALL_ROOT}" ]]; then
|
||||||
die "目录已存在: ${INSTALL_ROOT},请先卸载或选修复"
|
die "目录已存在: ${INSTALL_ROOT},请先卸载或选修复"
|
||||||
fi
|
fi
|
||||||
mkdir -p "$(dirname "${INSTALL_ROOT}")"
|
mkdir -p "$(dirname "${INSTALL_ROOT}")"
|
||||||
git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}"
|
git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}"
|
||||||
run_pipeline "${INSTALL_ROOT}"
|
run_pipeline "${INSTALL_ROOT}"
|
||||||
}
|
}
|
||||||
|
|
||||||
install_repair() {
|
install_repair() {
|
||||||
require_root
|
require_root
|
||||||
step "修复部署 — Docker 环境检测"
|
step "修复部署 — Docker 环境检测"
|
||||||
ensure_docker
|
ensure_docker
|
||||||
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
||||||
die "未找到安装目录 ${INSTALL_ROOT}"
|
die "未找到安装目录 ${INSTALL_ROOT}"
|
||||||
fi
|
fi
|
||||||
step "修复环境(保留 .env 与 data volume)"
|
step "修复环境(保留 .env 与 data volume)"
|
||||||
if [[ -d "${REPO_ROOT}/.git" ]]; then
|
if [[ -d "${REPO_ROOT}/.git" ]]; then
|
||||||
git -C "${REPO_ROOT}" pull --ff-only origin "${GIT_BRANCH}" 2>/dev/null \
|
git -C "${REPO_ROOT}" pull --ff-only origin "${GIT_BRANCH}" 2>/dev/null \
|
||||||
|| git -C "${REPO_ROOT}" pull --ff-only 2>/dev/null \
|
|| git -C "${REPO_ROOT}" pull --ff-only 2>/dev/null \
|
||||||
|| true
|
|| true
|
||||||
fi
|
fi
|
||||||
run_pipeline "${REPO_ROOT}"
|
run_pipeline "${REPO_ROOT}"
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_existing() {
|
handle_existing() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "检测到已部署: ${INSTALL_ROOT}"
|
echo "检测到已部署: ${INSTALL_ROOT}"
|
||||||
echo " a) 取消"
|
echo " a) 取消"
|
||||||
echo " b) 修复/重装环境(保留 .env 与数据 volume)"
|
echo " b) 修复/重装环境(保留 .env 与数据 volume)"
|
||||||
local choice=""
|
local choice=""
|
||||||
cm_read choice "请选择 [a/b]: "
|
cm_read choice "请选择 [a/b]: "
|
||||||
case "${choice}" in
|
case "${choice}" in
|
||||||
b|B) install_repair ;;
|
b|B) install_repair ;;
|
||||||
*) log "已取消" ;;
|
*) log "已取消" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
main_install() {
|
main_install() {
|
||||||
require_root
|
require_root
|
||||||
if repo_ready "${INSTALL_ROOT}"; then
|
if repo_ready "${INSTALL_ROOT}"; then
|
||||||
handle_existing
|
handle_existing
|
||||||
else
|
else
|
||||||
install_fresh
|
install_fresh
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
main_install "$@"
|
main_install "$@"
|
||||||
|
|||||||
+105
-105
@@ -1,105 +1,105 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# deploy/lib/uninstall.sh — 停容器;可选删 volume;备份 .env;删除安装目录
|
# deploy/lib/uninstall.sh — 停容器;可选删 volume;备份 .env;删除安装目录
|
||||||
set -e
|
set -e
|
||||||
set -u
|
set -u
|
||||||
if [ -n "${BASH_VERSION:-}" ]; then
|
if [ -n "${BASH_VERSION:-}" ]; then
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
fi
|
fi
|
||||||
|
|
||||||
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
# shellcheck source=common.sh
|
# shellcheck source=common.sh
|
||||||
source "${LIB_DIR}/common.sh"
|
source "${LIB_DIR}/common.sh"
|
||||||
|
|
||||||
main_uninstall() {
|
main_uninstall() {
|
||||||
require_root
|
require_root
|
||||||
|
|
||||||
local root=""
|
local root=""
|
||||||
if ! root="$(resolve_repo_root)"; then
|
if ! root="$(resolve_repo_root)"; then
|
||||||
if [[ -d "${INSTALL_ROOT}" ]]; then
|
if [[ -d "${INSTALL_ROOT}" ]]; then
|
||||||
root="${INSTALL_ROOT}"
|
root="${INSTALL_ROOT}"
|
||||||
else
|
else
|
||||||
die "未找到安装目录 ${INSTALL_ROOT}"
|
die "未找到安装目录 ${INSTALL_ROOT}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
REPO_ROOT="${root}"
|
REPO_ROOT="${root}"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "将卸载 比特骆驼行情采集分析 (market_intel):"
|
echo "将卸载 比特骆驼行情采集分析 (market_intel):"
|
||||||
echo " - 停止并移除 Compose 容器"
|
echo " - 停止并移除 Compose 容器"
|
||||||
echo " - 备份 .env 到 ${BACKUP_ROOT}"
|
echo " - 备份 .env 到 ${BACKUP_ROOT}"
|
||||||
echo " - 删除安装目录: ${INSTALL_ROOT}"
|
echo " - 删除安装目录: ${INSTALL_ROOT}"
|
||||||
echo " - 可选:删除 data volume"
|
echo " - 可选:删除 data volume"
|
||||||
echo ""
|
echo ""
|
||||||
if ! confirm_yes "确认卸载并删除 ${INSTALL_ROOT}?"; then
|
if ! confirm_yes "确认卸载并删除 ${INSTALL_ROOT}?"; then
|
||||||
log "已取消卸载"
|
log "已取消卸载"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local remove_volume=0
|
local remove_volume=0
|
||||||
if confirm_yes "是否同时删除 Docker data volume (mi_data)?"; then
|
if confirm_yes "是否同时删除 Docker data volume (mi_data)?"; then
|
||||||
remove_volume=1
|
remove_volume=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local stamp backup_dir
|
local stamp backup_dir
|
||||||
stamp="$(TZ="${TZ_NAME}" date +%Y%m%d-%H%M%S)"
|
stamp="$(TZ="${TZ_NAME}" date +%Y%m%d-%H%M%S)"
|
||||||
backup_dir="${BACKUP_ROOT}/pre-uninstall-${stamp}"
|
backup_dir="${BACKUP_ROOT}/pre-uninstall-${stamp}"
|
||||||
mkdir -p "${backup_dir}"
|
mkdir -p "${backup_dir}"
|
||||||
|
|
||||||
step "备份 .env"
|
step "备份 .env"
|
||||||
if [[ -f "${REPO_ROOT}/.env" ]]; then
|
if [[ -f "${REPO_ROOT}/.env" ]]; then
|
||||||
cp -a "${REPO_ROOT}/.env" "${backup_dir}/.env"
|
cp -a "${REPO_ROOT}/.env" "${backup_dir}/.env"
|
||||||
fi
|
fi
|
||||||
{
|
{
|
||||||
echo "created_at=${stamp}"
|
echo "created_at=${stamp}"
|
||||||
echo "install_root=${INSTALL_ROOT}"
|
echo "install_root=${INSTALL_ROOT}"
|
||||||
echo "remove_volume=${remove_volume}"
|
echo "remove_volume=${remove_volume}"
|
||||||
echo "action=rm_rf_install_root"
|
echo "action=rm_rf_install_root"
|
||||||
} >"${backup_dir}/uninstall.manifest"
|
} >"${backup_dir}/uninstall.manifest"
|
||||||
|
|
||||||
step "停止并移除容器"
|
step "停止并移除容器"
|
||||||
if command -v docker >/dev/null 2>&1 && [[ -f "${REPO_ROOT}/docker-compose.yml" ]]; then
|
if command -v docker >/dev/null 2>&1 && [[ -f "${REPO_ROOT}/docker-compose.yml" ]]; then
|
||||||
if [[ "${remove_volume}" -eq 1 ]]; then
|
if [[ "${remove_volume}" -eq 1 ]]; then
|
||||||
(cd "${REPO_ROOT}" && docker compose down -v) || true
|
(cd "${REPO_ROOT}" && docker compose down -v) || true
|
||||||
else
|
else
|
||||||
(cd "${REPO_ROOT}" && docker compose down) || true
|
(cd "${REPO_ROOT}" && docker compose down) || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
step "删除安装目录 ${INSTALL_ROOT}"
|
step "删除安装目录 ${INSTALL_ROOT}"
|
||||||
if [[ -d "${INSTALL_ROOT}" ]]; then
|
if [[ -d "${INSTALL_ROOT}" ]]; then
|
||||||
case "${INSTALL_ROOT}" in
|
case "${INSTALL_ROOT}" in
|
||||||
/opt/market_intel|/opt/market_intel/)
|
/opt/market_intel|/opt/market_intel/)
|
||||||
rm -rf "${INSTALL_ROOT}"
|
rm -rf "${INSTALL_ROOT}"
|
||||||
log "已删除: ${INSTALL_ROOT}"
|
log "已删除: ${INSTALL_ROOT}"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
if [[ "${ALLOW_UNSAFE_UNINSTALL:-}" == "1" ]]; then
|
if [[ "${ALLOW_UNSAFE_UNINSTALL:-}" == "1" ]]; then
|
||||||
rm -rf "${INSTALL_ROOT}"
|
rm -rf "${INSTALL_ROOT}"
|
||||||
log "已删除(ALLOW_UNSAFE_UNINSTALL=1): ${INSTALL_ROOT}"
|
log "已删除(ALLOW_UNSAFE_UNINSTALL=1): ${INSTALL_ROOT}"
|
||||||
else
|
else
|
||||||
die "拒绝删除非默认路径 ${INSTALL_ROOT};若确认,设置 ALLOW_UNSAFE_UNINSTALL=1"
|
die "拒绝删除非默认路径 ${INSTALL_ROOT};若确认,设置 ALLOW_UNSAFE_UNINSTALL=1"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
else
|
else
|
||||||
log "安装目录不存在,跳过删除"
|
log "安装目录不存在,跳过删除"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local leftover
|
local leftover
|
||||||
for leftover in /opt/market_intel.removed.* /opt/market_intel.old.*; do
|
for leftover in /opt/market_intel.removed.* /opt/market_intel.old.*; do
|
||||||
if [[ -e "${leftover}" ]]; then
|
if [[ -e "${leftover}" ]]; then
|
||||||
rm -rf "${leftover}"
|
rm -rf "${leftover}"
|
||||||
log "已清理残留: ${leftover}"
|
log "已清理残留: ${leftover}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "卸载完成."
|
echo "卸载完成."
|
||||||
echo " 配置备份: ${backup_dir}"
|
echo " 配置备份: ${backup_dir}"
|
||||||
echo " volume 已删除: $([[ ${remove_volume} -eq 1 ]] && echo yes || echo no)"
|
echo " volume 已删除: $([[ ${remove_volume} -eq 1 ]] && echo yes || echo no)"
|
||||||
echo ""
|
echo ""
|
||||||
echo "重新部署:"
|
echo "重新部署:"
|
||||||
echo " curl -fsSL https://git.bz121.com/dekun/market_intel/raw/branch/main/deploy/manage.sh | bash"
|
echo " curl -fsSL https://git.bz121.com/dekun/market_intel/raw/branch/main/deploy/manage.sh | bash"
|
||||||
}
|
}
|
||||||
|
|
||||||
main_uninstall "$@"
|
main_uninstall "$@"
|
||||||
|
|||||||
+41
-41
@@ -1,41 +1,41 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# deploy/lib/update.sh — git pull + compose build/up;保留 .env 与 volume
|
# deploy/lib/update.sh — git pull + compose build/up;保留 .env 与 volume
|
||||||
set -e
|
set -e
|
||||||
set -u
|
set -u
|
||||||
if [ -n "${BASH_VERSION:-}" ]; then
|
if [ -n "${BASH_VERSION:-}" ]; then
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
fi
|
fi
|
||||||
|
|
||||||
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
# shellcheck source=common.sh
|
# shellcheck source=common.sh
|
||||||
source "${LIB_DIR}/common.sh"
|
source "${LIB_DIR}/common.sh"
|
||||||
|
|
||||||
main_update() {
|
main_update() {
|
||||||
require_root
|
require_root
|
||||||
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
||||||
die "未找到安装目录 ${INSTALL_ROOT},请先执行「1) 一键部署」"
|
die "未找到安装目录 ${INSTALL_ROOT},请先执行「1) 一键部署」"
|
||||||
fi
|
fi
|
||||||
if ! repo_ready "${REPO_ROOT}"; then
|
if ! repo_ready "${REPO_ROOT}"; then
|
||||||
die "安装不完整,请先执行「1) 一键部署」"
|
die "安装不完整,请先执行「1) 一键部署」"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
step "更新 — Docker 环境检测"
|
step "更新 — Docker 环境检测"
|
||||||
ensure_docker
|
ensure_docker
|
||||||
step "git pull"
|
step "git pull"
|
||||||
if [[ -d "${REPO_ROOT}/.git" ]]; then
|
if [[ -d "${REPO_ROOT}/.git" ]]; then
|
||||||
git -C "${REPO_ROOT}" fetch --all --prune
|
git -C "${REPO_ROOT}" fetch --all --prune
|
||||||
git -C "${REPO_ROOT}" checkout "${GIT_BRANCH}" 2>/dev/null || true
|
git -C "${REPO_ROOT}" checkout "${GIT_BRANCH}" 2>/dev/null || true
|
||||||
git -C "${REPO_ROOT}" pull --ff-only origin "${GIT_BRANCH}" \
|
git -C "${REPO_ROOT}" pull --ff-only origin "${GIT_BRANCH}" \
|
||||||
|| git -C "${REPO_ROOT}" pull --ff-only
|
|| git -C "${REPO_ROOT}" pull --ff-only
|
||||||
else
|
else
|
||||||
log "警告: 非 git 目录,跳过 pull"
|
log "警告: 非 git 目录,跳过 pull"
|
||||||
fi
|
fi
|
||||||
# 补全缺失 env key,不覆盖已有
|
# 补全缺失 env key,不覆盖已有
|
||||||
ensure_dotenv "${REPO_ROOT}"
|
ensure_dotenv "${REPO_ROOT}"
|
||||||
compose_up_build
|
compose_up_build
|
||||||
verify_health || true
|
verify_health || true
|
||||||
echo ""
|
echo ""
|
||||||
log "更新完成(.env 与 data volume 已保留)"
|
log "更新完成(.env 与 data volume 已保留)"
|
||||||
}
|
}
|
||||||
|
|
||||||
main_update "$@"
|
main_update "$@"
|
||||||
|
|||||||
+228
-228
@@ -1,228 +1,228 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# 比特骆驼行情采集分析 部署管理器(工程 market_intel)
|
# 比特骆驼行情采集分析 部署管理器(工程 market_intel)
|
||||||
# 部署环境: Ubuntu 22.04 LTS · Docker Compose
|
# 部署环境: Ubuntu 22.04 LTS · Docker Compose
|
||||||
#
|
#
|
||||||
# 新服务器(免克隆):
|
# 新服务器(免克隆):
|
||||||
# curl -fsSL https://git.bz121.com/dekun/market_intel/raw/branch/main/deploy/manage.sh | bash
|
# curl -fsSL https://git.bz121.com/dekun/market_intel/raw/branch/main/deploy/manage.sh | bash
|
||||||
#
|
#
|
||||||
# 已安装:
|
# 已安装:
|
||||||
# bash /opt/market_intel/deploy/manage.sh
|
# bash /opt/market_intel/deploy/manage.sh
|
||||||
#
|
#
|
||||||
set -e
|
set -e
|
||||||
if [ -n "${BASH_VERSION:-}" ]; then
|
if [ -n "${BASH_VERSION:-}" ]; then
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
fi
|
fi
|
||||||
|
|
||||||
INSTALL_ROOT="${INSTALL_ROOT:-/opt/market_intel}"
|
INSTALL_ROOT="${INSTALL_ROOT:-/opt/market_intel}"
|
||||||
GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/market_intel.git}"
|
GIT_URL="${GIT_URL:-https://git.bz121.com/dekun/market_intel.git}"
|
||||||
GIT_BRANCH="${GIT_BRANCH:-main}"
|
GIT_BRANCH="${GIT_BRANCH:-main}"
|
||||||
|
|
||||||
_script_src="${BASH_SOURCE[0]:-}"
|
_script_src="${BASH_SOURCE[0]:-}"
|
||||||
if [[ -n "${_script_src}" && -f "${_script_src}" ]]; then
|
if [[ -n "${_script_src}" && -f "${_script_src}" ]]; then
|
||||||
DEPLOY_DIR="$(cd "$(dirname "${_script_src}")" && pwd)"
|
DEPLOY_DIR="$(cd "$(dirname "${_script_src}")" && pwd)"
|
||||||
REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)"
|
REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)"
|
||||||
LIB_DIR="${DEPLOY_DIR}/lib"
|
LIB_DIR="${DEPLOY_DIR}/lib"
|
||||||
else
|
else
|
||||||
DEPLOY_DIR=""
|
DEPLOY_DIR=""
|
||||||
REPO_ROOT=""
|
REPO_ROOT=""
|
||||||
LIB_DIR=""
|
LIB_DIR=""
|
||||||
fi
|
fi
|
||||||
unset _script_src
|
unset _script_src
|
||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
repo_ready() {
|
repo_ready() {
|
||||||
[[ -f "${1}/deploy/manage.sh" && -f "${1}/docker-compose.yml" && -d "${1}/deploy/lib" ]]
|
[[ -f "${1}/deploy/manage.sh" && -f "${1}/docker-compose.yml" && -d "${1}/deploy/lib" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_git_cli() {
|
ensure_git_cli() {
|
||||||
if command -v git >/dev/null 2>&1; then
|
if command -v git >/dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if command -v apt-get >/dev/null 2>&1; then
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
local waited=0
|
local waited=0
|
||||||
while pgrep -x unattended-upgr >/dev/null 2>&1 \
|
while pgrep -x unattended-upgr >/dev/null 2>&1 \
|
||||||
|| pgrep -x apt-get >/dev/null 2>&1 \
|
|| pgrep -x apt-get >/dev/null 2>&1 \
|
||||||
|| pgrep -x apt >/dev/null 2>&1 \
|
|| pgrep -x apt >/dev/null 2>&1 \
|
||||||
|| pgrep -x dpkg >/dev/null 2>&1 \
|
|| pgrep -x dpkg >/dev/null 2>&1 \
|
||||||
|| { command -v fuser >/dev/null 2>&1 && fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; }; do
|
|| { command -v fuser >/dev/null 2>&1 && fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; }; do
|
||||||
if [[ "${waited}" -eq 0 ]]; then
|
if [[ "${waited}" -eq 0 ]]; then
|
||||||
echo "等待 apt 锁释放(unattended-upgrades)…"
|
echo "等待 apt 锁释放(unattended-upgrades)…"
|
||||||
fi
|
fi
|
||||||
if [[ "${waited}" -ge 600 ]]; then
|
if [[ "${waited}" -ge 600 ]]; then
|
||||||
echo "错误: 等待 apt 锁超时,请稍后再试" >&2
|
echo "错误: 等待 apt 锁超时,请稍后再试" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
sleep 5
|
sleep 5
|
||||||
waited=$((waited + 5))
|
waited=$((waited + 5))
|
||||||
done
|
done
|
||||||
apt-get update -qq
|
apt-get update -qq
|
||||||
apt-get install -y git ca-certificates curl
|
apt-get install -y git ca-certificates curl
|
||||||
else
|
else
|
||||||
echo "错误: 未找到 git" >&2
|
echo "错误: 未找到 git" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
sync_repo_if_present() {
|
sync_repo_if_present() {
|
||||||
local root="$1"
|
local root="$1"
|
||||||
if [[ -d "${root}/.git" ]] && command -v git >/dev/null 2>&1; then
|
if [[ -d "${root}/.git" ]] && command -v git >/dev/null 2>&1; then
|
||||||
git -C "${root}" fetch --all --prune 2>/dev/null || true
|
git -C "${root}" fetch --all --prune 2>/dev/null || true
|
||||||
git -C "${root}" checkout "${GIT_BRANCH}" 2>/dev/null || true
|
git -C "${root}" checkout "${GIT_BRANCH}" 2>/dev/null || true
|
||||||
git -C "${root}" pull --ff-only origin "${GIT_BRANCH}" 2>/dev/null \
|
git -C "${root}" pull --ff-only origin "${GIT_BRANCH}" 2>/dev/null \
|
||||||
|| git -C "${root}" pull --ff-only 2>/dev/null \
|
|| git -C "${root}" pull --ff-only 2>/dev/null \
|
||||||
|| true
|
|| true
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
heal_existing_install() {
|
heal_existing_install() {
|
||||||
local root="$1"
|
local root="$1"
|
||||||
echo "检测到已有目录但缺少管理脚本: ${root}"
|
echo "检测到已有目录但缺少管理脚本: ${root}"
|
||||||
echo "尝试同步最新代码…"
|
echo "尝试同步最新代码…"
|
||||||
ensure_git_cli
|
ensure_git_cli
|
||||||
|
|
||||||
if [[ -d "${root}/.git" ]]; then
|
if [[ -d "${root}/.git" ]]; then
|
||||||
sync_repo_if_present "${root}"
|
sync_repo_if_present "${root}"
|
||||||
if repo_ready "${root}"; then
|
if repo_ready "${root}"; then
|
||||||
echo "同步成功,切换到仓库内 manage.sh"
|
echo "同步成功,切换到仓库内 manage.sh"
|
||||||
exec bash "${root}/deploy/manage.sh" "$@" </dev/tty
|
exec bash "${root}/deploy/manage.sh" "$@" </dev/tty
|
||||||
fi
|
fi
|
||||||
echo "git pull 后仍不完整,尝试强制对齐 origin/${GIT_BRANCH} …"
|
echo "git pull 后仍不完整,尝试强制对齐 origin/${GIT_BRANCH} …"
|
||||||
git -C "${root}" fetch origin "${GIT_BRANCH}" || true
|
git -C "${root}" fetch origin "${GIT_BRANCH}" || true
|
||||||
git -C "${root}" reset --hard "origin/${GIT_BRANCH}" || true
|
git -C "${root}" reset --hard "origin/${GIT_BRANCH}" || true
|
||||||
if repo_ready "${root}"; then
|
if repo_ready "${root}"; then
|
||||||
echo "对齐成功,切换到仓库内 manage.sh"
|
echo "对齐成功,切换到仓库内 manage.sh"
|
||||||
exec bash "${root}/deploy/manage.sh" "$@" </dev/tty
|
exec bash "${root}/deploy/manage.sh" "$@" </dev/tty
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "将备份配置并重新克隆到 ${root}"
|
echo "将备份配置并重新克隆到 ${root}"
|
||||||
local stamp backup_dir
|
local stamp backup_dir
|
||||||
stamp="$(date +%Y%m%d-%H%M%S)"
|
stamp="$(date +%Y%m%d-%H%M%S)"
|
||||||
backup_dir="/root/backups/market_intel/heal-${stamp}"
|
backup_dir="/root/backups/market_intel/heal-${stamp}"
|
||||||
mkdir -p "${backup_dir}"
|
mkdir -p "${backup_dir}"
|
||||||
[[ -f "${root}/.env" ]] && cp -a "${root}/.env" "${backup_dir}/.env"
|
[[ -f "${root}/.env" ]] && cp -a "${root}/.env" "${backup_dir}/.env"
|
||||||
echo "备份目录: ${backup_dir}"
|
echo "备份目录: ${backup_dir}"
|
||||||
|
|
||||||
local removed="${root}.old.${stamp}"
|
local removed="${root}.old.${stamp}"
|
||||||
mv "${root}" "${removed}"
|
mv "${root}" "${removed}"
|
||||||
echo "旧目录已移至: ${removed}"
|
echo "旧目录已移至: ${removed}"
|
||||||
mkdir -p "$(dirname "${root}")"
|
mkdir -p "$(dirname "${root}")"
|
||||||
git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${root}"
|
git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${root}"
|
||||||
if [[ -f "${backup_dir}/.env" ]]; then
|
if [[ -f "${backup_dir}/.env" ]]; then
|
||||||
cp -a "${backup_dir}/.env" "${root}/.env"
|
cp -a "${backup_dir}/.env" "${root}/.env"
|
||||||
echo "已恢复 .env"
|
echo "已恢复 .env"
|
||||||
fi
|
fi
|
||||||
exec bash "${root}/deploy/manage.sh" "$@" </dev/tty
|
exec bash "${root}/deploy/manage.sh" "$@" </dev/tty
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrap_repo() {
|
bootstrap_repo() {
|
||||||
if repo_ready "${INSTALL_ROOT}"; then
|
if repo_ready "${INSTALL_ROOT}"; then
|
||||||
REPO_ROOT="${INSTALL_ROOT}"
|
REPO_ROOT="${INSTALL_ROOT}"
|
||||||
DEPLOY_DIR="${REPO_ROOT}/deploy"
|
DEPLOY_DIR="${REPO_ROOT}/deploy"
|
||||||
LIB_DIR="${DEPLOY_DIR}/lib"
|
LIB_DIR="${DEPLOY_DIR}/lib"
|
||||||
sync_repo_if_present "${REPO_ROOT}"
|
sync_repo_if_present "${REPO_ROOT}"
|
||||||
if ! repo_ready "${REPO_ROOT}"; then
|
if ! repo_ready "${REPO_ROOT}"; then
|
||||||
heal_existing_install "${INSTALL_ROOT}" "$@"
|
heal_existing_install "${INSTALL_ROOT}" "$@"
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if [[ -n "${REPO_ROOT}" ]] && repo_ready "${REPO_ROOT}"; then
|
if [[ -n "${REPO_ROOT}" ]] && repo_ready "${REPO_ROOT}"; then
|
||||||
DEPLOY_DIR="${REPO_ROOT}/deploy"
|
DEPLOY_DIR="${REPO_ROOT}/deploy"
|
||||||
LIB_DIR="${DEPLOY_DIR}/lib"
|
LIB_DIR="${DEPLOY_DIR}/lib"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -d "${INSTALL_ROOT}" ]]; then
|
if [[ -d "${INSTALL_ROOT}" ]]; then
|
||||||
if [[ "$(id -u)" -ne 0 ]]; then
|
if [[ "$(id -u)" -ne 0 ]]; then
|
||||||
echo "错误: 请使用 root 执行" >&2
|
echo "错误: 请使用 root 执行" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
heal_existing_install "${INSTALL_ROOT}" "$@"
|
heal_existing_install "${INSTALL_ROOT}" "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "比特骆驼行情采集分析 部署管理器 — 首次自举"
|
echo "比特骆驼行情采集分析 部署管理器 — 首次自举"
|
||||||
echo "将克隆到: ${INSTALL_ROOT}"
|
echo "将克隆到: ${INSTALL_ROOT}"
|
||||||
if [[ "$(id -u)" -ne 0 ]]; then
|
if [[ "$(id -u)" -ne 0 ]]; then
|
||||||
echo "错误: 请使用 root 执行" >&2
|
echo "错误: 请使用 root 执行" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
ensure_git_cli
|
ensure_git_cli
|
||||||
mkdir -p "$(dirname "${INSTALL_ROOT}")"
|
mkdir -p "$(dirname "${INSTALL_ROOT}")"
|
||||||
git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}"
|
git clone -b "${GIT_BRANCH}" "${GIT_URL}" "${INSTALL_ROOT}"
|
||||||
exec bash "${INSTALL_ROOT}/deploy/manage.sh" "$@" </dev/tty
|
exec bash "${INSTALL_ROOT}/deploy/manage.sh" "$@" </dev/tty
|
||||||
}
|
}
|
||||||
|
|
||||||
show_banner() {
|
show_banner() {
|
||||||
local path
|
local path
|
||||||
path="${INSTALL_ROOT}"
|
path="${INSTALL_ROOT}"
|
||||||
if [[ -n "${REPO_ROOT}" ]] && repo_ready "${REPO_ROOT}"; then
|
if [[ -n "${REPO_ROOT}" ]] && repo_ready "${REPO_ROOT}"; then
|
||||||
path="${REPO_ROOT}"
|
path="${REPO_ROOT}"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
echo "╔══════════════════════════════════════╗"
|
echo "╔══════════════════════════════════════╗"
|
||||||
echo "║ 比特骆驼行情采集分析 部署管理器 ║"
|
echo "║ 比特骆驼行情采集分析 部署管理器 ║"
|
||||||
echo "║ 路径: ${path}"
|
echo "║ 路径: ${path}"
|
||||||
echo "╚══════════════════════════════════════╝"
|
echo "╚══════════════════════════════════════╝"
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
show_menu() {
|
show_menu() {
|
||||||
echo " 1) 一键部署"
|
echo " 1) 一键部署"
|
||||||
echo " 2) 更新"
|
echo " 2) 更新"
|
||||||
echo " 3) 停止"
|
echo " 3) 停止"
|
||||||
echo " 4) 启动"
|
echo " 4) 启动"
|
||||||
echo " 5) 查看状态"
|
echo " 5) 查看状态"
|
||||||
echo " 6) 一键卸载"
|
echo " 6) 一键卸载"
|
||||||
echo " 0) 退出"
|
echo " 0) 退出"
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
cm_read() {
|
cm_read() {
|
||||||
local __var="$1"
|
local __var="$1"
|
||||||
local __prompt="${2:-}"
|
local __prompt="${2:-}"
|
||||||
local __line=""
|
local __line=""
|
||||||
if [[ -n "${__prompt}" ]]; then
|
if [[ -n "${__prompt}" ]]; then
|
||||||
printf '%s' "${__prompt}" >/dev/tty 2>/dev/null || printf '%s' "${__prompt}"
|
printf '%s' "${__prompt}" >/dev/tty 2>/dev/null || printf '%s' "${__prompt}"
|
||||||
fi
|
fi
|
||||||
if [[ -r /dev/tty ]]; then
|
if [[ -r /dev/tty ]]; then
|
||||||
IFS= read -r __line </dev/tty || true
|
IFS= read -r __line </dev/tty || true
|
||||||
else
|
else
|
||||||
IFS= read -r __line || true
|
IFS= read -r __line || true
|
||||||
fi
|
fi
|
||||||
printf -v "${__var}" '%s' "${__line}"
|
printf -v "${__var}" '%s' "${__line}"
|
||||||
}
|
}
|
||||||
|
|
||||||
main_menu() {
|
main_menu() {
|
||||||
bootstrap_repo
|
bootstrap_repo
|
||||||
# shellcheck source=lib/common.sh
|
# shellcheck source=lib/common.sh
|
||||||
source "${LIB_DIR}/common.sh"
|
source "${LIB_DIR}/common.sh"
|
||||||
REPO_ROOT="$(resolve_repo_root || echo "${INSTALL_ROOT}")"
|
REPO_ROOT="$(resolve_repo_root || echo "${INSTALL_ROOT}")"
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
show_banner
|
show_banner
|
||||||
show_menu
|
show_menu
|
||||||
local choice=""
|
local choice=""
|
||||||
cm_read choice "请选择 [0-6]: "
|
cm_read choice "请选择 [0-6]: "
|
||||||
case "${choice}" in
|
case "${choice}" in
|
||||||
1) bash "${LIB_DIR}/install.sh" ;;
|
1) bash "${LIB_DIR}/install.sh" ;;
|
||||||
2) bash "${LIB_DIR}/update.sh" ;;
|
2) bash "${LIB_DIR}/update.sh" ;;
|
||||||
3) compose_stop ;;
|
3) compose_stop ;;
|
||||||
4) compose_start ;;
|
4) compose_start ;;
|
||||||
5) show_status ;;
|
5) show_status ;;
|
||||||
6) bash "${LIB_DIR}/uninstall.sh" ;;
|
6) bash "${LIB_DIR}/uninstall.sh" ;;
|
||||||
0)
|
0)
|
||||||
echo "再见."
|
echo "再见."
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "无效选项,请输入 0-6"
|
echo "无效选项,请输入 0-6"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
echo ""
|
echo ""
|
||||||
cm_read _ "按 Enter 返回菜单..."
|
cm_read _ "按 Enter 返回菜单..."
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
main_menu "$@"
|
main_menu "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user