Goku Gateway 3.1.x 管理面与 CLI 命令详解

Goku Gateway(goku_lite CE)3.1.x 管理面 HTTP API 与节点 CLI 实操详解:form 表单与 Cookie 会话约定、路由全景与错误码速查,登录→集群→节点→负载均衡→API→策略→配置发布全主线 curl 实测回显,gateway-console/node/run.sh 命令行与 config 离线模式,批量接口三种参数格式等六大坑位,全部 console 3.1.4 + node 3.1.5 实机取证(2026-10-23 ~ 10-24)。

Goku GatewayAPI 网关Go2026/10/24

Goku Gateway 3.1.x 管理面与 CLI 命令详解

目标:把 Goku Gateway(goku_lite 社区版 CE)3.1.x 的管理面 HTTP API 与节点侧 CLI 一次讲透——从登录会话、集群/节点管理,到负载均衡、API 定义、策略生命周期、配置发布的完整主线,全部用管理台自带的 Open API 以 form 表单实测取证;CLI 部分覆盖管理台进程 gateway-console、网关节点进程 node、服务脚本 run.sh 与离线 config 模式。全部回显均在实机(console 3.1.4 + node 3.1.5)上抓取,实测日期 2026-10-23 ~ 2026-10-24。

一、环境信息

本章列出实测环境与访问入口,读者可对照自己的部署核对。

  • 软件版本:管理台 console 3.1.4、网关节点 node 3.1.5(与《Goku Gateway 3.1.x Docker Compose 部署指南》为同一套持续运行的实例);
  • 管理台 Web/API 入口:http://127.0.0.1:8131(Web 控制台与管理 API 同端口同路由,未单独鉴权分离);
  • 网关转发口:6689(数据面 HTTP 入口);
  • 节点注册口:7005(console 的 admin_bind,node 通过它注册并拉取配置);
  • 管理员账号:admin(口令为部署时设置的演示口令,本文脱敏;初始化账号的创建过程见部署指南 4.7 节);
  • 配套后端:一个演示后端 10.89.61.4:80(返回静态页,用于负载均衡指向);
  • 取证方式:curl -d(application/x-www-form-urlencoded)直连管理 API,回显原样记录;CLI 部分为在节点主机目录下的实跑记录。

版本说明:node 程序目录名为 node-3.1.5,但注册到 console 后节点列表显示 version: 3.1.4,且目录内 version 文件内容为 3.1.3——三个"版本号"不一致是 3.1.x 的常态(打包遗留),以实际运行的二进制行为为准,详见 5.4 节。

二、管理面 API 总览

2.1 通信约定

在写第一行 API 之前,先记住四条铁律,全部经实测验证:

  1. 只收 form 表单,不收 JSON。所有写操作(增删改)参数以 application/x-www-form-urlencoded 的 POST body 提交,用 curl -d 'k=v&k2=v2' 即可;GET 查询类接口同样接受 query 或 form。发 JSON 会被当空参数处理。
  2. Cookie 会话,无 Header Token。登录成功后服务端种下 userID、userToken 两个 Cookie(Max-Age=86400,即 24 小时),后续请求带上即可。没有 API Key、没有 Bearer。
  3. 统一回显结构:业务结果 + statusCode。"statusCode":"000000" 为成功;失败时附带 resultDesc(英文错误描述)与 type(对象类型)。常见错误码见 2.3 节。
  4. 同一路由表。管理台前端页面与 API 共用一套 HTTP 路由(源码 console/router.go 用标准库 http.HandleFunc 注册),因此抓前端请求即可发现 API,反之亦然。

2.2 路由全景

以下路由清单整理自源码 console/router.go(与实机行为一致),按模块分组,是本文主线之外"按图索骥"的总索引:

