修复容器环境三个关键bug:systemd误判、变量名冲突、启动验证

- has_systemd(): 改为检查 /proc/1/comm 是否为 systemd,避免容器中 systemctl --version 误判
- read_or_default(): 简化为两参数,去掉变量名间接引用避免冲突
- 新增 confirm_or_default(): 处理 y/n 确认,管道模式默认 true
- safe_start_service(): systemd 启动失败自动回退到 nohup
- safe_start_service(): 启动后 sleep 1 并验证进程存活,失败输出日志路径
- get_service_status(): unknown -> inactive(更准确的措辞)
- 端口变量支持环境变量覆盖: GATEWAY_PORT/REMOTE_PORT
This commit is contained in:
2026-07-02 14:54:00 +08:00
parent a6fbf3c175
commit d9eccdfd81
+59 -40
View File
@@ -13,55 +13,71 @@ log_warn() { echo -e "${YELLOW}[WARN]${PLAIN} $1"; }
log_error() { echo -e "${RED}[ERROR]${PLAIN} $1"; } log_error() { echo -e "${RED}[ERROR]${PLAIN} $1"; }
log_step() { echo -e "\n${BLUE}[${1}]${PLAIN} ${2}"; } log_step() { echo -e "\n${BLUE}[${1}]${PLAIN} ${2}"; }
# 检测是否在管道中运行(stdin 不是 tty # 交互式读取或自动使用默认值(管道模式下静默使用默认值
is_piped() {
[ ! -t 0 ]
}
# 交互式读取或自动使用默认值
read_or_default() { read_or_default() {
local prompt_msg="$1" local prompt_msg="$1"
local default_value="$2" local default_value="$2"
local var_name="$3"
if is_piped; then if [ -t 0 ]; then
# 管道模式:检查环境变量,否则使用默认值
local env_val="${!var_name}"
if [ -n "$env_val" ]; then
echo "$env_val"
else
echo "$default_value"
fi
else
# 交互模式:正常 read
read -p "$prompt_msg" input_val read -p "$prompt_msg" input_val
echo "${input_val:-$default_value}" echo "${input_val:-$default_value}"
else
echo "$default_value"
fi fi
} }
# 交互式确认(管道模式下默认返回 true)
confirm_or_default() {
local prompt_msg="$1"
local default="$2"
if [ -t 0 ]; then
read -p "$prompt_msg" answer
answer="${answer:-$default}"
[[ "$answer" == "y" || "$answer" == "Y" ]]
else
[[ "$default" == "y" || "$default" == "Y" ]]
fi
}
# 检查是否有 systemdpid=1 是 systemd 才算真正有 systemd
has_systemd() { has_systemd() {
[ -d /run/systemd/system ] || [ -d /var/run/systemd/system ] || systemctl --version &>/dev/null [ -f /proc/1/comm ] && grep -qx "systemd" /proc/1/comm 2>/dev/null
} }
# 安全的进程启动(支持 systemd 和 nohup 两种模式) # 安全的进程启动(支持 systemd 和 nohup 两种模式)
# 返回 0 表示启动成功
safe_start_service() { safe_start_service() {
local name=$1 local name=$1
local cmd=$2 local cmd=$2
local service_file=$3
if has_systemd; then if has_systemd; then
systemctl daemon-reload 2>/dev/null systemctl daemon-reload 2>/dev/null
systemctl enable "$name" --now 2>/dev/null if systemctl enable "$name" --now 2>/dev/null; then
log_info "$name 已通过 systemd 启动" log_info "$name 已通过 systemd 启动"
else
# 容器/无 systemd 环境:使用 nohup + 简单的 PID 文件管理
local pid_file="/var/run/${name}.pid"
if [ -f "$pid_file" ] && kill -0 "$(cat "$pid_file")" 2>/dev/null; then
log_warn "$name 已在运行 (PID: $(cat "$pid_file"))"
return 0 return 0
fi fi
nohup $cmd > "/var/log/${name}.log" 2>&1 & # systemd 启动失败,回退到 nohup
echo $! > "$pid_file" log_warn "systemd 启动失败,回退到 nohup 模式"
fi
# 容器/无 systemd 环境:使用 nohup + 简单的 PID 文件管理
local pid_file="/var/run/${name}.pid"
local log_file="/var/log/${name}.log"
if [ -f "$pid_file" ] && kill -0 "$(cat "$pid_file")" 2>/dev/null; then
log_warn "$name 已在运行 (PID: $(cat "$pid_file"))"
return 0
fi
nohup $cmd > "$log_file" 2>&1 &
echo $! > "$pid_file"
sleep 1
if kill -0 "$!" 2>/dev/null; then
log_info "$name 已通过 nohup 启动 (PID: $!)" log_info "$name 已通过 nohup 启动 (PID: $!)"
return 0
else
log_error "$name 启动失败,查看日志: $log_file"
return 1
fi fi
} }
@@ -69,7 +85,7 @@ safe_start_service() {
get_service_status() { get_service_status() {
local name=$1 local name=$1
if has_systemd; then if has_systemd; then
systemctl is-active "$name" 2>/dev/null || echo "unknown" systemctl is-active "$name" 2>/dev/null || echo "inactive"
else else
local pid_file="/var/run/${name}.pid" local pid_file="/var/run/${name}.pid"
if [ -f "$pid_file" ] && kill -0 "$(cat "$pid_file")" 2>/dev/null; then if [ -f "$pid_file" ] && kill -0 "$(cat "$pid_file")" 2>/dev/null; then
@@ -87,8 +103,10 @@ restart_service() {
systemctl restart "$name" 2>/dev/null systemctl restart "$name" 2>/dev/null
else else
local pid_file="/var/run/${name}.pid" local pid_file="/var/run/${name}.pid"
[ -f "$pid_file" ] && kill "$(cat "$pid_file")" 2>/dev/null if [ -f "$pid_file" ]; then
sleep 1 kill "$(cat "$pid_file")" 2>/dev/null
sleep 1
fi
fi fi
} }
@@ -113,9 +131,7 @@ fi
log_step "1/5" "正在检测 frpc 环境..." log_step "1/5" "正在检测 frpc 环境..."
if ! command -v frpc &>/dev/null && [ ! -f "/usr/local/bin/frpc" ] && [ ! -f "/usr/bin/frpc" ]; then if ! command -v frpc &>/dev/null && [ ! -f "/usr/local/bin/frpc" ] && [ ! -f "/usr/bin/frpc" ]; then
log_warn "未检测到 frpc" log_warn "未检测到 frpc"
INSTALL_FRP=$(read_or_default "是否需要为您自动下载并安装最新版 frpc (使用国内加速镜像)? (y/n, 默认 y): " "y" "INSTALL_FRP") if confirm_or_default "是否需要为您自动下载并安装最新版 frpc (使用国内加速镜像)? (y/n, 默认 y): " "y"; then
if [[ "$INSTALL_FRP" == "y" || "$INSTALL_FRP" == "Y" ]]; then
ARCH=$(uname -m) ARCH=$(uname -m)
case "$ARCH" in case "$ARCH" in
x86_64) FRP_ARCH="amd64" ;; x86_64) FRP_ARCH="amd64" ;;
@@ -201,8 +217,8 @@ fi
# ================= 配置网关与映射端口 ================= # ================= 配置网关与映射端口 =================
log_step "2/5" "配置动态网关参数:" log_step "2/5" "配置动态网关参数:"
GATEWAY_PORT=$(read_or_default "请输入 Python 动态网关的本地监听端口 (默认 8080): " "8080" "GATEWAY_PORT") GATEWAY_PORT="${GATEWAY_PORT:-$(read_or_default "请输入 Python 动态网关的本地监听端口 (默认 8080): " "8080")}"
REMOTE_PORT=$(read_or_default "请输入你想在 frps 公网端暴露的端口 (默认 18000): " "18000" "REMOTE_PORT") REMOTE_PORT="${REMOTE_PORT:-$(read_or_default "请输入你想在 frps 公网端暴露的端口 (默认 18000): " "18000")}"
# 端口有效性检查 # 端口有效性检查
if ! [[ "$GATEWAY_PORT" =~ ^[0-9]+$ ]] || [ "$GATEWAY_PORT" -lt 1 ] || [ "$GATEWAY_PORT" -gt 65535 ]; then if ! [[ "$GATEWAY_PORT" =~ ^[0-9]+$ ]] || [ "$GATEWAY_PORT" -lt 1 ] || [ "$GATEWAY_PORT" -gt 65535 ]; then
@@ -240,7 +256,9 @@ fi
APPEND_FRP="n" APPEND_FRP="n"
if [ -n "$FRPC_CONFIG" ]; then if [ -n "$FRPC_CONFIG" ]; then
log_info "识别到 frpc 配置: $FRPC_CONFIG (${FRPC_TYPE})" log_info "识别到 frpc 配置: $FRPC_CONFIG (${FRPC_TYPE})"
APPEND_FRP=$(read_or_default "是否自动将华为云转发规则追加到该文件? (y/n, 默认 y): " "y" "APPEND_FRP") if confirm_or_default "是否自动将华为云转发规则追加到该文件? (y/n, 默认 y): " "y"; then
APPEND_FRP="y"
fi
else else
log_warn "未找到 frpc 配置文件,跳过自动追加" log_warn "未找到 frpc 配置文件,跳过自动追加"
log_warn "请手动在 frpc 配置中添加以下规则:" log_warn "请手动在 frpc 配置中添加以下规则:"
@@ -292,8 +310,9 @@ fi
USE_VENV=false USE_VENV=false
VENV_PATH="/opt/huawei-gateway/venv" VENV_PATH="/opt/huawei-gateway/venv"
if [ "$IS_CONTAINER" = true ] || [ "$EUID" -eq 0 ]; then if [ "$IS_CONTAINER" = true ] || [ "$EUID" -eq 0 ]; then
USE_VENV_INPUT=$(read_or_default "是否使用虚拟环境安装 Python 依赖? (推荐, y/n, 默认 y): " "y" "USE_VENV") if confirm_or_default "是否使用虚拟环境安装 Python 依赖? (推荐, y/n, 默认 y): " "y"; then
[[ "$USE_VENV_INPUT" == "y" || "$USE_VENV_INPUT" == "Y" ]] && USE_VENV=true USE_VENV=true
fi
fi fi
if [ "$USE_VENV" = true ]; then if [ "$USE_VENV" = true ]; then
@@ -641,7 +660,7 @@ EOF
fi fi
# 启动服务 # 启动服务
safe_start_service "huawei-gateway" "$PYTHON_CMD /usr/local/bin/huawei_gateway.py $GATEWAY_PORT" "/etc/systemd/system/huawei-gateway.service" safe_start_service "huawei-gateway" "$PYTHON_CMD /usr/local/bin/huawei_gateway.py $GATEWAY_PORT"
# ================= 追加 frpc 规则 ================= # ================= 追加 frpc 规则 =================
if [[ "$APPEND_FRP" == "y" || "$APPEND_FRP" == "Y" ]] && [ -n "$FRPC_CONFIG" ] && [ -f "$FRPC_CONFIG" ]; then if [[ "$APPEND_FRP" == "y" || "$APPEND_FRP" == "Y" ]] && [ -n "$FRPC_CONFIG" ] && [ -f "$FRPC_CONFIG" ]; then