本文总结当前仓库中“库存管理 -> 新增机器”的实现方式。这里的“新增机器”不是只往数据库插一条记录,而是“后端落库存 + 调用 orchestrator 下发纳管 + 后端定时回写库存状态”的完整流程。
POST /api/resource/stocks。stock_info,并将状态置为 JOINING。addNode 接口,但不等待纳管完成,接口立即返回。ClusterOperation,随后创建 NodeInventory。NodeInventory controller 通过 SSH 登录目标机器,安装 kubeadm 依赖并执行 kubeadm join。StockJoiningStatusReconciler 轮询 orchestrator 的节点列表,发现对应 NodeInventory 进入 IDLE 后,把库存状态回写为 IDLE。入口页面是 StockPage.vue。
页面右上角提供“+ 新增机器”按钮,点击后打开创建弹窗。创建弹窗和编辑弹窗共用同一套表单结构。
新增弹窗要求填写以下信息:
ipAddresssshUsernamesshPasswordcpuModelcpuCoresramGbssdGbdescription新增时还提供一个“自动获取以下配置”按钮,会调用 frontend/src/api/stock.js 里的 probeStock(),对应后端 POST /api/resource/stocks/probe。后端会通过 SSH 在目标机器上执行探测脚本,从机器自身读取 CPU、内存和磁盘信息,再回填到表单中。
提交时前端调用 createStock(payload),即:
POST /api/resource/stocks前端做了基本校验:
新增机器的入口在 StockController.java:
POST /api/resource/stocks -> stockService.addMachine(...)真正的业务逻辑在 StockService.java。
addMachine() 会先调用 requireOpsRole(),因此只有以下角色可以新增机器:
ADMINDEVELOPEROPS后端会执行以下处理:
JOINING,对应前端展示的“加入中”。对应的请求 DTO 是 StockMachineCreateReq.java,库存实体是 StockInfoDO.java。
addMachine() 的核心顺序是:
sshPasswordCipher。JOINING。stockDAO.save(normalizedMachine) 插入 stock_info。OrchestratorIdMapper.toNodeId(machineId) 生成固定节点名,格式为 node-{machineId}。k8sOrchestratorClient.addNode(...) 发起纳管。GET /v1/nodes,按 node-{machineId} 找到对应 NodeInventory。NodeInventory 的 status.phase 变为 IDLE 后,再把库存状态改回 IDLE。这里有一个重要设计点:库存记录先落库,纳管结果后回写。如果 orchestrator 短期内还没完成,库存列表会持续显示“加入中”,直到后台 reconciler 看到节点真正就绪。
创建成功后,后端会返回新增后的机器信息,前端把它插入表格首行,并显示“纳管请求已提交”提示。此时状态一般是“加入中”,不会立即显示为 IDLE。
库存数据表是 backend/src/main/resources/db/schema.sql 里的 stock_info。
关键字段:
machine_idip_addresscpu_corescpu_modelram_gbssd_gbssh_usernamessh_password_cipherstatusdescription对应 MyBatis SQL 在 StockDAO.xml:
save 负责插入机器记录findByIpAddress 用于 IP 去重updateStatusByIdAndStatus 用于状态切换deleteByIdAndStatus 用于删除前的状态约束后端通过 HttpK8sOrchestratorClient.java 调用编排器。
addNode() 会向 orchestrator 的 POST /v1/nodes 发送:
nodeIdcpuramssdipAddresssshUsersshPasswordsshPortorchestrator 侧 OrchestratorService 会把这次请求包装成一个 ClusterOperation,操作类型是 AddNode。
ClusterOperationReconciler 在处理 AddNode 时,会创建一个 NodeInventory 资源,关键字段来自请求:
spec.address -> 机器 IPspec.capacity -> CPU / RAM / SSDspec.sshSecretRef -> SSH Secretspec.bootstrap.joinCommandOverride -> join 命令覆盖参数相关代码在 clusteroperation_controller.go 和 nodeinventory_types.go。
NodeInventoryReconciler 的状态流转在 nodeinventory_controller.go:
NEW -> 初始化状态PROVISIONING -> 开始 SSH 纳管IDLE -> 节点已成功加入,可分配FAILED -> 纳管失败,控制器会重试ensureNodeJoined() 会先尝试通过固定节点名或 IP 找到已存在的节点;如果不存在,再读取 SSH Secret,使用 onboarder 执行远程安装和 kubeadm join。
SSHOnboarder 在 onboarder.go 里完成三步:
--node-name,保证 Kubernetes 节点名和 NodeInventory 名称一致。JOINING,不会直接写成 WORKING。JOINING 和 WORKING 都属于受管生命周期态,库存新增接口不会允许手工写入。JOINING 和 WORKING 都属于受管生命周期态,编辑时只允许修改备注。stock_info.ssh_password_cipher 只保存加密后的密码,不保存明文。ip_address 必须唯一。JOINING 状态,后台 StockJoiningStatusReconciler 会持续轮询直到它变成 IDLE。当前的“新增机器”本质上是一个两阶段流程:先把机器作为库存资产写入后端数据库,再交给 k8s orchestrator 通过 NodeInventory 完成真实纳管和 Kubernetes 入网。