模块路由(省略同构的 edit/delete/getInfo/getList)
会话/guest/login、/user/logout、/user/password/edit、/user/getInfo、/user/getUserType、/user/checkIsAdmin、/user/checkIsSuperAdmin、/user/checkPermission
项目/project/add、/project/batchDelete、/project/strategy/getList
接口分组/apis/group/add、/apis/group/delete、/apis/group/getList
API/apis/add、/apis/copy、/apis/id/getList、/apis/batchEditGroup、/apis/batchDelete、/apis/batchEditBalance、/apis/manager/getList
API 插件绑定/plugin/api/addPluginToApi、/plugin/api/edit、/plugin/api/batchStart、/plugin/api/batchStop、/plugin/api/batchDelete、/plugin/api/notAssign/getList
策略插件绑定/plugin/strategy/addPluginToStrategy、/plugin/strategy/edit、/plugin/strategy/getStatus、/plugin/strategy/batchStart、/plugin/strategy/batchStop、/plugin/strategy/batchDelete
插件/plugin/add、/plugin/checkNameIsExist、/plugin/getConfig、/plugin/start、/plugin/stop、/plugin/availiable/check
策略/strategy/add、/strategy/copy、/strategy/batchEditGroup、/strategy/batchDelete、/strategy/batchStart、/strategy/batchStop、/strategy/id/getList
策略分组/strategy/group/add、/strategy/group/edit、/strategy/group/delete、/strategy/group/getList
策略绑定 API/strategy/api/add、/strategy/api/target、/strategy/api/batchEditTarget、/strategy/api/getList、/strategy/api/getNotInList、/strategy/api/batchDelete、/strategy/api/plugin/getList
节点/node/add、/node/edit、/node/delete、/node/getInfo、/node/getList、/node/batchEditGroup、/node/batchDelete
节点分组/node/group/add、/node/group/edit、/node/group/delete、/node/group/getList
负载均衡/balance/add、/balance/simple、/balance/batchDelete、/balance/service/...(服务发现,http.Handle 前缀路由)
鉴权/auth/getStatus、/auth/getInfo、/auth/editInfo
导入/import/ams/api、/import/ams/group、/import/ams/project
集群/cluster/add、/cluster/edit、/cluster/delete、/cluster/list、/cluster/simpleList
配置发布/version/config/add、/version/config/getList、/version/config/delete、/version/config/publish
运维/监控/monitor/gateway/getSummaryInfo、/monitor/module/config/get、/monitor/module/config/set、/updater/check/table/isExist、/updater/check/column/isExist、/config/log/(日志配置)
静态资源/(前端页面,./static 文件服务)

解读:这批路由完整覆盖了 Web 控制台的全部能力——意味着 console 没有独立"Open API"体系,管理 API 就是前端背后的那套接口;做自动化运维(批量建 API、切流量、定时发布)时直接调用即可,但要接受"无 API Token、靠 Cookie 会话"的现实(见 5.2 节)。

2.3 错误码速查(实测汇总)

statusCode实测场景resultDesc 原文
000000一切成功(无)
100000登录口令错误[ERROR]Wrong username or password!
100001未登录访问受限接口user not logged in
190000apis/batchDelete 参数格式错(见 3.9 节坑)[ERROR]Fail to excute SQL statement!
190021apis/add 的 requestURL 不合法[ERROR]Illegal requestURL!
220000策略批量启停参数格式错(见 3.7 节坑)[ERROR]Fail to update data!
260000balance/add 指向不存在的服务serviceName:no that service:demo-service
290005接口分组的 projectID 不存在[ERROR]The project does not exist
330003node/getList 缺 cluster 参数[ERROR]The cluster dosen't exist!
370001集群名含非法字符[ERROR]Illegal cluster name
370003集群名重复[ERROR]Cluster name already exists
38000x配置版本系列错误(非法 publish/ids 等)详见回显

三、主线实战:从登录到配置发布

本章按真实运维动线组织:登录 → 集群 → 节点 → 项目/分组 → 负载均衡 → API → 策略 → 策略绑定 API → 配置发布 → 监控。每一小节给出请求与原样回显。

3.1 登录与会话

登录接口是 /guest/login(挂在 guest 名下,无需会话),参数 loginCall + loginPassword:

curl -s -c cookie.txt -d 'loginCall=admin&loginPassword=******' \
     http://127.0.0.1:8131/guest/login -i
