[优化] 部署脚本优化

This commit is contained in:
ryan
2026-06-06 11:06:45 +08:00
parent 3cfefb4367
commit 2662c65f57
6 changed files with 577 additions and 228 deletions
+4
View File
@@ -20,12 +20,16 @@ sidebar: false
### 新增
- 新增 Agent 交互式安装向导,支持选择本地安装和 Docker 运行模式;未传参数时自动进入交互菜单
- 新增 Docker 运行模式的智能环境检查,检测到未安装 Docker 时支持一键在线安装,中国大陆环境支持多镜像源自动测速优选与加速器配置
- 新增 Agent 交互式卸载向导,支持选择本地卸载和 Docker 容器卸载模式;未传参数时自动进入交互菜单
- 新增 Pages 静态托管使用指南(`pages-usage.md`),讲解 ZIP 上传、SPA Fallback 与 API 代理配置
- 新增 Uptime Kuma 监控同步集成指南(`uptime-kuma.md`),说明同步参数与专属标签隔离机制
- 完善 WAF IP 组订阅模式使用指南(`waf-usage.md`),补充 JSON 路径提取映射规则与同步参数说明
### 变更
- 重构 `install-agent.sh` 安装脚本与 `uninstall-agent.sh` 卸载脚本以兼容交互式导引、非交互式命令行参数及 Docker 部署/卸载参数(`--docker`/`--method docker`)
- 重构 Go 包依赖结构为统一模块(Monorepo),模块命名为 `github.com/rain-kl/openflare`
- 移除各子目录下独立的 `go.mod`/`go.sum` 文件,统一由根目录 `go.mod` 进行全局依赖管理与依赖版本锁定
- 替换全仓库 Go 源文件中的内部引用路径,由本地相对路径迁移为标准 GitHub 绝对导入路径
+54 -11
View File
@@ -20,7 +20,19 @@ OpenFlare Agent 运行在代理节点侧。它不会接收远程 shell 指令,
## 一键安装
使用 `discovery_token`:
### 交互式安装 (推荐)
如果在不传递任何参数的情况下运行安装脚本,脚本将进入交互模式。您将可以通过向导选择安装方式(本地运行 / Docker 容器运行),并配置 Server 地址与认证 Token(若选择 Docker 方式且本地没有 Docker,脚本还会询问并智能安装 Docker):
```bash
curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/install-agent.sh | bash
```
### 自动化 (非交互式) 安装
如果在执行脚本时附加了任何参数,脚本将进入自动化安装模式,不需要任何交互。
使用 `discovery_token` 进行本地安装:
```bash
curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/install-agent.sh | bash -s -- \
@@ -28,7 +40,7 @@ curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/inst
--discovery-token YOUR_DISCOVERY_TOKEN
```
使用节点专属 `agent_token`:
使用节点专属 `agent_token` 进行本地安装:
```bash
curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/install-agent.sh | bash -s -- \
@@ -36,19 +48,30 @@ curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/inst
--agent-token YOUR_AGENT_TOKEN
```
安装脚本会下载最新 Agent,默认写入 `/opt/openflare-agent`,生成 `agent.json`,并在 Linux + systemd 环境创建 `openflare-agent.service`。
使用 Docker 容器自动化安装:
```bash
curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/install-agent.sh | bash -s -- \
--server-url http://your-server:3000 \
--discovery-token YOUR_DISCOVERY_TOKEN \
--docker
```
安装脚本在本地安装模式下会下载最新 Agent,默认写入 `/opt/openflare-agent`,生成 `agent.json`,并在 Linux + systemd 环境创建 `openflare-agent.service`。
支持参数:
| 参数 | 说明 |
| --- | --- |
| `--server-url` | Server 地址,必填 |
| `--server-url` | Server 地址 |
| `--discovery-token` | 首次自动注册 Token |
| `--agent-token` | 节点专属 Token |
| `--install-dir` | 安装目录,默认 `/opt/openflare-agent` |
| `--openresty-path` | OpenResty 二进制路径,未传时自动查找 `openresty` |
| `--install-dir` | 安装目录,默认 `/opt/openflare-agent`(仅本地安装生效) |
| `--openresty-path` | OpenResty 二进制路径,未传时自动查找 `openresty`(仅本地安装生效) |
| `--repo` | 下载 Agent 的 GitHub 仓库,默认 `Rain-kl/OpenFlare` |
| `--no-service` | 不创建 systemd 服务 |
| `--no-service` | 不创建 systemd 服务(仅本地安装生效) |
| `--docker` | 使用 Docker 容器方式安装 |
| `--method` | 安装方式,可选 `local` 或 `docker`(默认 `local`) |
## 配置文件
@@ -150,20 +173,40 @@ export LOG_LEVEL='info'
## 卸载
如需彻底卸载 Agent 并清空本地数据:
### 交互式卸载 (推荐)
如果在不传递任何参数的情况下运行卸载脚本,脚本将进入交互模式。您可以通过提示菜单选择卸载方式(本地卸载 / Docker 容器卸载):
```bash
curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/uninstall-agent.sh | bash
```
### 自动化 (非交互式) 卸载
使用命令行传参进行无人值守卸载。
本地卸载(默认):
```bash
curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/uninstall-agent.sh | bash -s -- --install-dir /opt/openflare-agent
```
Docker 容器卸载:
```bash
curl -fsSL https://raw.githubusercontent.com/Rain-kl/OpenFlare/main/scripts/uninstall-agent.sh | bash -s -- --docker
```
支持参数:
| 参数 | 说明 |
| --- | --- |
| `--install-dir` | 安装目录,默认 `/opt/openflare-agent` |
| `--service-name` | systemd 服务名,默认 `openflare-agent` |
| `--install-dir` | 安装目录,默认 `/opt/openflare-agent`(仅本地卸载生效) |
| `--service-name` | systemd 服务名,默认 `openflare-agent`(仅本地卸载生效) |
| `--docker` | 使用 Docker 容器方式卸载 |
| `--method` | 卸载方式,可选 `local` 或 `docker`(默认 `local`) |
卸载脚本只移除 Agent 服务、进程和安装目录,不会删除本机 OpenResty。
本地卸载只会移除 Agent 服务、进程和安装目录,不会删除本机 OpenResty。Docker 卸载会停止并删除 `openflare-agent` 容器,交互模式下还可以选择是否清理对应的 Docker 镜像。
## 常见问题
@@ -0,0 +1,85 @@
# 交互式智能安装脚本实现计划
本计划旨在拓展 OpenFlare Agent 安装脚本的功能,支持交互式选择本地安装或 Docker 容器安装,并提供智能检测/在线安装 Docker 环境的机制,同时保留通过命令行传参进行自动化安装的既有能力。
---
## 1. 目标与背景 (Goal & Context)
* **需求背景**:当前安装脚本 `install-agent.sh` 仅支持在宿主机直接下载二进制并配置为本地 systemd 服务运行。随着 Docker 部署方式的普及,需要让用户在一键安装时能根据需要交互式选择 Docker 或本地部署,从而提升部署体验。
* **开发范围 (Scope)**:
* 支持交互式运行(未传参时):提示用户选择 Local 方式或 Docker 方式。
* 当选择 Docker 方式时,检测本地是否存在 `docker` 命令。若不存在,提示并在线安装 Docker(支持国内镜像源及自动测速选择最低延迟源)。
* 交互引导用户配置 `server_url` 和 `agent-token` 或 `discovery-token`。
* 如果选择 Docker,则最终拉取 Agent 镜像并运行容器;如果选择 Local,则继续原有的本地二进制下载及配置发布逻辑。
* 兼容非交互式模式:如果执行脚本时传递了任意参数,则跳过任何交互式提示,直接进行自动化安装(支持新参数 `--docker` / `--method docker` 来自动选用 Docker 部署)。
---
## 2. 设计与决策 (Design & Decisions)
### 交互工作流
1. 检查 `$#`(参数数量)。若 `$# -eq 0`,激活 `INTERACTIVE=true`。
2. 在交互模式下:
* 引导用户选择安装方法(1: Local, 2: Docker)。
* 若选择 Docker,调用 `Install_Docker` 检测并安装环境。
* 引导用户输入 `SERVER_URL` 并进行非空校验。
* 引导用户选择 Token 类型(1: Discovery Token, 2: Agent Token),并输入对应的 Token 值。
* 若选择 Local 且未传 `--openresty-path`,如果 `openresty` 二进制未能在 $PATH 中找到,交互提示用户手动输入 OpenResty 路径。
3. 非交互模式下:
* 解析命令行参数。
* 支持通过 `--docker` 或 `--method docker` 指定 Docker 容器安装。
* 依然根据传入的 `--server-url` 和 Token 自动执行安装,绝不进行任何交互。
### 数据流与架构图
```mermaid
graph TD
Start[执行 install-agent.sh] --> CheckArgs{是否有命令行参数?}
CheckArgs -- 是 (非交互模式) --> ParseArgs[解析参数]
ParseArgs --> IsDockerParam{是否指定 Docker?}
IsDockerParam -- 是 --> RunDocker[Docker 容器拉取与启动]
IsDockerParam -- 否 --> RunLocal[本地二进制下载与 systemd 服务创建]
CheckArgs -- 否 (交互模式) --> PromptMethod[提示选择 Local 或 Docker]
PromptMethod --> MethodChosen{选择结果}
MethodChosen -- Docker --> CheckDocker{本地有 Docker 吗?}
CheckDocker -- 否 --> PromptDockerInstall[询问是否安装 Docker?]
PromptDockerInstall -- 是 --> InstallDocker[在线安装 Docker + 配置国内镜像加速]
PromptDockerInstall -- 否 --> ExitScript[取消安装并退出]
CheckDocker -- 是 --> PromptServerUrl[提示输入 Server URL & Token]
InstallDocker --> PromptServerUrl
MethodChosen -- Local --> PromptLocalConfig[检测 OpenResty 并提示输入 Server URL & Token]
PromptServerUrl --> RunDocker
PromptLocalConfig --> RunLocal
```
---
## 3. 具体修改文件清单 (Proposed Changes)
### 边缘 Agent 与部署脚本
* #### [MODIFY] [install-agent.sh](file:///Users/ryan/DEV/Go/OpenFlare/scripts/install-agent.sh)
* 职责:
1. 引入交互式选择逻辑和 `Install_Docker` / `configure_accelerator` 函数。
2. 新增 `--docker` 和 `--method` 命令行参数支持。
3. 支持用户交互输入配置项。
4. 增加 Docker 镜像拉取、停止旧容器并启动新容器的安装路径。
* #### [MODIFY] [agent.md](file:///Users/ryan/DEV/Go/OpenFlare/docs/deployment/agent.md)
* 职责:更新一键安装说明文档,增加交互式模式的说明以及 `--docker` 参数的自动化 Docker 安装说明。
---
## 4. 验证计划 (Verification Plan)
### 自动化与脚本测试
* 在干净的测试环境运行脚本:
* `bash scripts/install-agent.sh` (测试交互模式 -> 选用 Local)
* `bash scripts/install-agent.sh` (测试交互模式 -> 选用 Docker)
* `bash scripts/install-agent.sh --server-url http://127.0.0.1:3000 --discovery-token mytoken` (测试自动 Local 安装)
* `bash scripts/install-agent.sh --server-url http://127.0.0.1:3000 --discovery-token mytoken --docker` (测试自动 Docker 安装)
### 数据面生效验证
* 通过 `docker ps` 和 `docker logs openflare-agent` 确认容器成功拉取并启动,环境参数注入正确。
+358 -23
View File
@@ -15,6 +15,252 @@ AGENT_TOKEN=""
CREATE_SERVICE="true"
SERVICE_NAME="openflare-agent"
OPENRESTY_PATH=""
INSTALL_METHOD=""
CURRENT_DIR="$(pwd)"
LOG_FILE="${CURRENT_DIR}/install.log"
# Translation text variables
TXT_DOCKER_RESTARTED="Docker 已启动/重启并运行中"
TXT_LOW_DOCKER_VERSION="Docker 版本较低,建议升级到 20.10 及以上版本"
TXT_INSTALL_DOCKER_CONFIRM="未检测到 Docker,是否现在安装?(y/n) [y]: "
TXT_DOCKER_INSTALL_ONLINE="开始在线安装 Docker..."
TXT_INSTALL_DOCKER_ONLINE="使用 opkg 在线安装 Docker..."
TXT_CHOOSE_LOWEST_LATENCY_SOURCE="选择延迟最低的镜像源:"
TXT_CHOOSE_LOWEST_LATENCY_DELAY="延迟为:"
TXT_TRY_NEXT_LINK="尝试使用链接:"
TXT_DOWNLOAD_DOCKER_SCRIPT="下载 Docker 安装脚本..."
TXT_DOWNLOAD_DOCKER_SCRIPT_SUCCESS="下载成功:"
TXT_SUCCESSFULLY_MESSAGE="开始执行安装..."
TXT_DOWNLOAD_FAIELD="下载失败:"
TXT_ALL_DOWNLOAD_ATTEMPTS_FAILED="所有 Docker 下载尝试均失败,请手动安装 Docker"
TXT_DOCKER_INSTALL_FAIL="Docker 安装失败"
TXT_DOCKER_INSTALL_SUCCESS="Docker 安装成功"
TXT_CANNOT_SELECT_SOURCE="无法选择合适的镜像源"
TXT_REGIONS_OTHER_THAN_CHINA="检测到非中国大陆地区,使用官方源安装 Docker..."
TXT_DOCKER_START_NOTICE="正在启动 Docker 服务..."
TXT_CANCEL_INSTALL_DOCKER="已取消 Docker 安装"
TXT_INVALID_YN_INPUT="无效的输入,请输入 y 或 n"
log() {
echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
configure_accelerator() {
log "配置 Docker 国内镜像加速源..."
local docker_config_folder="/etc/docker"
if [[ ! -d "$docker_config_folder" ]]; then
mkdir -p "$docker_config_folder"
fi
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
EOF
if command -v systemctl &>/dev/null; then
systemctl daemon-reload
systemctl restart docker
else
service dockerd restart
fi
}
function Install_Docker(){
if which docker >/dev/null 2>&1; then
docker_version=$(docker --version | grep -oE '[0-9]+\.[0-9]+' | head -n 1)
major_version=${docker_version%%.*}
minor_version=${docker_version##*.}
local service_cmd="service dockerd start && service dockerd status"
if command -v systemctl &>/dev/null; then
service_cmd="systemctl start docker && systemctl status docker"
fi
set +e
local service_status=$($service_cmd 2>&1)
set -e
if [[ $service_status == *running* ]]; then
log "$TXT_DOCKER_RESTARTED"
else
if [[ $major_version -lt 20 ]]; then
log "$TXT_LOW_DOCKER_VERSION"
fi
set +e
local country_code=$(curl -s --max-time 5 ipinfo.io/country)
set -e
if [[ "$country_code" == "CN" ]]; then
configure_accelerator
fi
fi
else
while true; do
read -p "$TXT_INSTALL_DOCKER_CONFIRM" install_docker_choice
install_docker_choice=${install_docker_choice:-y}
case "$install_docker_choice" in
[yY])
log "$TXT_DOCKER_INSTALL_ONLINE"
if command -v opkg &>/dev/null; then
log "$TXT_INSTALL_DOCKER_ONLINE"
opkg update
opkg install luci-i18n-dockerman-zh-cn
opkg install zoneinfo-asia
service system restart
set +e
local country_code=$(curl -s --max-time 5 ipinfo.io/country)
set -e
if [[ "$country_code" == "CN" ]]; then
configure_accelerator
fi
else
set +e
local country_code=$(curl -s --max-time 5 ipinfo.io/country)
set -e
if [[ "$country_code" == "CN" ]]; then
sources=(
"https://mirrors.aliyun.com/docker-ce"
"https://mirrors.tencent.com/docker-ce"
"https://mirrors.163.com/docker-ce"
"https://mirrors.cernet.edu.cn/docker-ce"
)
docker_install_scripts=(
"https://get.docker.com"
"https://testingcf.jsdelivr.net/gh/docker/docker-install@master/install.sh"
"https://cdn.jsdelivr.net/gh/docker/docker-install@master/install.sh"
"https://fastly.jsdelivr.net/gh/docker/docker-install@master/install.sh"
"https://gcore.jsdelivr.net/gh/docker/docker-install@master/install.sh"
"https://raw.githubusercontent.com/docker/docker-install/master/install.sh"
)
get_average_delay() {
local source=$1
local total_delay=0
local iterations=2
local timeout=2
for ((i = 0; i < iterations; i++)); do
delay=$(curl -o /dev/null -s -m $timeout -w "%{time_total}\n" "$source")
if [ $? -ne 0 ]; then
delay=$timeout
fi
total_delay=$(awk "BEGIN {print $total_delay + $delay}")
done
average_delay=$(awk "BEGIN {print $total_delay / $iterations}")
echo "$average_delay"
}
min_delay=99999999
selected_source=""
for source in "${sources[@]}"; do
average_delay=$(get_average_delay "$source" &)
if (( $(awk 'BEGIN { print '"$average_delay"' < '"$min_delay"' }') )); then
min_delay=$average_delay
selected_source=$source
fi
done
wait
if [ -n "$selected_source" ]; then
log "$TXT_CHOOSE_LOWEST_LATENCY_SOURCE $selected_source,$TXT_CHOOSE_LOWEST_LATENCY_DELAY $min_delay"
export DOWNLOAD_URL="$selected_source"
for alt_source in "${docker_install_scripts[@]}"; do
log "$TXT_TRY_NEXT_LINK $alt_source $TXT_DOWNLOAD_DOCKER_SCRIPT"
if curl -fsSL --retry 2 --retry-delay 3 --connect-timeout 5 --max-time 10 "$alt_source" -o get-docker.sh; then
log "$TXT_DOWNLOAD_DOCKER_SCRIPT_SUCCESS $alt_source $TXT_SUCCESSFULLY_MESSAGE"
break
else
log "$TXT_DOWNLOAD_FAIELD $alt_source $TXT_TRY_NEXT_LINK"
fi
done
if [ ! -f "get-docker.sh" ]; then
log "$TXT_ALL_DOWNLOAD_ATTEMPTS_FAILED"
log "bash <(curl -sSL https://linuxmirrors.cn/docker.sh)"
exit 1
fi
sh get-docker.sh 2>&1 | tee -a "${CURRENT_DIR}/install.log"
docker_config_folder="/etc/docker"
if [[ ! -d "$docker_config_folder" ]]; then
mkdir -p "$docker_config_folder"
fi
set +e
docker version >/dev/null 2>&1
local docker_ver_res=$?
set -e
if [[ $docker_ver_res -ne 0 ]]; then
log "$TXT_DOCKER_INSTALL_FAIL"
exit 1
else
log "$TXT_DOCKER_INSTALL_SUCCESS"
if command -v systemctl &>/dev/null; then
systemctl enable docker 2>&1 | tee -a "${LOG_FILE}"
fi
configure_accelerator
fi
else
log "$TXT_CANNOT_SELECT_SOURCE"
exit 1
fi
else
log "$TXT_REGIONS_OTHER_THAN_CHINA"
export DOWNLOAD_URL="https://download.docker.com"
curl -fsSL "https://get.docker.com" -o get-docker.sh
sh get-docker.sh 2>&1 | tee -a "${LOG_FILE}"
log "$TXT_DOCKER_START_NOTICE"
if command -v systemctl &>/dev/null; then
systemctl enable docker; systemctl daemon-reload; systemctl start docker 2>&1 | tee -a "${LOG_FILE}"
else
service dockerd start 2>&1 | tee -a "${LOG_FILE}"
sleep 1
fi
docker_config_folder="/etc/docker"
if [[ ! -d "$docker_config_folder" ]]; then
mkdir -p "$docker_config_folder"
fi
set +e
docker version >/dev/null 2>&1
local docker_ver_res=$?
set -e
if [[ $docker_ver_res -ne 0 ]]; then
log "$TXT_DOCKER_INSTALL_FAIL"
exit 1
else
log "$TXT_DOCKER_INSTALL_SUCCESS"
fi
fi
fi
break
;;
[nN])
echo "$TXT_CANCEL_INSTALL_DOCKER"
exit 1
;;
*)
log "$TXT_INVALID_YN_INPUT"
continue
;;
esac
done
fi
}
usage() {
cat <<EOF
@@ -24,29 +270,35 @@ Usage:
install-agent.sh [OPTIONS]
Options:
--server-url URL Server URL (required)
--server-url URL Server URL
--discovery-token TOKEN Discovery token for auto-registration
--agent-token TOKEN Node-specific agent token
--install-dir DIR Installation directory (default: /opt/openflare-agent)
--openresty-path PATH OpenResty binary path (default: auto-detect from PATH)
--repo REPO GitHub repository (default: Rain-kl/OpenFlare)
--no-service Do not create systemd service
--docker Install via Docker container
--method METHOD Installation method: 'local' or 'docker' (default: local)
-h, --help Show this help message
Examples:
# Install with discovery token (auto-register)
# Interactive installation (prompts for options)
install-agent.sh
# Automated local installation
install-agent.sh --server-url http://10.0.0.1:3000 --discovery-token abc123
# Install with node-specific token
install-agent.sh --server-url http://10.0.0.1:3000 --agent-token node-token-xyz
Notes:
Reinstall will remove the entire install directory before installing again,
including the old agent.json, local state, cached data, and downloaded binary.
# Automated Docker installation
install-agent.sh --server-url http://10.0.0.1:3000 --discovery-token abc123 --docker
EOF
exit 0
}
HAS_ARGS="false"
if [[ $# -gt 0 ]]; then
HAS_ARGS="true"
fi
while [[ $# -gt 0 ]]; do
case "$1" in
--server-url) SERVER_URL="$2"; shift 2 ;;
@@ -56,19 +308,111 @@ while [[ $# -gt 0 ]]; do
--openresty-path) OPENRESTY_PATH="$2"; shift 2 ;;
--repo) REPO="$2"; shift 2 ;;
--no-service) CREATE_SERVICE="false"; shift ;;
--docker) INSTALL_METHOD="docker"; shift ;;
--method) INSTALL_METHOD="$2"; shift 2 ;;
-h|--help) usage ;;
*) echo "Unknown option: $1"; exit 1 ;;
esac
done
if [[ -z "$SERVER_URL" ]]; then
echo "Error: --server-url is required"
exit 1
if [[ "$HAS_ARGS" == "false" ]]; then
echo "=================================================="
echo "欢迎使用 OpenFlare Agent 安装脚本"
echo "Welcome to the OpenFlare Agent Installer"
echo "=================================================="
echo "请选择安装方式 / Please choose installation method:"
echo " 1) Local (本地安装: 下载二进制运行,需要本地有 OpenResty)"
echo " 2) Docker (容器安装: 运行内置 OpenResty 的 Agent 容器)"
read -p "请输入序号 [1-2] (默认 1): " method_choice
method_choice=${method_choice:-1}
case "$method_choice" in
2) INSTALL_METHOD="docker" ;;
*) INSTALL_METHOD="local" ;;
esac
if [[ "$INSTALL_METHOD" == "docker" ]]; then
Install_Docker
fi
# Prompt for Server URL
while [[ -z "$SERVER_URL" ]]; do
read -p "请输入 OpenFlare Server 地址 (例如 http://127.0.0.1:3000): " SERVER_URL
done
# Prompt for Token
while [[ -z "$DISCOVERY_TOKEN" && -z "$AGENT_TOKEN" ]]; do
echo "请选择认证 Token 类型 / Please choose token type:"
echo " 1) Discovery Token (自动注册凭证 - 适合新节点上线)"
echo " 2) Agent Token (专属接入凭证 - 适合预创建节点)"
read -p "请输入序号 [1-2] (默认 1): " token_type_choice
token_type_choice=${token_type_choice:-1}
if [[ "$token_type_choice" == "2" ]]; then
read -p "请输入 Agent Token: " AGENT_TOKEN
else
read -p "请输入 Discovery Token: " DISCOVERY_TOKEN
fi
done
else
# Non-interactive mode validation
if [[ -z "$INSTALL_METHOD" ]]; then
INSTALL_METHOD="local"
fi
if [[ -z "$SERVER_URL" ]]; then
echo "Error: --server-url is required"
exit 1
fi
if [[ -z "$DISCOVERY_TOKEN" && -z "$AGENT_TOKEN" ]]; then
echo "Error: either --discovery-token or --agent-token is required"
exit 1
fi
fi
if [[ -z "$DISCOVERY_TOKEN" && -z "$AGENT_TOKEN" ]]; then
echo "Error: either --discovery-token or --agent-token is required"
exit 1
# Run Docker container installation if Docker method selected
if [[ "$INSTALL_METHOD" == "docker" ]]; then
echo "拉取最新的 OpenFlare Agent 镜像..."
docker pull ghcr.io/rain-kl/openflare-agent:latest
echo "停止并移除旧的 openflare-agent 容器 (如果存在)..."
docker rm -f openflare-agent 2>/dev/null || true
echo "启动 openflare-agent 容器..."
if [[ -n "$AGENT_TOKEN" ]]; then
docker run -d --name openflare-agent --restart unless-stopped \
-p 80:80 -p 443:443/tcp -p 443:443/udp \
-e OPENFLARE_SERVER_URL="${SERVER_URL}" \
-e OPENFLARE_AGENT_TOKEN="${AGENT_TOKEN}" \
ghcr.io/rain-kl/openflare-agent:latest
else
docker run -d --name openflare-agent --restart unless-stopped \
-p 80:80 -p 443:443/tcp -p 443:443/udp \
-e OPENFLARE_SERVER_URL="${SERVER_URL}" \
-e OPENFLARE_DISCOVERY_TOKEN="${DISCOVERY_TOKEN}" \
ghcr.io/rain-kl/openflare-agent:latest
fi
echo ""
echo "OpenFlare Agent (Docker) 安装成功!"
echo "您可以执行以下命令查看运行日志:"
echo " docker logs -f openflare-agent"
exit 0
fi
# Local installation starts below
if [[ -z "$OPENRESTY_PATH" ]]; then
if command -v openresty >/dev/null 2>&1; then
OPENRESTY_PATH="$(command -v openresty)"
elif [[ "$HAS_ARGS" == "false" ]]; then
read -p "未在 PATH 中检测到 openresty,请输入 OpenResty 二进制路径: " OPENRESTY_PATH
if [[ -z "$OPENRESTY_PATH" ]]; then
echo "Error: OpenResty binary path is required for local installation."
exit 1
fi
else
echo "Error: openresty was not found in PATH. Install OpenResty first or pass --openresty-path."
exit 1
fi
fi
# Detect platform
@@ -85,15 +429,6 @@ if [[ "$OS" != "linux" && "$OS" != "darwin" ]]; then
exit 1
fi
if [[ -z "$OPENRESTY_PATH" ]]; then
if command -v openresty >/dev/null 2>&1; then
OPENRESTY_PATH="$(command -v openresty)"
else
echo "Error: openresty was not found in PATH. Install OpenResty first or pass --openresty-path."
exit 1
fi
fi
if [[ ! -x "$OPENRESTY_PATH" ]]; then
echo "Error: OpenResty binary is not executable: ${OPENRESTY_PATH}"
exit 1
-192
View File
@@ -1,192 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
INSTALL_DIR="/opt/openflare-agent"
SERVICE_NAME="openflare-agent"
usage() {
cat <<EOF
OpenFlare Agent Uninstaller
Usage:
uninstall-agent.sh [OPTIONS]
Options:
--install-dir DIR Installation directory (default: /opt/openflare-agent)
--service-name NAME systemd service name (default: openflare-agent)
-h, --help Show this help message
Behavior:
1. Stop the agent service/process and remove the entire installation directory
2. Remove the systemd service definition when present
3. Check the saved agent config to identify the OpenResty mode
4. If Docker mode was used, remove the OpenResty container and try to remove its image
5. If local openresty_path mode was used, do not modify the local OpenResty install
Examples:
uninstall-agent.sh
uninstall-agent.sh --install-dir /srv/openflare-agent
EOF
exit 0
}
while [[ $# -gt 0 ]]; do
case "$1" in
--install-dir) INSTALL_DIR="$2"; shift 2 ;;
--service-name) SERVICE_NAME="$2"; shift 2 ;;
-h|--help) usage ;;
*) echo "Unknown option: $1"; exit 1 ;;
esac
done
if [[ -z "$INSTALL_DIR" || "$INSTALL_DIR" == "/" || "$INSTALL_DIR" == "." ]]; then
echo "Refusing to remove unsafe install directory: '${INSTALL_DIR}'"
exit 1
fi
json_get_string() {
local file="$1"
local key="$2"
local match
match=$(grep -o "\"${key}\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" "$file" 2>/dev/null | head -n 1 || true)
if [[ -z "$match" ]]; then
return 0
fi
printf '%s\n' "$match" | sed -E 's/.*:[[:space:]]*"([^"]*)"/\1/'
}
AGENT_BINARY="${INSTALL_DIR}/openflare-agent"
CONFIG_FILE="${INSTALL_DIR}/agent.json"
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
OPENRESTY_PATH=""
OPENRESTY_CONTAINER_NAME="openflare-openresty"
OPENRESTY_DOCKER_IMAGE="openresty/openresty:alpine"
DOCKER_BINARY="docker"
OPENRESTY_MODE="unknown"
if [[ -f "$CONFIG_FILE" ]]; then
OPENRESTY_PATH="$(json_get_string "$CONFIG_FILE" "openresty_path")"
OPENRESTY_CONTAINER_NAME="$(json_get_string "$CONFIG_FILE" "openresty_container_name")"
OPENRESTY_DOCKER_IMAGE="$(json_get_string "$CONFIG_FILE" "openresty_docker_image")"
DOCKER_BINARY="$(json_get_string "$CONFIG_FILE" "docker_binary")"
if [[ -z "$OPENRESTY_CONTAINER_NAME" ]]; then
OPENRESTY_CONTAINER_NAME="openflare-openresty"
fi
if [[ -z "$OPENRESTY_DOCKER_IMAGE" ]]; then
OPENRESTY_DOCKER_IMAGE="openresty/openresty:alpine"
fi
if [[ -z "$DOCKER_BINARY" ]]; then
DOCKER_BINARY="docker"
fi
if [[ -n "$OPENRESTY_PATH" ]]; then
OPENRESTY_MODE="local"
else
OPENRESTY_MODE="docker"
fi
fi
SYSTEMCTL_AVAILABLE="false"
if command -v systemctl >/dev/null 2>&1; then
SYSTEMCTL_AVAILABLE="true"
fi
echo "Uninstalling OpenFlare Agent from ${INSTALL_DIR}..."
if [[ "$SYSTEMCTL_AVAILABLE" == "true" ]]; then
if systemctl is-active --quiet "$SERVICE_NAME"; then
echo "Stopping service: ${SERVICE_NAME}"
systemctl stop "$SERVICE_NAME"
fi
if systemctl is-enabled --quiet "$SERVICE_NAME" >/dev/null 2>&1; then
echo "Disabling service: ${SERVICE_NAME}"
systemctl disable "$SERVICE_NAME" >/dev/null 2>&1 || true
fi
fi
if command -v pgrep >/dev/null 2>&1; then
mapfile -t agent_pids < <(pgrep -f "$AGENT_BINARY" || true)
if (( ${#agent_pids[@]} > 0 )); then
echo "Stopping agent process: ${agent_pids[*]}"
kill "${agent_pids[@]}" || true
sleep 1
mapfile -t remaining_agent_pids < <(pgrep -f "$AGENT_BINARY" || true)
if (( ${#remaining_agent_pids[@]} > 0 )); then
echo "Force stopping remaining agent process: ${remaining_agent_pids[*]}"
kill -9 "${remaining_agent_pids[@]}" || true
fi
fi
fi
if [[ -f "$SERVICE_FILE" ]]; then
echo "Removing service file: ${SERVICE_FILE}"
rm -f "$SERVICE_FILE"
fi
if [[ "$SYSTEMCTL_AVAILABLE" == "true" ]]; then
systemctl daemon-reload || true
systemctl reset-failed "$SERVICE_NAME" >/dev/null 2>&1 || true
fi
if [[ -d "$INSTALL_DIR" ]]; then
echo "Removing installation directory: ${INSTALL_DIR}"
rm -rf "$INSTALL_DIR"
else
echo "Installation directory not found, skipping: ${INSTALL_DIR}"
fi
echo "Agent uninstall complete."
echo ""
echo "Checking OpenResty installation mode..."
if [[ "$OPENRESTY_MODE" == "docker" ]]; then
echo "Detected Docker OpenResty mode."
if ! command -v "$DOCKER_BINARY" >/dev/null 2>&1; then
echo "Docker binary '${DOCKER_BINARY}' was not found."
echo "Please remove container '${OPENRESTY_CONTAINER_NAME}' and image '${OPENRESTY_DOCKER_IMAGE}' manually."
exit 0
fi
if "$DOCKER_BINARY" inspect "$OPENRESTY_CONTAINER_NAME" >/dev/null 2>&1; then
if [[ -z "$OPENRESTY_DOCKER_IMAGE" ]]; then
OPENRESTY_DOCKER_IMAGE="$("$DOCKER_BINARY" inspect -f '{{.Config.Image}}' "$OPENRESTY_CONTAINER_NAME" 2>/dev/null || true)"
fi
echo "Removing Docker container: ${OPENRESTY_CONTAINER_NAME}"
"$DOCKER_BINARY" rm -f "$OPENRESTY_CONTAINER_NAME"
else
echo "Docker container not found, skipping: ${OPENRESTY_CONTAINER_NAME}"
fi
if [[ -n "$OPENRESTY_DOCKER_IMAGE" ]] && "$DOCKER_BINARY" image inspect "$OPENRESTY_DOCKER_IMAGE" >/dev/null 2>&1; then
other_container_ids="$("$DOCKER_BINARY" ps -a --filter "ancestor=${OPENRESTY_DOCKER_IMAGE}" --format '{{.ID}}' 2>/dev/null || true)"
if [[ -z "$other_container_ids" ]]; then
echo "Removing Docker image: ${OPENRESTY_DOCKER_IMAGE}"
if ! "$DOCKER_BINARY" image rm "$OPENRESTY_DOCKER_IMAGE"; then
echo "Image removal skipped because Docker reported it is still in use."
fi
else
echo "Docker image is still used by other containers, skipping image removal: ${OPENRESTY_DOCKER_IMAGE}"
fi
fi
echo "Docker OpenResty cleanup complete."
elif [[ "$OPENRESTY_MODE" == "local" ]]; then
echo "Detected local OpenResty mode via openresty_path:"
echo " ${OPENRESTY_PATH}"
echo "Agent has been removed, but the local OpenResty installation was not modified."
echo "Please uninstall the local OpenResty manually if you no longer need it."
else
echo "OpenResty mode could not be determined because ${CONFIG_FILE} was not found before uninstall."
echo "If you were using Docker OpenResty, please remove its container and image manually if needed."
fi
echo ""
echo "OpenFlare Agent uninstall finished."
+76 -2
View File
@@ -3,6 +3,7 @@ set -euo pipefail
INSTALL_DIR="/opt/openflare-agent"
SERVICE_NAME="openflare-agent"
INSTALL_METHOD=""
usage() {
cat <<EOF
@@ -14,29 +15,102 @@ Usage:
Options:
--install-dir DIR Installation directory (default: /opt/openflare-agent)
--service-name NAME systemd service name (default: openflare-agent)
--docker Uninstall Docker container agent
--method METHOD Uninstall method: 'local' or 'docker' (default: local)
-h, --help Show this help message
Behavior:
1. Stop the agent service/process and remove the entire installation directory
2. Remove the systemd service definition when present
3. Leave the local OpenResty installation untouched
3. Uninstall Docker container when --docker is specified
4. Leave the local OpenResty installation untouched
Examples:
# Interactive uninstall (prompts for options)
uninstall-agent.sh
uninstall-agent.sh --install-dir /srv/openflare-agent
# Automated local uninstall
uninstall-agent.sh --install-dir /opt/openflare-agent
# Automated Docker uninstall
uninstall-agent.sh --docker
EOF
exit 0
}
HAS_ARGS="false"
if [[ $# -gt 0 ]]; then
HAS_ARGS="true"
fi
while [[ $# -gt 0 ]]; do
case "$1" in
--install-dir) INSTALL_DIR="$2"; shift 2 ;;
--service-name) SERVICE_NAME="$2"; shift 2 ;;
--docker) INSTALL_METHOD="docker"; shift ;;
--method) INSTALL_METHOD="$2"; shift 2 ;;
-h|--help) usage ;;
*) echo "Unknown option: $1"; exit 1 ;;
esac
done
if [[ "$HAS_ARGS" == "false" ]]; then
echo "=================================================="
echo "欢迎使用 OpenFlare Agent 卸载脚本"
echo "Welcome to the OpenFlare Agent Uninstaller"
echo "=================================================="
echo "请选择卸载方式 / Please choose uninstall method:"
echo " 1) Local (本地卸载: 停止服务并删除二进制及配置)"
echo " 2) Docker (容器卸载: 停止并删除 Docker 容器)"
read -p "请输入序号 [1-2] (默认 1): " method_choice
method_choice=${method_choice:-1}
case "$method_choice" in
2) INSTALL_METHOD="docker" ;;
*) INSTALL_METHOD="local" ;;
esac
else
if [[ -z "$INSTALL_METHOD" ]]; then
INSTALL_METHOD="local"
fi
fi
if [[ "$INSTALL_METHOD" == "docker" ]]; then
echo "正在卸载 OpenFlare Agent (Docker)..."
# Check if container exists
if command -v docker >/dev/null 2>&1; then
if docker ps -a --format '{{.Names}}' | grep -Eq "^openflare-agent$"; then
echo "停止并移除 openflare-agent 容器..."
docker stop openflare-agent || true
docker rm -f openflare-agent || true
echo "已成功移除 openflare-agent 容器。"
else
echo "未检测到 openflare-agent 容器。"
fi
# In interactive mode, ask if user wants to remove docker image
if [[ "$HAS_ARGS" == "false" ]]; then
read -p "是否删除 OpenFlare Agent 镜像 (ghcr.io/rain-kl/openflare-agent:latest)? (y/n) [n]: " remove_image_choice
remove_image_choice=${remove_image_choice:-n}
case "$remove_image_choice" in
[yY])
echo "正在删除 Docker 镜像..."
docker rmi ghcr.io/rain-kl/openflare-agent:latest || true
;;
*)
echo "保留 Docker 镜像。"
;;
esac
fi
else
echo "Error: 未检测到 Docker 运行环境,无法进行 Docker 方式的卸载。"
exit 1
fi
echo "OpenFlare Agent (Docker) 卸载完成。"
exit 0
fi
if [[ -z "$INSTALL_DIR" || "$INSTALL_DIR" == "/" || "$INSTALL_DIR" == "." ]]; then
echo "Refusing to remove unsafe install directory: '${INSTALL_DIR}'"
exit 1