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 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 之前,先记住四条铁律,全部经实测验证:
- 只收 form 表单,不收 JSON。所有写操作(增删改)参数以
application/x-www-form-urlencoded的 POST body 提交,用curl -d 'k=v&k2=v2'即可;GET 查询类接口同样接受 query 或 form。发 JSON 会被当空参数处理。 - Cookie 会话,无 Header Token。登录成功后服务端种下
userID、userToken两个 Cookie(Max-Age=86400,即 24 小时),后续请求带上即可。没有 API Key、没有 Bearer。 - 统一回显结构:业务结果 +
statusCode。"statusCode":"000000"为成功;失败时附带resultDesc(英文错误描述)与type(对象类型)。常见错误码见 2.3 节。 - 同一路由表。管理台前端页面与 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 |
190000 | apis/batchDelete 参数格式错(见 3.9 节坑) | [ERROR]Fail to excute SQL statement! |
190021 | apis/add 的 requestURL 不合法 | [ERROR]Illegal requestURL! |
220000 | 策略批量启停参数格式错(见 3.7 节坑) | [ERROR]Fail to update data! |
260000 | balance/add 指向不存在的服务 | serviceName:no that service:demo-service |
290005 | 接口分组的 projectID 不存在 | [ERROR]The project does not exist |
330003 | node/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_auth | Basic鉴权 | 鉴权(1) | 1.4 | 1001 |
| goku-apikey_auth | APIKey鉴权 | 鉴权(1) | 1.4 | 1003 |
| goku-ip_restriction | IP黑白名单 | 鉴权(1) | 1.4 | 990 |
| goku-extra_params | 额外参数 | 转换(2) | 1.5 | 800 |
| goku-params_transformer | 参数映射 | 转换(2) | 1.6 | 801 |
节点侧与之一一对应的 .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/deleteJSON 数组、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!
四个参数三种模式:
-
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)。 -
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.log84 字节),仅有一条无害告警manager/config unmarshal access log fields error:<nil>。
-
-
-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 节),不建议在此之上做重资产投入。
六、参考链接
- 本专栏认知篇:《Goku Gateway 3.1.x 介绍与选型指南》
- 本专栏部署篇:《Goku Gateway 3.1.x Docker Compose 部署指南》
- 本专栏参数篇:《Goku Gateway 3.1.x 配置参数详解》
- 源码仓库(路由表与参数定义出处):
https://github.com/eolinker/goku_lite - 官方文档站:
https://help.eolinker.com/