HTTP/1.1 200 OK
Set-Cookie: userToken=a27add77bc9ec1cb85e08db3e2f96faa; Path=/; Max-Age=86400
Set-Cookie: userID=2; Path=/; Max-Age=86400

{"statusCode":"000000","type":"guest","userID":2}

口令错误时返回 100000(实测 root/错误口令与 admin/123456 均命中同一回显,不区分"用户不存在"与"口令错误"):

{"resultDesc":"[ERROR]Wrong username or password!","statusCode":"100000","type":"guest"}

带着 Cookie 调 /user/getInfo 验证会话(userType: 0 为超管):

{"statusCode":"000000","type":"user","userInfo":{"loginCall":"admin","permission":{},"remark":"","userID":2,"userType":0}}

配套的会话接口还有 /user/getUserType(返回 {"statusCode":"000000","type":"user","userType":0})与 /user/checkIsAdmin。退出登录:

### curl -b cookie.txt -X POST http://127.0.0.1:8131/user/logout
{"statusCode":"000000","type":"user"}

服务端会下发清 Cookie 的响应头(Set-Cookie: userID=; Path=/; Max-Age=0)。但注意:实测用退出前的旧 Cookie 再调 /user/getInfo,仍返回 000000 和完整用户信息——userToken 服务端并未失效,Cookie 被动过期前 token 一直可用。安全敏感环境务必把管理台放在内网(见 5.2 节)。

3.2 集群管理

Goku 的"集群(cluster)"= 机房/分组维度的节点池。查列表 /cluster/list:

{"clusters":[{"id":1,"name":"Default","title":"Default","note":"default","nodeCount":1,"redis":null}],"page":{"itemNum":1,"totalNum":1},"statusCode":"000000","type":"cluster"}

新建集群 /cluster/add(参数 name/title/note),两个实测错误与一个成功:

### name 含特殊字符
{"resultDesc":"[ERROR]Illegal cluster name","statusCode":"370001","type":"cluster"}
### name=backup_area 新建成功
{"statusCode":"000000","type":"cluster"}
### name=backup_area 重复新建
{"resultDesc":"[ERROR]Cluster name already exists","statusCode":"370003","type":"cluster"}

/cluster/simpleList 会带出每个集群的节点计数:

{"clusters":[{"id":1,"name":"Default","title":"Default","note":"default","nodeCount":1,"redis":null},{"id":2,"name":"backup_area","title":"备用机房","note":"d1 test","nodeCount":0,"redis":null}],"page":{"itemNum":2,"totalNum":2},"statusCode":"000000","type":"cluster"}

删除空集群 /cluster/delete(cluster=backup_area)返回 000000;Default 因挂有节点不可删。多机房是付费版(EE)能力,社区版 console 界面上"多机房"入口不可用,但 API 层的集群增删是通的——不过单集群场景没有理由新建第二个。

3.3 节点管理

节点接口的第一个坑:/node/getList 必须带 cluster 参数,否则即使 Default 集群存在也报:

{"resultDesc":"[ERROR]The cluster dosen't exist!","statusCode":"330003","type":"node"}

带 cluster=Default 的正确回显(一条注册成功的在线节点):

{"nodeList":[{"nodeID":1,"nodeName":"node-1","nodeKey":"dbcf5af2f61546367cae44869e1dc21a","listenAddress":"10.89.61.3:6689","adminAddress":"10.89.61.3:7005","cluster":"Default","cluster_title":"Default","version":"3.1.4","nodeStatus":1,"groupName":"未分类","isUpdate":false,"gatewayPath":"","createTime":"2026-10-23 21:54:29","updateTime":"2026-10-23 22:04:43"}],"page":{"itemNum":1,"totalNum":1},"statusCode":"000000","type":"node"}

