重新设计新的部署逻辑,去掉本机自己的go build,合并到docker多阶段构建部分进行

This commit is contained in:
2026-07-28 22:23:39 +08:00
parent 76ac9503c6
commit 00f2b9fd14
+32 -158
View File
@@ -1,9 +1,9 @@
#!/bin/bash #!/bin/bash
# ============================================================ # ============================================================
# frpc-console 一键部署脚本 # frpc-console 一键部署脚本Docker 优先)
# 支持:Linux x86_64 / ARM64 / ARMv7 # 支持:Linux x86_64 / ARM64 / ARMv7
# 自动安装:git / curl / wget / Go / Docker # 自动安装:git / curl / wget / Docker
# #
# 用法: # 用法:
# ./deploy.sh # 完整交互流程 # ./deploy.sh # 完整交互流程
@@ -40,22 +40,18 @@ WORK_DIR="/tmp/frpc-console-build"
DEFAULT_PORT=9300 DEFAULT_PORT=9300
DEFAULT_DEPLOY_DIR="/opt/frpc-console" DEFAULT_DEPLOY_DIR="/opt/frpc-console"
IMAGE_NAME="frpc-console" IMAGE_NAME="frpc-console"
GO_VERSION="1.25.0"
# ---------- 状态变量 ---------- # ---------- 状态变量 ----------
OS="" OS=""
OS_VERSION="" OS_VERSION=""
ARCH="" ARCH=""
GO_ARCH=""
HAS_GIT=false HAS_GIT=false
HAS_CURL=false HAS_CURL=false
HAS_WGET=false HAS_WGET=false
HAS_GO=false
HAS_DOCKER=false HAS_DOCKER=false
NEED_INSTALL_GIT=false NEED_INSTALL_GIT=false
NEED_INSTALL_CURL=false NEED_INSTALL_CURL=false
NEED_INSTALL_WGET=false NEED_INSTALL_WGET=false
NEED_INSTALL_GO=false
PORT=${DEFAULT_PORT} PORT=${DEFAULT_PORT}
DEPLOY_DIR=${DEFAULT_DEPLOY_DIR} DEPLOY_DIR=${DEFAULT_DEPLOY_DIR}
DATA_DIR="${DEPLOY_DIR}/data" DATA_DIR="${DEPLOY_DIR}/data"
@@ -136,14 +132,8 @@ detect_os() {
detect_arch() { detect_arch() {
ARCH=$(uname -m) ARCH=$(uname -m)
case $ARCH in case $ARCH in
x86_64|amd64) x86_64|amd64|aarch64|arm64|armv7l|armhf)
GO_ARCH="amd64" print_success "CPU 架构: $ARCH"
;;
aarch64|arm64)
GO_ARCH="arm64"
;;
armv7l|armhf)
GO_ARCH="armv6l"
;; ;;
*) *)
print_error "不支持的 CPU 架构: $ARCH" print_error "不支持的 CPU 架构: $ARCH"
@@ -154,33 +144,10 @@ detect_arch() {
# ---------- 检测工具 ---------- # ---------- 检测工具 ----------
check_tools() { check_tools() {
if command -v git &> /dev/null; then command -v git &> /dev/null && HAS_GIT=true || NEED_INSTALL_GIT=true
HAS_GIT=true command -v curl &> /dev/null && HAS_CURL=true || NEED_INSTALL_CURL=true
else command -v wget &> /dev/null && HAS_WGET=true || NEED_INSTALL_WGET=true
NEED_INSTALL_GIT=true command -v docker &> /dev/null && HAS_DOCKER=true
fi
if command -v curl &> /dev/null; then
HAS_CURL=true
else
NEED_INSTALL_CURL=true
fi
if command -v wget &> /dev/null; then
HAS_WGET=true
else
NEED_INSTALL_WGET=true
fi
if command -v go &> /dev/null; then
HAS_GO=true
else
NEED_INSTALL_GO=true
fi
if command -v docker &> /dev/null; then
HAS_DOCKER=true
fi
} }
# ---------- 检查容器状态 ---------- # ---------- 检查容器状态 ----------
@@ -200,7 +167,7 @@ print_environment_summary() {
echo "" echo ""
echo -e " ${CYAN}操作系统:${NC} $OS $OS_VERSION" echo -e " ${CYAN}操作系统:${NC} $OS $OS_VERSION"
echo -e " ${CYAN}CPU 架构:${NC} $ARCH → Go 架构: $GO_ARCH" echo -e " ${CYAN}CPU 架构:${NC} $ARCH"
echo "" echo ""
echo " ${CYAN}必要工具:${NC}" echo " ${CYAN}必要工具:${NC}"
@@ -220,14 +187,6 @@ print_environment_summary() {
echo " wget ❌ 未安装 (将自动安装)" echo " wget ❌ 未安装 (将自动安装)"
fi fi
echo ""
echo " ${CYAN}Go 环境:${NC}"
if [ "$HAS_GO" = true ]; then
echo -e " go ✅ 已安装 ($(go version | awk '{print $3}'))"
else
echo " go ❌ 未安装 (将自动安装 Go ${GO_VERSION})"
fi
echo "" echo ""
echo " ${CYAN}Docker 环境:${NC}" echo " ${CYAN}Docker 环境:${NC}"
if [ "$HAS_DOCKER" = true ]; then if [ "$HAS_DOCKER" = true ]; then
@@ -267,12 +226,8 @@ generate_plan() {
[ "$NEED_INSTALL_WGET" = true ] && pkgs="${pkgs} wget" [ "$NEED_INSTALL_WGET" = true ] && pkgs="${pkgs} wget"
PLAN="${PLAN} • 安装必要工具:${pkgs}\n" PLAN="${PLAN} • 安装必要工具:${pkgs}\n"
fi fi
if [ "$NEED_INSTALL_GO" = true ]; then
PLAN="${PLAN} • 安装 Go ${GO_VERSION}\n"
fi
PLAN="${PLAN} • 拉取 frpc-console 源码 (${BRANCH} 分支)\n" PLAN="${PLAN} • 拉取 frpc-console 源码 (${BRANCH} 分支)\n"
PLAN="${PLAN}编译 frpc-console 二进制\n" PLAN="${PLAN}构建 Docker 镜像(源码内编译)\n"
PLAN="${PLAN} • 构建 Docker 镜像\n"
if [ "$CONTAINER_EXISTS" = true ]; then if [ "$CONTAINER_EXISTS" = true ]; then
PLAN="${PLAN} • 停止并删除旧容器\n" PLAN="${PLAN} • 停止并删除旧容器\n"
fi fi
@@ -321,12 +276,8 @@ confirm_deploy() {
read -r CONFIRM </dev/tty read -r CONFIRM </dev/tty
case $CONFIRM in case $CONFIRM in
n|N) n|N) return 1 ;;
return 1 *) return 0 ;;
;;
*)
return 0
;;
esac esac
} }
@@ -353,7 +304,7 @@ custom_config() {
echo "" echo ""
} }
# ---------- 执行部署 ---------- # ---------- 实际执行部署 ----------
do_deploy() { do_deploy() {
print_title print_title
print_subtitle "开始部署" print_subtitle "开始部署"
@@ -364,14 +315,13 @@ do_deploy() {
BACKUP_DIR="/tmp/frpc-console/db-backups" BACKUP_DIR="/tmp/frpc-console/db-backups"
mkdir -p "$BACKUP_DIR" mkdir -p "$BACKUP_DIR"
DB_FILE="${DEPLOY_DIR}/frpc-console.db" # 注意路径变了,不再在 data 子目录 DB_FILE="${DEPLOY_DIR}/frpc-console.db"
if [ -f "$DB_FILE" ]; then if [ -f "$DB_FILE" ]; then
TIMESTAMP=$(date +%Y%m%d_%H%M%S) TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/frpc-console.db.$TIMESTAMP" BACKUP_FILE="$BACKUP_DIR/frpc-console.db.$TIMESTAMP"
cp "$DB_FILE" "$BACKUP_FILE" cp "$DB_FILE" "$BACKUP_FILE"
print_info "已备份: $BACKUP_FILE" print_info "已备份: $BACKUP_FILE"
# 检查数据库是否有效
if command -v sqlite3 &> /dev/null; then if command -v sqlite3 &> /dev/null; then
if ! sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='users';" 2>/dev/null | grep -q "^1$"; then if ! sqlite3 "$DB_FILE" "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='users';" 2>/dev/null | grep -q "^1$"; then
print_warn "数据库文件无效,将删除,由容器全新初始化" print_warn "数据库文件无效,将删除,由容器全新初始化"
@@ -386,6 +336,16 @@ do_deploy() {
print_info "数据库文件不存在,跳过备份" print_info "数据库文件不存在,跳过备份"
fi fi
# ----- 停止旧容器(提前释放资源)-----
if [ "$CONTAINER_EXISTS" = true ]; then
print_step "停止旧容器..."
if [ "$CONTAINER_RUNNING" = true ]; then
docker stop frpc-console 2>/dev/null || true
fi
docker rm frpc-console 2>/dev/null || true
print_success "旧容器已清理"
fi
# ----- 安装必要工具 ----- # ----- 安装必要工具 -----
if [ "$NEED_INSTALL_GIT" = true ] || [ "$NEED_INSTALL_CURL" = true ] || [ "$NEED_INSTALL_WGET" = true ]; then if [ "$NEED_INSTALL_GIT" = true ] || [ "$NEED_INSTALL_CURL" = true ] || [ "$NEED_INSTALL_WGET" = true ]; then
print_step "安装必要工具..." print_step "安装必要工具..."
@@ -424,57 +384,6 @@ do_deploy() {
print_success "必要工具安装完成" print_success "必要工具安装完成"
fi fi
# ----- 安装 Go -----
if [ "$NEED_INSTALL_GO" = true ]; then
print_step "安装 Go ${GO_VERSION} (${GO_ARCH})..."
GO_TMP="/tmp/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz"
if [ -f "$GO_TMP" ]; then
print_info "使用缓存: $GO_TMP"
else
print_info "正在下载..."
MIRRORS=(
"https://mirrors.aliyun.com/golang/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz"
"https://mirrors.tuna.tsinghua.edu.cn/golang/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz"
"https://golang.google.cn/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz"
"https://dl.google.com/go/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz"
)
DOWNLOADED=false
for MIRROR in "${MIRRORS[@]}"; do
print_info "尝试: $MIRROR"
if curl -# -f -L -o "$GO_TMP" "$MIRROR"; then
print_success "下载成功"
DOWNLOADED=true
break
else
print_warn "失败,尝试下一个镜像..."
rm -f "$GO_TMP"
fi
done
if [ "$DOWNLOADED" = false ]; then
print_error "所有镜像源均下载失败"
exit 1
fi
fi
rm -rf /usr/local/go
tar -C /usr/local -xzf "$GO_TMP"
export PATH=$PATH:/usr/local/go/bin
if [ ! -f /etc/profile.d/go.sh ]; then
echo 'export PATH=$PATH:/usr/local/go/bin' > /etc/profile.d/go.sh
fi
/usr/local/go/bin/go env -w GOPROXY=https://goproxy.cn,direct
/usr/local/go/bin/go env -w GOPRIVATE=git.whitetop.xyz
print_success "Go ${GO_VERSION} (${GO_ARCH}) 安装完成"
fi
export PATH=$PATH:/usr/local/go/bin
# ----- 拉取代码 ----- # ----- 拉取代码 -----
print_step "拉取代码..." print_step "拉取代码..."
rm -rf "$WORK_DIR" rm -rf "$WORK_DIR"
@@ -483,33 +392,14 @@ do_deploy() {
mkdir -p bin static mkdir -p bin static
print_success "代码拉取完成" print_success "代码拉取完成"
# ----- 修复 go.mod ----- # ----- 修复 go.modDocker 构建时使用)-----
print_step "检查 go.mod..." print_step "检查 go.mod..."
if grep -q "go 1.2[6-9]" go.mod 2>/dev/null; then if grep -q "go 1.2[6-9]" go.mod 2>/dev/null; then
print_warn "检测到 go.mod 版本过高,自动降级到 go 1.21" print_warn "检测到 go.mod 版本过高,自动降级到 go 1.21"
sed -i 's/go 1.2[6-9].*/go 1.21/' go.mod sed -i 's/go 1.2[6-9].*/go 1.21/' go.mod
fi fi
# ----- 下载依赖 ----- # ----- 准备数据目录 -----
print_step "下载 Go 依赖..."
go mod download
print_success "依赖下载完成"
# ----- 编译 -----
print_step "编译 frpc-console..."
CGO_ENABLED=0 GOOS=linux go build \
-ldflags="-s -w" \
-o frpc-console .
if [ -f "frpc-console" ]; then
SIZE=$(du -h frpc-console | cut -f1)
print_success "编译完成 ($SIZE)"
else
print_error "编译失败"
exit 1
fi
# ----- 准备部署目录 -----
print_step "准备部署目录..." print_step "准备部署目录..."
mkdir -p "$DEPLOY_DIR" mkdir -p "$DEPLOY_DIR"
mkdir -p "$DATA_DIR" mkdir -p "$DATA_DIR"
@@ -520,24 +410,11 @@ do_deploy() {
print_info "数据库文件不存在,容器启动时将自动创建" print_info "数据库文件不存在,容器启动时将自动创建"
fi fi
cp frpc-console "$DEPLOY_DIR/" # ----- 构建 Docker 镜像(内部自动编译)-----
print_success "二进制已复制到 $DEPLOY_DIR"
# ----- 构建 Docker 镜像 -----
print_step "构建 Docker 镜像..." print_step "构建 Docker 镜像..."
docker build -t "${IMAGE_NAME}:latest" . docker build -t "${IMAGE_NAME}:latest" .
print_success "Docker 镜像构建完成: ${IMAGE_NAME}:latest" print_success "Docker 镜像构建完成: ${IMAGE_NAME}:latest"
# ----- 停止旧容器 -----
if [ "$CONTAINER_EXISTS" = true ]; then
print_step "处理旧容器..."
if [ "$CONTAINER_RUNNING" = true ]; then
docker stop frpc-console 2>/dev/null || true
fi
docker rm frpc-console 2>/dev/null || true
print_success "旧容器已清理"
fi
# ----- 启动新容器 ----- # ----- 启动新容器 -----
print_step "启动 frpc-console 容器..." print_step "启动 frpc-console 容器..."
docker run -d \ docker run -d \
@@ -556,14 +433,12 @@ do_deploy() {
exit 1 exit 1
fi fi
# ----- 检查 frpc 子进程(增强版) ----- # ----- 检查 frpc 子进程 -----
print_step "检查 frpc 状态..." print_step "检查 frpc 状态..."
sleep 3 sleep 3
# 先确认容器在运行
if docker ps --format '{{.Names}}' | grep -q "^frpc-console$"; then if docker ps --format '{{.Names}}' | grep -q "^frpc-console$"; then
# 再检查 frpc 进程 if docker exec frpc-console ps aux 2>/dev/null | grep -q "[f]rpc -c"; then
if docker exec frpc-console ps aux 2>/dev/null | grep -q "frpc -c"; then
print_success "frpc 进程运行正常" print_success "frpc 进程运行正常"
else else
print_warn "frpc 进程未运行(可能配置为空,请在 WebUI 中导入 TOML" print_warn "frpc 进程未运行(可能配置为空,请在 WebUI 中导入 TOML"
@@ -573,7 +448,7 @@ do_deploy() {
exit 1 exit 1
fi fi
# ----- 事务后钩子:检测数据库是否可用 ----- # ----- 事务后钩子:检测数据库 -----
print_step "验证数据库状态..." print_step "验证数据库状态..."
if docker exec frpc-console sqlite3 /app/frpc-console.db "SELECT COUNT(*) FROM users;" 2>/dev/null | grep -q "^[0-9]"; then if docker exec frpc-console sqlite3 /app/frpc-console.db "SELECT COUNT(*) FROM users;" 2>/dev/null | grep -q "^[0-9]"; then
print_success "数据库可用" print_success "数据库可用"
@@ -593,8 +468,8 @@ do_deploy() {
echo "" echo ""
echo -e " ${CYAN}📍 访问地址:${NC} http://$(hostname -I | awk '{print $1}'):${PORT}" echo -e " ${CYAN}📍 访问地址:${NC} http://$(hostname -I | awk '{print $1}'):${PORT}"
echo -e " ${CYAN}📂 数据目录:${NC} ${DATA_DIR}" echo -e " ${CYAN}📂 数据目录:${NC} ${DEPLOY_DIR}"
echo -e " ${CYAN}📦 备份目录:${NC} ${BACKUP_DIR}" echo -e " ${CYAN}📦 备份目录:${NC} /tmp/frpc-console/db-backups"
echo -e " ${CYAN}🐳 容器名称:${NC} frpc-console" echo -e " ${CYAN}🐳 容器名称:${NC} frpc-console"
echo "" echo ""
echo -e " ${CYAN}常用命令:${NC}" echo -e " ${CYAN}常用命令:${NC}"
@@ -638,7 +513,6 @@ main() {
fi fi
generate_plan generate_plan
print_deployment_plan print_deployment_plan
if ! confirm_deploy; then if ! confirm_deploy; then