字段解读:

  • nodeKey:节点实例唯一标识,node 进程首次向 admin_bind(7005)注册时生成,此后每次启动凭它续注册——重启节点进程后 nodeID 不变就是靠它(实测 kill 后重启,列表原样返回同一条记录);
  • listenAddress:该节点对外转发口(6689);adminAddress:节点自身的管理口(7005);
  • nodeStatus:1 在线(console 能连上节点管理口)、0 离线。实测一个"登记了但没启动"的节点 nodeStatus=0;
  • version:节点上报的版本(详见 5.4 节的三版本错位)。

新建节点 /node/add(参数 cluster、nodeName、listenAddress、adminAddress 等,取自源码 node.go)返回:

{"nodeID":2,"resultDesc":"","statusCode":"000000","type":"node","version":"3.1.4"}

/node/getInfo?nodeID=1 返回上述单条 nodeInfo 结构;/node/delete(nodeID=2)返回 000000。注意:/node/add 只是"登记地址",真正的节点身份由节点进程自己注册产生——先在主机上把 node 进程跑起来(见第四章),它才会以 node-1 的身份出现在列表里;单纯 API 登记的节点永远是 nodeStatus=0 的占位。

3.4 项目与接口分组

API 两级归属:项目(project)→ 接口分组(apiGroup)→ API。建项目:

### curl -d 'projectName=d1-project' /project/add
{"projectID":3,"statusCode":"000000","type":"project"}

/project/getList:

{"page":{"itemNum":2,"totalNum":2},"projectList":[{"projectID":3,"projectName":"d1-project","createTime":"","updateTime":"2026-10-24 03:52:44"},{"projectID":1,"projectName":"demo-project","createTime":"","updateTime":"2026-10-23 22:33:25"}],"statusCode":"000000","type":"project"}

建分组时的坑:projectID 必须是已存在的数字 ID,传名字或漏传直接 290005:

### /apis/group/add 缺有效 projectID
{"resultDesc":"[ERROR]The project does not exist","statusCode":"290005","type":"api"}
### /apis/group/add projectID=3&groupName=d1-group
{"groupID":1,"statusCode":"000000","type":"apiGroup"}
### /apis/group/getList projectID=3
{"groupList":[{"groupDepth":1,"groupID":1,"groupName":"d1-group","parentGroupID":0}],"page":{"itemNum":1,"totalNum":1},"statusCode":"000000","type":"apiGroup"}

3.5 负载均衡

负载均衡(balance)是 API 转发目标的抽象。/balance/add 参数(源码 balance/param.go):balanceName(必填)、serviceName(必填,服务名)、appName、static、staticCluster(JSON 对象:{"集群名":"地址"})、balanceDesc。静态后端的标准姿势是 serviceName=static + staticCluster:

curl -s -b cookie.txt -d 'balanceName=d1-balance&serviceName=static&serviceType=static&serviceDriver=static&staticCluster={"Default":"10.89.61.4:80"}&balanceDesc=d1 test backend' \
     http://127.0.0.1:8131/balance/add
{"statusCode":"000000","type":"balance"}

指向不存在的服务名时的报错(serviceName 不是 static 也不是已登记的服务):

{"resultDesc":"serviceName:no that service:demo-service","statusCode":"260000","type":"balance"}

/balance/getList 回显(注意 staticCluster 已被解析成对象,canDelete=0 表示仍被 API 引用):

{"balanceList":[{"balanceName":"d1-balance","serviceName":"static","serviceType":"static","serviceDriver":"static","appName":"","static":"","staticCluster":{"Default":"10.89.61.4:80"},"balanceDesc":"d1 test backend","createTime":"2026-10-24 03:52:44","updateTime":"2026-10-24 03:52:44","canDelete":0}],"page":{"itemNum":1,"totalNum":2},"statusCode":"000000","type":"balance"}

3.6 API 定义

/apis/add 是参数最多的接口(源码 api.go 全量:apiName、alias、requestURL、requestMethod、protocol、balanceName、targetURL、targetMethod、isFollow、timeout、retryCount、groupID、projectID、alertValve、managerID、apiType、linkApis、staticResponse、responseDataType)。最小可用集 + URL 校验:

### requestURL 传了个不含路径的值
{"resultDesc":"[ERROR]Illegal requestURL!","statusCode":"190021","type":"api"}
### requestURL=/d1&requestMethod=GET&protocol=HTTP&apiType=1&balanceName=d1-balance&projectID=3
{"apiID":2,"statusCode":"000000","type":"api"}

/apis/getList?projectID=3:

{"apiList":[{"apiID":2,"apiName":"d1-api","apiType":1,"groupID":0,"groupName":"未分组","groupPath":"0","isFollow":false,"managerName":"admin","protocol":"HTTP","requestMethod":"GET","requestURL":"/d1","target":"d1-balance","targetMethod":"GET","targetURL":"","updateTime":"2026-10-24 03:53:21","updaterName":"admin"}],"page":{"itemNum":1,"page":1,"pageSize":10,"totalNum":1},"statusCode":"000000","type":"api"}

target 字段直接回填了 balanceName——API 与负载均衡在创建时就绑死,后续要换后端要么 apis/edit,要么 apis/batchEditBalance 批量改。

3.7 策略生命周期

策略(strategy)是 Goku 的流量管理单元:一个策略 = 一组 API + 一组插件 + 一个分组归属,策略启用与否决定整组 API 是否对外服务。

创建(参数 strategyName、groupID),返回的 strategyID 是 6 位随机码,不是自增 ID:

### /strategy/add strategyName=d1-strategy
{"statusCode":"000000","strategyID":"YdXE9N","type":"strategy"}

查询 /strategy/getList(enableStatus: 0 停用 / 1 启用;新建策略默认停用):

{"page":{"itemNum":2,"page":1,"pageSize":10,"totalNum":2},"statusCode":"000000","strategyList":[{"strategyID":"YdXE9N","strategyName":"d1-strategy","updateTime":"2026-10-24 03:52:44","createTime":"2026-10-24 03:52:44","groupID":0,"groupName":"未分组","enableStatus":0,"strategyType":0,"updater":"","creater":""},{"strategyID":"QYYGza","strategyName":"demo-strategy","enableStatus":1,"strategyType":0,"groupName":"未分组"}],"type":"strategy"}

改基本信息 /strategy/edit(strategyID + strategyName + groupID)返回 {"statusCode":"000000","strategyID":"YdXE9N","type":"strategy"},实测把 d1-strategy 改名为 d1-strategy-v2 成功。

启停的坑(本文实测最大的一个误导性错误):/strategy/batchStop 与 /strategy/batchStart 的参数 strategyIDList 是逗号分隔的裸 ID(源码 strings.Split(strategyIDList, ",") 后拼进 SQL 的 IN (...))。传成 JSON 数组字符串 ["YdXE9N"] 不会报参数错,而是 SQL 更新 0 行,返回一个看起来像数据库故障的错误:

### 错误姿势:strategyIDList=["YdXE9N"]
{"resultDesc":"[ERROR]Fail to update data!","statusCode":"220000","type":"strategy"}
### 正确姿势:strategyIDList=YdXE9N
{"statusCode":"000000","type":"strategy"}

成功后复查 getList:d1-strategy-v2 的 enableStatus 在 0/1 间随 stop/start 正确切换,另一个策略不受影响。

删除 /strategy/delete(strategyID=YdXE9N)返回 000000。

3.8 策略绑定 API 与插件清单

API 建好后要与策略绑定才进入转发链路。/strategy/api/add 参数就两个:strategyID + apiID:

### /strategy/api/add strategyID=QYYGza&apiID=1
{"statusCode":"000000","type":"apiStrategy"}

注意回显的 type 变成了 apiStrategy(策略内 API 关系)。绑定结果用 /strategy/api/getList?strategyID=QYYGza 验证:

{"apiList":[{"apiID":1,"apiName":"demo-nginx","apiType":1,"isFollow":true,"managerName":"admin","requestMethod":"GET","requestURL":"/demo","target":"demo-balance","targetMethod":"ALL"}],"page":{"itemNum":1,"totalNum":1},"statusCode":"000000","type":"apiStrategy"}

配套接口:/strategy/api/getNotInList(查"还没进策略"的 API)、/strategy/api/target(改策略内 API 的转发目标)、/strategy/api/batchDelete(参数 apiIDs,逗号分隔)。删除策略本身时,绑定关系会级联清理(实测删除 YdXE9N 后无残留)。

插件方面,/plugin/getList 实测返回社区版内置的 5 个插件(均可在策略或 API 级别启停):

pluginName中文名类型版本pluginPriority
goku-basic_authBasic鉴权鉴权(1)1.41001
goku-apikey_authAPIKey鉴权鉴权(1)1.41003
goku-ip_restrictionIP黑白名单鉴权(1)1.4990
goku-extra_params额外参数转换(2)1.5800
goku-params_transformer参数映射转换(2)1.6801

节点侧与之一一对应的 .so 动态库文件位于节点程序目录 plugin/ 下(见 4.5 节)——console 里装的插件,节点机器上必须有同名 .so 才真正生效。

3.9 配置版本与发布

这是管理面最关键的一步:console 上的一切改动只是写库,节点并不实时感知;只有"发布配置版本"后,节点才会拉到新配置。三个接口:

  • /version/config/add:参数 name、version、remark、publish(传 1 可"创建即发布");
  • /version/config/publish:参数 versionID;
  • /version/config/getList:keyword 可选。

实测发布动作:

### /version/config/add name=d1-config&version=v10&remark=d1 publish test&publish=0
{"statusCode":"000000","type":"versionConfig"}
### /version/config/publish versionID=10
{"statusCode":"000000","type":"versionConfig"}

发布后 getList 的状态位(节选前三条):

{'versionID': 10, 'name': 's8-cli-version', 'publishStatus': 1, 'publishTime': '2026-10-24 03:54:06'}
{'versionID': 11, 'name': 'd1-config', 'version': 'v10', 'publishStatus': 0, 'publishTime': '2026-10-24 03:54:06'}
{'versionID': 9, 'name': 'http-proto', 'publishStatus': 0}

语义拆解:publishStatus=1 的那一条就是当前生效版本,publishTime 是生效时刻;发布新版本后旧版本自动归 0(实测先发布 10 再发布 9,getList 中 9 变 1、10 归 0)。发布成功的即时效果可从网关口验证:发布前后 curl -I http://127.0.0.1:6689/demo 均为 200,已生效路由不因发布动作抖动。

删除版本的坑:/version/config/delete 的参数 ids 反而是 JSON 数组(源码 json.Unmarshal([]byte(ids), &idList))——和 3.7 节策略的逗号分隔刚好相反:

### /version/config/delete ids=[10,11]
{"statusCode":"000000","type":"versionConfig"}

删 API 的坑(更狠):/apis/batchDelete 的 apiIDList 源码里是直接拼接进 SQL 的 IN (...),传 JSON 数组会真的把 ["2"] 拼出非法 SQL:

### 错误姿势:apiIDList=["2"]
{"resultDesc":"[ERROR]Fail to excute SQL statement!","statusCode":"190000","type":"api"}
### 正确姿势:apiIDList=2(多个用裸逗号:1,2,3)
{"statusCode":"000000","type":"api"}

三种"批量"接口、三种格式——strategy/batch* 逗号分隔、version/config/delete JSON 数组、apis/batchDelete 裸拼 SQL。这是自动化脚本最容易踩的一组坑,建议封装成三个函数分别处理。

3.10 监控摘要

/monitor/gateway/getSummaryInfo 一次返回全局概览,适合做巡检脚本:

{"baseInfo":{"nodeCount":1,"nodeStartCount":0,"nodeStopCount":0,"projectCount":1,"apiCount":1,"strategyCount":2,"pluginCount":5,"clusterCount":1,"version":"3.1.4"},"statusCode":"000000","type":"monitor"}

version 字段是 console 自身版本。配合 /updater/check/table/isExist、/config/log/ 系列可做表结构与日志配置巡检。

四、CLI 命令详解

管理面 API 之外,3.1.x 的运行时控制全靠两个二进制与一个服务脚本。以下均来自节点/管理台主机目录的实跑取证。

4.1 管理台进程 gateway-console

$ ./gateway-console --help
Usage of ./gateway-console:
  -c string
        Please provide a valid configuration file path (default "./config/goku.conf")
  -debug

  -p string
        Please provide user password
  -u string
        Please provide user name
  • -c:指定 goku.conf 路径(缺省取工作目录下 ./config/goku.conf;该文件只有 listen_port、admin_bind 两行,完整参数解析见《Goku Gateway 3.1.x 配置参数详解》);
  • -u/-p:命令行传入管理员账号口令(首次初始化用,日常运行不需要);
  • -debug:调试日志。

启动成功标志(进程日志):

2026/10/23 22:28:59 Listen: 7000
2026/10/23 22:28:59 Start Successfully!
dbcf5af2f61546367cae44869e1dc21a

第一行是 listen_port 生效;那串 32 位十六进制是本 console 的实例标识(即 3.3 节节点回显里 node 关联的 nodeKey 前缀来源——node 注册时必须带它)。

4.2 网关节点进程 node

$ ./node --help
Usage of ./node:
  -admin string
        Please provide a valid host!
  -config string
        Please provide a config file
  -debug

  -instance string
        Please provide a valid instance!

四个参数三种模式:

  1. console 模式(生产标准姿势):-admin=<console 地址:7005> -instance=<实例标识>。实测进程命令行:

    /app/goku-ce/node/node-3.1.5/node --admin=10.89.61.2:7005 --instance=dbcf5af2f61546367cae44869e1dc21a
    

    -admin 指向管理台注册口;-instance 是 4.1 节那串 32 位标识。不传参数直接运行会打印上述 Usage 并退出(rc=0)。

  2. config 模式(离线/单机调试):-config=/path/to/goku-node.json,与 console 完全断开,配置文件结构(GokuConfig)逐字段解析见《Goku Gateway 3.1.x 配置参数详解》5.6 节。实测两个要点:

    • log.enable 字段类型是 int(1/0),写成 JSON 布尔值 true 直接 panic 退出:

      [PANI] read config from : /tmp/offline.json   json: cannot unmarshal bool into Go struct field LogConfig.log.enable of type int
      panic: [PANI] read config from : /tmp/offline.json   ...
      
    • 修正后正常启动,日志落 -config 里 log.dir 指定的文件(实测 offline-test.log 84 字节),仅有一条无害告警 manager/config unmarshal access log fields error:<nil>。

  3. -debug:两种模式下均可叠加,输出调试日志。

4.3 run.sh 服务脚本

节点程序目录自带 run.sh,是裸机部署时的服务管理入口:

$ ./run.sh
Usage: ./run.sh {start|stop|reload|restart|force-reload} [admin url] [port]

实测行为表:

命令实测结果
run.sh start $admin $port正常拉起 node 进程;重复执行报 [FATA] duplicate instance(端口/实例冲突,进程拒绝二次启动)
run.sh stop(无运行中实例)输出 Note! node not started!,退出码 0(脚本不区分"没起"与"停失败",做自动化时先查进程再停)
run.sh reload通知运行中的 node 重载配置(对应 console 侧重新发布)
run.sh restart / force-reload先 stop 后 start
run.sh 任意非法参数打印 Usage,退出码 1

start 时会把参数写进 work/node.env(实测内容 ENV_PORT= 与 ENV_ADMIN=10.89.61.2:7005 两行),restart 读它复现同样的启动参数——所以改启动参数要么改 env 文件,要么显式带参 restart,否则永远用旧参数。

4.4 节点工作目录与日志

console 模式下 node 的工作目录 work/ 结构:

work/
├── logs/
│   ├── access-2026-10-23-21.log   # 按小时滚动的访问日志
│   ├── node-2026-10-23.log        # 按天滚动的运行日志
│   ├── access.log / node.log      # 当前正在写的日志
└── node.env                       # 启动参数快照

访问日志按小时切、运行日志按天切,保留策略由 console 下发的配置版本控制(/config/log/ 系列 API 可改)。排查转发问题先看 access.log 再看 node.log。

4.5 install.sh 与程序目录结构

节点程序目录还带一个 install.sh <目标目录>,作用是把程序目录复制到目标位置、建立 node -> node-3.1.5/ 符号链接并创建 work/ 目录——官方约定的"版本目录 + current 软链"布局,升级时新版本目录就位、软链一换即可(回滚同理)。完整目录实拍:

node/                 -> node-3.1.5/
├── node              # 21MB 的网关主程序
├── run.sh / install.sh
├── version           # 内容 "3.1.3"(打包遗留,见 5.4)
├── plugin/           # 与 console 内置插件对应的动态库
│   ├── goku-apikey_auth.so  goku-basic_auth.so
│   ├── goku-ip_restriction.so  goku-params_transformer.so
│   └── goku-extra_params.so
└── work -> /app/goku-ce/node/work

五、常见问题(FAQ)

5.1 请求发了没生效?——先确认"发布"了吗

console 的所有增删改(含 API、策略、插件配置)都只改数据库,节点不会热感知。必须调 /version/config/add(或 publish=1)+ /version/config/publish 生成新的生效版本,节点拉取后才生效。判断方法:version/config/getList 看 publishStatus=1 的是哪条、publishTime 是否在你改动之后。

5.2 管理台 API 有没有鉴权体系?安全上注意什么

没有 API Token 体系,全部走 Cookie 会话(2.1 节),且实测 /user/logout 后旧 userToken 在服务端并未立即失效。因此:管理台端口只绑内网;自动化调用把 Cookie 文件当密码管理(chmod 600);不要把管理台直接暴露公网。另外接口层面连 /guest/login 都不限制试错频率,口令要够长。

5.3 批量接口报"Fail to update/execute"是不是数据库坏了

大概率不是。220000/190000 两组错误几乎都是参数格式问题:strategy/batch* 要裸逗号分隔(YdXE9N,abc123),apis/batchDelete 要裸逗号分隔数字(1,2,3),version/config/delete 才用 JSON 数组([10,11])。对照 3.7/3.9 节修正参数即可。

5.4 为什么版本号对不上:3.1.3 / 3.1.4 / 3.1.5

实测三处"版本"并存:节点程序目录 version 文件写 3.1.3(打包时遗留未更新)、console 节点列表上报 version: 3.1.4(node 二进制内编译值)、程序目录名 node-3.1.5(发布 tag)。以二进制行为与官方发行 tag 对应关系为准(tag→发布日期取证见《Goku Gateway 3.1.x 介绍与选型指南》2.2 节),version 文件仅作参考。

5.5 node 拉不起来/注册不上,先查什么

依次检查:-admin 地址端口是否为 console 的 admin_bind(默认 7005);-instance 是否为 console 日志里打出的 32 位标识;重复启动会 duplicate instance FATAL(先停旧进程);config 模式下 log.enable 必须是数字 1/0 而非布尔(4.2 节 panic 实录)。注册成功后 node/getList 的 nodeStatus 应变为 1。

5.6 能不能绕过 Web 控制台做 CI/CD

可以,但不舒服:API 是 Cookie 会话 + 无 OpenAPI 文档 + 批量接口三种格式(5.3 节),只能靠抓前端请求或读源码 console/router.go 对齐。脚本化时的最小闭环:guest/login 拿 Cookie → 业务接口改配置 → version/config/add(publish=1) 发布 → monitor/gateway/getSummaryInfo 巡检。本项目已停止维护(见选型指南 2.2 节),不建议在此之上做重资产投入。

六、参考链接

  1. 本专栏认知篇:《Goku Gateway 3.1.x 介绍与选型指南》
  2. 本专栏部署篇:《Goku Gateway 3.1.x Docker Compose 部署指南》
  3. 本专栏参数篇:《Goku Gateway 3.1.x 配置参数详解》
  4. 源码仓库(路由表与参数定义出处):https://github.com/eolinker/goku_lite
  5. 官方文档站:https://help.eolinker.com/