Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

galaxio-labs Operator Ecosystem

核心流程

  1. gops mod 创建模块维护器,用 GXL 编写维护器的 workflow
  2. gops sys 创建系统维护器,组合多个模块维护器,用 GXL 编写 workflow
  3. 系统维护器保存到配置管理库中,待发布到客户环境
  4. 在客户环境中,使用 gops prj 创建维护工程,并加载系统维护器
  5. 在客户环境中,使用 gx 执行维护器的 workflow
  6. 保存维护工程到配置管理库中

GXL 文档的来源

gxl/ 下的页面大部分是 galaxy-flow 仓库 docs/gxl/ 的镜像, 单一真源在 galaxy-flow,请不要在这里直接改这些页面(改动会在下次同步时被覆盖)。

例外:gxl/example/*.md 是本仓库自有的运维向改写(补充“对应目录 / 运行方式 / 这个示例验证了什么”等), 不属于镜像,不会被同步覆盖。

同步与校验:

# 在 galaxy-flow 仓库执行同步(默认写入 ../operator-docs/src/gxl)
scripts/sync-gxl-docs.sh sync --dest <operator-docs>/src/gxl

# 只校验是否已同步
scripts/sync-gxl-docs.sh check --dest <operator-docs>/src/gxl

本仓库的 GXL docs sync check workflow 会每天定时、以及在 push / PR 时 用 galaxy-flow main 的 docs/gxl/ 校验上述镜像是否已同步。 新增镜像页面后,记得同时把条目加进 SUMMARY.md,否则该页不会出现在侧边栏。

目录约定

站点源(mdBook 的 src)在 src/,book.toml 留在仓库根:这样 .git/、.github/ 落在站点源之外, 不会被 mdBook 当作站点资源拷进 book/ 产物。theme/ 按 mdBook 约定放在 book.toml 同级。

上线前提:该 workflow 调用的是 galaxy-flow 仓库里的 scripts/sync-gxl-docs.sh。 在它并入 galaxy-flow main 之前,workflow 会给出 warning 并跳过校验(不会误报红)。

Changelog

文档更新 2026-09-30 —— 值变更表(gops sys diff / gops mod diff)

  • 命令行工具:cmd/gops.md 新增「展示系统值变更」与「展示模块值变更」两节(列含义、未展开值比对、--json、localize 末尾附带变更表);gops prj diff 标注暂不提供;mod localize / sys localize 补文件变更表(created/replaced,前后内容指纹比对);sys diff 补 gxl 系统的模块分组([mod: <name>],values/<mod>/mod_value.yml)与 --json 新结构

文档更新 2026-09-28 —— 对齐 galaxy-ops 1.3.3 的 docker-compose 文件位置

  • System 文档:kind: docker-compose 的 compose 文件默认从系统根移至 sys/docker-compose.yaml,并补充查找顺序、compose 项目目录锚定系统根、旧布局仍兼容的说明;同步 operator/sys/structure/directory.md、file-organization.md、naming-conventions.md、operator/sys/README.md、operator/sys/examples/docker-compose.md、operator/sys/troubleshooting/common-issues.md、operator/overview.md、operator/roadmap.md
  • 命令行工具:cmd/gops.md 的系统目录结构与 .env 消费说明改为 sys/docker-compose.yaml

工程 2026-09-18 —— 站点源移入 src/,避免 .git 被拷进产物

  • book.toml 的 src 由 ./ 改为 src,站点内容(SUMMARY.md、README.md、CHANGELOG.md、cmd/、gxl/、operator/、config/、buildin.md、work.md、mermaid.min.js、favicon.svg)平移至 src/
  • 原因:站点源为仓库根时,mdBook 会把 .git/(约 5.2MB,含 objects/refs)、.github/、.gitignore 一并拷进 book/ 产物(并且遍历 .git 时会撞上 git 临时 index 文件而偶发构建失败)。移入子目录后这些落在站点源之外
  • theme/ 保留在 book.toml 同级(mdBook 从 book root 取 theme/,已实测确认);产物不再包含 book.toml
  • galaxy-flow 的 scripts/sync-gxl-docs.sh 默认 --dest 与 GXL docs sync check workflow 同步改为 src/gxl

页面风格 2026-09-18 —— 对齐 wp-docs 主题

  • 移植 wp-docs 的 VitePress 风格 mdBook 主题:新增 theme/(site.css 与上游一致;site.js 裁掉 wp 专有的顶栏/中英切换/版本横幅,保留侧栏折叠、侧栏宽度持久化、本页目录、mermaid 主题联动),book.toml 设 default-theme / preferred-dark-theme 并指向该目录
  • favicon 改由 theme/favicon.svg 提供;删除 mermaid.css(其内容是一段报错文本,被误当样式表引用)
  • mermaid.min.js 改为按需懒加载(站内无 mermaid 图,原先每页白加载 2.9MB)
  • CI 固定 mdBook 0.5.2:主题依赖 0.5 的 DOM 结构

文档更新 2026-09-18 —— 对齐当前工具集与 galaxy-ops 实现

  • 命令行工具:cmd/gflow.md 重写为 cmd/gx.md(命令表按实机 gx --help 校正);移除 gmod / gsys 条目,gprj 标注 legacy;cmd/gops.md 按当前实现重写(ops-systems.yml 已并入 ops-prj.yml、sys localize 参数、sys package / prj reimport / sys new --kind)
  • 维护器:operator/sys/* 补齐 kind(gxl / docker-compose)分派、sys-model 字段、GXL 与 docker-compose 两套目录结构、merged_vars.yml / sys_value.yml / .env 与常见问题,并新增 docker-compose 示例;operator/mod/* 与 README 同步 gx 名称
  • 工程:SUMMARY.md 清掉指向不存在文件的条目并注册新页;book.toml 移除非法字段 multilingual(mdbook build 恢复可用);并入 galaxy-sec → galaxio-labs 署名

Galaxy Flow v0.8.3 → v0.8.6

新增

  • 日志重定向系统重构:改用管道(pipe)实现,改进处理机制与稳定性
  • 逻辑表达式(logic_exp):完整的解析与执行能力
  • gx.tar / gx.untar:原生压缩与解压缩能力

改进

  • 成功状态处理逻辑重构、表达式逻辑更新、清理 taskvalue 中的日志
  • 依赖更新(clap 等)、代码格式化与 clippy 修复、artifact 构建更新
  • 新增读取文件日志功能

修复

  • 模块路径错误、模块名称列表问题
  • 通道与启用状态的关联问题
  • 干运行参数未传递给子 gxl 的问题

从 v0.8.3 升级到 v0.8.6 向后兼容;建议试用新的日志重定向与逻辑表达式功能。

0.8.3

新增

  • GXL 支持 数字、BOOL、数组、对象 数据类型
  • 提供 defined 函数 - 检查变量是否已定义
  • 提供 gx.shell 方便 shell 调用
  • 支持 ${VAR:default} 变量定义默认值
  • gprj update mod 或 gflow –update mod 支持更新项目依赖的 Mod

改进

  • gx.read_file 读取内容到对象,便于后续处理
  • winnow 升级 0.7
  • 对于远程Mod的获取,去掉外部Git 依赖
  • 修改外部依赖

0.7.0

新增

  • 支持事务机制
  • 支持 dryrun 机制(预览操作结果而不实际执行)

0.6.4

新增

  • gx.cmd 支持 quiet(静默):自定义控制 cmd 的日志输出

0.6.2

新增

  • 优化日志输出、增加日志重定向,支持捕获控制台标准日志输出

0.6.0

新增

  • 生成任务报告(执行过程与结果详情)
  • 支持 flow 上的 Task 注解

改进

  • flow 编排语法由 : 改为 |

gflow-0.5.3

内置环境变量

  • GXL_PRJ_ROOT:最近定义的 _gal/project.toml 所在目录

extern mod 支持变量

extern mod head { path = "${GXL_START_ROOT}/_gal/"; }

0.5.3 下载

0.5.2

内置环境变量

  • GXL_START_ROOT:GXL 启动处理的目录
  • GXL_CUR_DIR:GXL 当前所在目录(调用 gx.run 时可能与 GXL_START_ROOT 不同)

命令行工具

当前(galaxio-labs operator ecosystem)提供的命令:

  • gops:模块 / 系统 / 运维项目管理(galaxy-ops)
  • gx:GXL 执行器(galaxy-flow)

早期的 gflow、gmod、gsys、gprj 已更名或合并: gflow → gx;gmod / gsys → gops mod / gops sys; gprj → gx init project。

gx 命令使用文档

gx 是 gflow 的新名字(galaxy-flow 的执行器 CLI)。本文档按当前 gx CLI 编写。

概述

gx 用于运行 GXL 工作流,并提供运行环境 / 项目初始化与模块管理。它负责“执行”这一层:

  • galaxy-flow(gx):定义并执行工作流
  • galaxy-ops(gops):组织与交付模块、系统、运维项目

基本用法

gx <COMMAND>

命令列表

命令说明
gx run [FLOWS]...运行工作流(默认 ./_gal/work.gxl)
gx adm [FLOWS]...运行管理流程(默认 ./_gal/adm.gxl)
gx init env初始化本地 Galaxy 环境(~/.galaxy、网络访问控制等)
gx init project [--repo URL] [--path SUBDIR] [--branch B] [--tag T]初始化项目(默认用本地模板;--path/--repo 走远程)
gx mod update更新项目模块(依据本地 _gal 配置)
gx doc [TOPIC]查看内置文档
gx check打印当前运行环境信息
gx self check|update|rollback自更新管理

参数说明

位置参数

  • FLOWS...:流程名称列表(用于 gx run / gx adm)

选项参数

  • -e, --env <ENV>:环境名称(默认 default)
  • -d, --debug <DEBUG>:调试级别(默认 0)
  • -c, --conf <CONF>:GXL 配置文件路径(默认值由子命令决定)
  • --log <LOG>:日志配置,例如 --log cmd=debug,parse=info
  • --cmd-arg <ARG>:传递给流程的命令行参数
  • -q, --quiet:静默模式
  • -h, --help / -V, --version

使用示例

# 运行默认工作流
gx run

# 运行指定流程
gx run conf ver

# 运行管理流程
gx adm package

# 指定环境与调试级别
gx adm -e dev -d 2 start

# 初始化项目(默认模板仓库)
gx init project --path <subdir>

# 更新模块 / 查看环境
gx mod update
gx check

目录约定

  • ./_gal/work.gxl:工作流入口(gx run)
  • ./_gal/adm.gxl:管理流程入口(gx adm)
  • ./_gal/mods/:本地项目模块

注意:旧文档里的 ./_rg/ 已改为 ./_gal/。

环境变量

  • RUST_LOG:Rust 日志级别
  • GXL 模块渠道等变量按具体工作流约定(例如模板里的 GXL_CHANNEL)

返回值

  • 0:执行成功
  • 非 0:执行失败,返回错误码

常见问题

找不到配置文件

gx run / gx adm 默认读取当前目录下的 ./_gal/work.gxl / ./_gal/adm.gxl,请在项目根目录执行,或用 -c 指定配置文件。

权限问题

chmod +x gx

模块加载失败

检查网络连接与模块路径配置(_gal 中的 extern mod)。

与 gops 的关系

kind: gxl 的系统在 gops run start/stop/status/... 时委托外部执行器执行系统的管理流程; kind: docker-compose 的系统不需要 gx,直接映射到本机 docker compose。

gops - Galaxy Operations System 系统操作管理工具

概述

gops 是 Galaxy Operations System 的核心命令行工具,用于管理系统配置、模块操作和系统设置。它提供了完整的系统管理功能,帮助开发者高效地管理 Galaxy 系统的各种组件和配置。

基本用法

显示版本信息

gops
# 输出示例:gops: 1.3.0

显示帮助信息

gops --help
gops <command> --help
gops <command> <subcommand> --help

命令结构

gops 采用三层命令结构:

gops [全局选项] <主命令> [子命令选项] <子命令>

主命令

  1. gops prj - 部署管理命令
  2. gops mod - 模块管理命令
  3. gops sys - 系统管理命令(定义 / 交付 / 工件)
  4. gops run - 运行时运维命令(在环境里落地 / 运行)
  5. gops self - 自升级命令

全局选项

所有命令都支持以下全局选项:

调试选项

  • -d, --debug <LEVEL> - 调试级别(0-3)
    • 0: 关闭调试输出
    • 1: 基础调试信息
    • 2: 详细调试信息
    • 3: 跟踪调试信息

日志选项

  • --log <LOG> - 日志级别配置
    • 格式:模块=级别,模块=级别
    • 例如:--log setting=debug,system=info

强制选项

  • -f, --force <LEVEL> - 强制更新级别
    • 0: 正常模式(默认)
    • 1: 跳过确认
    • 2: 覆盖文件
    • 3: 强制拉取

部署工程管理命令 (gops prj)

创建维护工程

gops prj new [OPTIONS]

选项:

  • -n, --name <NAME> - 工程配置名称(必填)
  • -d, --debug <LEVEL> - 调试级别
  • --log <LOG> - 日志配置

功能:

  • 创建指定名称的维护工程
  • 初始化工程目录结构
  • 生成必要的配置文件

示例:

# 创建名为 my-project 的工程
gops prj new --name my-project

# 创建工程并启用调试
gops prj new --name my-project --debug 2

导入系统到工程

gops prj import [OPTIONS]

选项:

  • -p, --path <PATH> - 系统导入路径(必填)
  • -d, --debug <LEVEL> - 调试级别
  • --log <LOG> - 日志配置
  • -f, --force <LEVEL> - 强制更新级别

功能:

  • 从指定路径导入系统配置
  • 将系统集成到当前工程
  • 自动处理系统依赖关系

示例:

# 从指定路径导入系统
gops prj import --path /path/to/system

# 详细调试导入过程
gops prj import --path /path/to/system --debug 3

更新工程

gops prj update [OPTIONS]

选项:

  • -d, --debug <LEVEL> - 调试级别
  • --log <LOG> - 日志配置
  • -f, --force <LEVEL> - 强制更新级别

功能:

  • 更新工程中的系统引用
  • 更新模块依赖关系
  • 下载远程资源

示例:

# 正常更新工程
gops prj update

# 强制更新(覆盖文件)
gops prj update --force 2

# 详细调试更新过程
gops prj update --debug 3 --log update=debug

重新导入系统

gops prj reimport [OPTIONS]

选项:

  • -d, --debug <LEVEL> - 调试级别
  • --log <LOG> - 日志配置
  • -f, --force <LEVEL> - 强制更新级别

功能:

  • 按 ops-prj.yml 记录的 sys_models 重新导入系统
  • 保留 values/ 客户值(适用于“删除了已导入系统目录、但保留了 values/ + ops-prj.yml”的场景)

示例:

gops prj reimport

模块管理命令 (gops mod)

创建示例模块结构

gops mod example [OPTIONS]

选项:

  • -d, --debug <LEVEL> - 调试级别
  • --log <LOG> - 日志配置

功能:

  • 创建完整的示例模块结构
  • 包含示例配置和工作流
  • 展示模块组织最佳实践

示例:

# 创建示例模块
gops mod example

# 创建示例模块并启用调试
gops mod example --debug 2

定义新模块操作符

gops mod new [OPTIONS]

选项:

  • -n, --name <NAME> - 模块名称(必填)
    • 支持字母数字、连字符和下划线
  • -d, --debug <LEVEL> - 调试级别
  • --log <LOG> - 日志配置

功能:

  • 使用给定名称创建新模块规范
  • 初始化模块目录结构
  • 生成所有必要的配置文件

示例:

# 创建名为 my-module 的模块
gops mod new --name my-module

# 创建模块并启用调试
gops mod new --name my-module --debug 3

更新现有模块操作符

gops mod update [OPTIONS]

选项:

  • -d, --debug <LEVEL> - 调试级别
  • --log <LOG> - 日志配置
  • -f, --force <LEVEL> - 强制更新级别

功能:

  • 更新现有模块的配置
  • 更新模块依赖关系或规范
  • 支持强制更新模式

示例:

# 正常更新模块
gops mod update

# 强制更新模块
gops mod update --force 1

# 详细调试更新过程
gops mod update --debug 3 --log mod=debug

本地化模块配置

gops mod localize [OPTIONS]

选项:

  • -d, --debug <LEVEL> - 调试级别
  • --log <LOG> - 日志配置
  • --value <PATH> - 包含环境特定值的 YAML/JSON 文件路径
  • --default - 使用内置默认值而不是用户提供的 value.yml

功能:

  • 基于环境特定值生成本地化配置文件
  • 适配不同部署环境的需求
  • 支持自定义值或默认值选择
  • 渲染 spec/ → local/ 后打印文件变更表(FILE | STATE,created / replaced):用前后内容指纹(sha256)比对,先清空 local/ 再重建不会误报未变文件,删除不报;标头为 <输出目录> ← <源模板>(如 …/local ← sys/setting/warp-fusion),区分来源

示例:

# 使用默认值本地化
gops mod localize --default

# 使用自定义值文件本地化
gops mod localize --value prod-values.yml

# 使用自定义值文件并启用调试
gops mod localize --value dev-values.yml --debug 2

展示模块值变更

gops mod diff [--json]

只读比对「模块默认值」(mod/<model>/vars.yml,来源 mod-default)与生效值,按模型列出每个键的初始值 / 生效值 / 来源 / 可变性 / 变更状态。gops mod localize 结束时也会打印同一张表。

示例:

gops mod diff
gops mod diff --json

系统管理命令 (gops sys)

创建新的系统操作符

gops sys new [OPTIONS]

选项:

  • -n, --name <NAME> - 系统名称(必填)
    • 支持字母数字、连字符和下划线
  • --kind <KIND> - 部署类型:gxl(默认)或 docker-compose;不指定时交互式选择

功能:

  • 创建新的系统规范
  • 初始化系统目录结构(kind 决定是否生成 GXL 骨架)
  • gxl:交互式选择系统型号(测试环境下设 TEST_MODE=1 自动选择)
  • docker-compose:无型号,只生成精简骨架

示例:

# 默认:GXL 系统(交互式选择型号)
gops sys new --name my-system

# 纯 docker-compose 系统
gops sys new --name gateway --kind docker-compose

# 在测试环境中创建系统
TEST_MODE=1 gops sys new --name test-system

更新系统配置

gops sys update [OPTIONS]

选项:

  • -d, --debug <LEVEL> - 调试级别
  • --log <LOG> - 日志配置
  • -f, --force <LEVEL> - 强制更新级别

功能:

  • 更新现有系统配置
  • 更新系统规范或依赖关系
  • 支持强制更新以不确认的情况下覆盖配置

示例:

# 正常更新系统
gops sys update

# 强制更新系统(跳过确认)
gops sys update --force 1

# 详细调试更新过程
gops sys update --debug 3 --log sys=debug

打包系统

gops sys package [OPTIONS]

选项:

  • -f, --force <LEVEL> - 强制更新级别
  • --output <PATH> - 输出路径(默认:父目录下 <name>-<version>.tar.gz)
  • --full - 打当前目录全部(含制品与本地化产物,用于隔离网络交付;默认只打 git 入库文件)。旧名 --no-git 仍可用(隐藏别名)

功能:

  • 先执行一次 update(解析变量、生成 sys/merged_vars.yml),保证交付包可被 gops prj import 完整导入
  • 再打包为 .tar.gz:默认只含 git 入库文件(git ls-files,等价 git archive 的“只含入库文件”,需在 git 仓库内运行),自然排除被 .gitignore 忽略的产物(sys/*/mods/、**/local、.env 等);--full 则打当前目录全部(含制品/本地化产物)
  • 两种模式都会排除 sys-prj.yml 的 ignore: 节列出的路径;deliver.lock 作为交付清单始终随包分发(不受 ignore 影响)

ignore 节(sys-prj.yml):列出打包时排除的路径模式(glob,相对系统根),即使 --full 也排除。匹配文件自身或其任一祖先目录——目录级模式(如 sys/*/mods)会排除整棵子树。模式锚定在根:裸名 mods 只匹配根级 mods,任意层级请用 **/mods;* 不跨 /,跨级用 **;前导 / 或 ./ 会被归一化(等价于不带)。

注意:模式过宽(如 *)会连 sys/merged_vars.yml 等一并排除;deliver.lock 不受影响(始终随包)。

# sys-prj.yml
ignore:
  - artifacts
  - sys/*/mods
  - '**/cache'
  - .env

示例:

# 默认:只含入库文件(不含制品)
gops sys package
# 整目录打包(含制品 / 被忽略的产物,用于隔离网络)
gops sys package --full
gops sys package --output /tmp/gateway-0.1.0.tar.gz

为环境本地化系统配置

gops sys localize [OPTIONS]

选项:

  • -d, --debug <LEVEL> - 调试级别
  • --log <LOG> - 日志配置
  • --mod <MODULE> - 只处理指定模块
  • --only - 只 localize,跳过 update(不解析/下载模块)

功能:

  • 生成 .env:sys/merged_vars.yml 默认值 ⊕ values/sys_value.yml ⊕ values/value.yml
  • 两个值文件都是可选、可部分覆盖:只写需要修改的项,其余取系统默认值
  • 默认先解析变量:gops sys localize 默认无条件先解析(等价于先跑一次 gops sys update,含解析/下载模块),因此改完 sys/setting/vars.yml 一条命令即生效;--only 跳过该步骤(用现有 sys/merged_vars.yml,缺失时会明确报错)。
  • kind: docker-compose 时,.env 供 compose 消费(默认 compose 文件为 sys/docker-compose.yaml,.env 仍在系统根)

示例:

# 生成本地化配置(默认先解析变量,再写 .env)
gops sys localize

# 只 localize,不解析/下载(用现有 merged_vars.yml;缺失则报错)
gops sys localize --only

# 只处理某个模块
gops sys localize --mod gateway

值文件说明: values/sys_value.yml 由 sys update 首次生成,整份是注释模板——取消注释需要覆盖的项即可;values/value.yml 优先级更高(覆盖层优先:value.yml > sys_value.yml > 变量定义),适合入库的客户覆盖。

localize 渲染 sys setting 模板(src → dst)后,会打印文件变更表(FILE | STATE,created / replaced),用前后内容指纹(sha256)比对:清空输出树再重建不会把内容未变的文件误报为变更,删除不报。

改了 sys/setting/vars.yml 而未重新 localize 时,gops sys check 会输出 [WARN] 提示(仅比对 .env 看不到这层陈旧)。

展示系统值变更

gops sys diff [--json]

只读比对「系统默认值」(sys/merged_vars.yml 的 system: 段,来源 sys-defaults)与生效值(⊕ values/sys_value.yml(sys-setting) ⊕ values/value.yml(customer)),只列出被覆盖的键:

列含义
KEY变量名
INITIAL初始层取值(- 表示初始层无此键)
EFFECTIVE生效值
ORIGIN生效值来自哪一层
MUTABILITY生效值可变性(merged_vars.yml 不序列化可变性,故多为 module)
STATEsame / changed / added / removed(表格只列非 same 行)

比对用未展开值(${VAR} 展开前),避免伪变更。gops sys localize 结束时也会打印同一张表(无覆盖时打 [OK] 值无覆盖)。

对 gxl 系统(有 sys/mod_list.yml),sys localize 会逐模块消费 values/<mod>/mod_value.yml,故 sys diff / localize 还按模块分组呈现 [mod: <name>](初始层 = sys/<model>/mods/<mod>/vars.yml;生效层 ⊕ values/<mod>/value.yml ⊕ values/<mod>/mod_value.yml ⊕ 系统层)。模块内容未下载时给 [WARN](先 gops sys update)。

值文件键大小写不敏感(加载时归一化为大写)。--json 为 { "system": [...], "modules": [{ "module": …, "changes": [...] }], "files": [{ "target": …, "changes": [...] }] }(只含有变更的分组)。

文件覆盖层: 除值以外,sys diff 还会列出 sys/setting/<mod>/** 相对模块 <mod>/spec/** 的新增 / 替换(localize 把两者都渲染进 local/,即「setting 覆盖了模块默认的哪些文件」);纯路径 + 内容比对,不需渲染,也不依赖上次 localize 的磁盘状态。

示例:

gops sys diff
# [sys] 值变更 (1 项):
# KEY         INITIAL      EFFECTIVE    ORIGIN    MUTABILITY  STATE
# NGINX_TAG   1.25-alpine  1.27-alpine  customer  module      changed
# [mod: warp-parse] 值变更 (1 项):
# KEY  INITIAL  EFFECTIVE  ORIGIN       MUTABILITY  STATE
# CPU  1000     2000       mod-setting  module      changed

gops sys diff --json

gops prj diff 暂不提供(prj 视角即逐系统的 sys 表)。

运行时运维命令 (gops run)

在目标系统上执行标准运维动作(算子流契约)。按 sys/sys_model.yml 的 kind 分派:gxl 系统委托 gx run <cmd>(需 gx >= 0.13.0);docker-compose 系统映射到 docker compose 子命令(无需 gx)。

gops run download    # 下载制品        compose: pull
gops run install     # 安装组件        compose: create
gops run uninstall   # 卸载组件        compose: down
gops run start       # 启动服务        compose: up -d
gops run stop        # 停止服务        compose: stop
gops run status      # 查询状态        compose: ps
gops run diagnose    # 诊断问题        compose: config(密钥掩码注入)

通用选项: --mod <MODULE>、-e, --env <ENV>(默认 default)、-d/--debug、--log。

与 gops sys(定义/交付/工件:new/update/localize/package/setting/check/diff)区分:gops run 只管「在环境里落地/运行」。

示例:

gops run start --env default
gops run status --mod nginx
gops run diagnose     # 校验并展示解析后的 compose(密钥以 ******** 掩码注入)

自升级命令 (gops self)

与 gx self 对齐,用于检查与升级 gops 自身。

查看状态

gops self status

输出当前版本、安装目录与最近一次自升级结果(state.last_remote_version / state.last_result / state.last_error)。

检查更新

# 默认 stable 通道
gops self check

# 指定通道
gops self check --channel alpha

# 机器可读输出(stdout 仅 JSON,不含版本横幅)
gops self check --channel alpha --json

升级

# 升级到通道最新版
gops self update --channel alpha

# 跳过交互确认
gops self update --channel alpha --yes

# 只演练,不实际安装
gops self update --channel alpha --dry-run

# 指定目标版本(与清单不一致时报错)
gops self update --channel alpha --to 2.1.0

# 已是最新时强制重装
gops self update --channel alpha --force

更新前会备份当前二进制;新版本 --version 健康检查失败会自动回滚。

回滚

# 回滚到最近一次备份
gops self rollback

# 指定备份 id(14 位时间戳)
gops self rollback --id 20260321123456

说明

  • 制品清单来自 galaxio-labs/get 的 updates/gops 通道,与 inst-x.sh gops <channel> 同一来源。
  • 状态、锁与备份存放于 ~/.galaxy/self_update/gops(与 gx 的同名目录隔离)。

环境变量

调试环境变量

  • TEST_MODE - 测试模式设置
    • 当设置为任意值时,启用测试环境行为
    • 在 gops sys new 中自动选择系统型号而不是交互式选择

模拟环境变量

  • MOCK_SUCCESS - 模拟成功状态
    • 用于测试环境中模拟成功的操作
    • 通常与 TEST_MODE 一起使用

配置文件结构

工程目录结构

my-project/
├── ops-prj.yml              # 工程 manifest:name + work_envs + sys_models
├── version.txt
├── _gal/                    # GXL 工程文件
├── values/                  # 客户值目录
│   └── {system-name}/
│       ├── sys_value.yml    # 值文件(只写需要覆盖的项)
│       └── value.yml        # 额外覆盖层(可选)
└── {system-name}/           # 已导入的系统目录
    └── values -> ../values/{system-name}   # 符号链接(prj import/reimport 建立)

历史:原 ops-systems.yml 已合并进 ops-prj.yml;加载时会兼容合并旧文件,保存后写入单文件。

模块目录结构

my-module/
├── mod.yml                  # 模块配置文件
├── sys/                     # 系统配置
├── workflow/                # 工作流配置
├── artifacts/               # 构建产物
├── config/                  # 配置文件
└── settings/                # 模块设置

系统目录结构

my-system/
├── sys-prj.yml              # 系统根配置
├── version.txt
├── _gal/                    # GXL 工程文件(仅 kind: gxl)
├── values/                  # 值文件目录
└── sys/
    ├── sys_model.yml        # name / model / kind / vender
    ├── docker-compose.yaml  # 系统级 compose 定义(${VAR} 占位)
    ├── mod_list.yml         # 模块列表(GXL;可选)
    ├── merged_vars.yml      # 聚合变量(sys update 生成,需入库)
    ├── workflows/           # GXL 工作流(可选)
    └── setting/
        ├── list.yml         # 可选
        └── vars.yml         # 系统设置变量定义(源)

纯 docker-compose 系统只保留 sys_model.yml、docker-compose.yaml 与 setting/vars.yml(详见 System 目录结构)。

最佳实践

工程管理

# 1. 创建新工程
gops prj new --name my-project

# 2. 导入系统到工程
gops prj import --path /path/to/system --force 1

# 3. 更新工程
gops prj update

# 4. 按 ops-prj.yml 重新导入并保留 values/
gops prj reimport

# 5. 客户差异写在 values/<system>/value.yml(只写要覆盖的项)

模块开发

# 1. 创建示例模块(学习结构)
gops mod example

# 2. 创建新模块
gops mod new --name my-module

# 3. 更新模块
gops mod update --force 2

# 4. 本地化模块配置
gops mod localize --value dev-values.yml

系统管理

# 1. 创建新系统
gops sys new --name my-system

# 2. 解析变量 / 初始化值文件
gops sys update --force 1

# 3. 本地化(生成 .env)
gops sys localize

调试技巧

# 启用详细调试
gops prj import --path /test --debug 3 --log all=debug

# 调试特定模块
gops mod update --debug 3 --log mod=debug

# 调试系统操作
gops sys update --debug 3 --log sys=debug

# 调试设置操作
gops sys setting --init --debug 2 --log setting=debug

故障排除

常见错误及解决方案

Q: 工程创建失败

错误:无法创建目录 "my-project"
解决:检查目录权限,或选择不同的名称

Q: 系统导入失败

错误:load project from ./path fail!
解决:检查路径是否正确,确保有适当的访问权限
gops prj import --path /path/to/system --debug 3

Q: 模块更新失败

错误:无法加载模块配置
解决:确保在正确的模块目录中执行命令
gops mod update --debug 3 --log mod=debug

Q: 系统创建卡在选择界面

解决:在测试环境中设置 TEST_MODE 环境变量
TEST_MODE=1 gops sys new --name test-system

Q: 设置命令在非交互模式下失败

解决:确保 sys/setting/ 目录存在,并在系统根目录执行
gops sys setting --init --debug 2

调试模式使用

# 基础调试
gops prj import --path /test --debug 1

# 详细调试
gops mod update --debug 2 --log mod=debug

# 跟踪级别调试
gops sys update --debug 3 --log sys=trace

# 跟踪级别调试(工程)
gops prj update --debug 3 --log all=debug

日志配置示例

# 调试特定模块
gops mod update --log mod=debug

# 调试多个模块
gops sys update --log sys=debug,net=info

# 设置不同级别
gops prj import --log import=debug,system=info,net=trace

# 调试所有内容
gops mod update --log all=debug

测试

项目包含完整的测试套件:

# 运行所有测试
cargo test

# 运行特定测试
cargo test test_gxops_run_success

# 运行测试并显示输出
cargo test -- --nocapture

# 在测试环境中运行
TEST_MODE=true cargo test

# 运行特定命令的测试
cargo test test_ia_setting_interactive
cargo test test_ia_setting_non_interactive

示例工作流

开发环境设置

# 1. 创建开发工程
gops prj new --name dev-project

# 2. 导入开发系统
gops prj import --path /path/to/dev-system --force 1

# 3. 更新工程依赖
gops prj update --debug 2

# 4. 写客户差异(项目值目录,只写要覆盖的项)
#    dev-project/values/dev-system/value.yml

# 5. 创建开发模块
gops mod new --name dev-module

# 6. 本地化模块配置
gops mod localize --value dev-values.yml

生产环境部署

# 1. 创建生产工程
gops prj new --name prod-project

# 2. 导入生产系统(打包产物:.tar.gz 或 git/http 地址)
gops prj import --path /path/to/prod-system-0.1.0.tar.gz --force 3

# 3. 在项目值目录里写客户差异(只写需要覆盖的项)
#    prod-project/values/prod-system/value.yml

# 4. 本地化生产配置(在系统目录内执行,自动使用项目值)
cd prod-system
gops sys localize

版本信息

当前版本:1.3.0

功能状态

命令子命令状态说明
gops prjnew✅ 完成创建维护工程
gops prjimport✅ 完成导入系统到工程(打包产物)
gops prjupdate✅ 完成更新工程
gops prjreimport✅ 完成按 ops-prj.yml 重新导入(保留 values/)
gops modexample✅ 完成创建示例模块结构
gops modnew✅ 完成定义新模块操作符
gops modupdate✅ 完成更新现有模块操作符
gops modlocalize✅ 完成本地化模块配置
gops sysnew✅ 完成创建系统(--kind gxl / docker-compose)
gops sysupdate✅ 完成解析变量、初始化值文件
gops syspackage✅ 完成先 update 再打包交付产物
gops syslocalize✅ 完成生成 .env(--only 跳过 update)
gops syssetting✅ 完成初始化系统设置
gops sysdownload/install/start/stop/uninstall/status/diagnose✅ 完成按 kind 分派(gxl→gx;docker-compose→docker compose)

许可证

本项目采用 MIT 许可证 - 详见项目根目录的 LICENSE 文件

BUILDIN

Galaxy-Ops 文档

想先了解 gops 的定位与独特价值,见 定位与价值。

gops <COMMAND>

一级命令:

  • gops mod:模块管理
  • gops sys:系统管理
  • gops prj:运维项目管理

对象模型

galaxy-ops 围绕三层对象工作:

Module -> System -> Project
  • Module:最小可复用运维单元
  • System:由多个模块组合形成的系统定义
  • Project:面向具体客户环境的交付项目

这三层分别对应当前 CLI 的三组命令:

  • gops mod ...
  • gops sys ...
  • gops prj ...

当前命令面

部署项目命令

gops prj new --name <name>
gops prj import --path <system-path>
gops prj update
gops prj reimport

gops prj reimport 按 ops-prj.yml 记录的 sys_models 重新导入系统,保留 values/ 客户值。

系统命令

# gops sys —— 定义 / 交付 / 工件
gops sys new --name <name> [--kind gxl|docker-compose]
gops sys update
gops sys package [--full]
gops sys localize [--mod <module>] [--only]
gops sys setting --init
gops sys check

# gops run —— 运行时运维(在环境里落地/运行)
gops run download [--mod <module>] [--env <env>]
gops run install [--mod <module>] [--env <env>]
gops run uninstall [--mod <module>] [--env <env>]
gops run start [--mod <module>] [--env <env>]
gops run stop [--mod <module>] [--env <env>]
gops run status [--mod <module>] [--env <env>]
gops run diagnose [--mod <module>] [--env <env>]

sys/sys_model.yml 的 kind 决定部署行为:gxl(默认)委托 gx 执行;docker-compose 直接映射到本机 docker compose。

模块命令

gops mod example
gops mod new --name <name>
gops mod update
gops mod localize [--value <file> | --default]

文档索引

对齐说明

本目录文档已经按当前 galaxy-ops 代码实现收敛为以下原则:

  • 只使用 gops 作为 CLI 入口
  • 只描述当前代码里存在的命令和对象
  • 文件树以真实生成结果为准
  • 不再保留推断型 Rust API、旧命令名和过时的架构图

GOps 定位与价值

一句话定位

gops(galaxy-ops)不是执行引擎,而是运维能力的资产化 + 组合 + 交付层:

把“一套系统交付给 N 个客户“变成有对象模型、有版本、可审计的工程流程。 执行本身仍然交给 galaxy-flow(gx)或本机 docker compose。

要解决的问题

这一节回答“为什么会有 gops“。这些问题最终都指向同一个主题:交付中“该共享的“与“该隔离的“没有被分层表达——能力、值、流程应沉淀到共享层,客户差异与运行形态应隔离到独立层;一旦混在一起,变更就会逃出版本与责任的闭环。

1. 客户环境的部署配置:时常修改、容易遗忘、后果严重

客户环境下的部署配置,是运维交付长期的重灾区:

  • 时常修改:客户环境异构、需求会变(扩容、换证书、换域名、合规),配置天生是“活的“。
  • 容易遗忘:修改发生在交付之后的现场,脱离产品版本库,没有“谁改了、改成了什么、相对默认差了多少“的记录。
  • 后果严重:配置直接驱动运行时,一个错值就是生产事故,而且往往没有回滚点。

根因:配置的三种“脱节“

脱节含义
时间脱节配置在“交付之后、运行之中“被改,脱离了产品构建时刻
空间脱节配置躺在客户环境中,脱离了产品的版本库
责任脱节产品 / 实施 / 客户运维都可能改,却没人完整拥有

三种脱节合起来,就是“配置改动逃出了版本与责任闭环“。

GOps 的应对

症状脱节GOps 机制
时常修改时间分层值文件(merged_vars 默认 ⊕ sys_value.yml ⊕ value.yml),高频改动被收敛进受控差异层
容易遗忘空间sys_value.yml 注释模板、merged_vars.yml 入库、prj reimport 保留 values/
后果严重责任配置与密钥分离(${SEC_xxx} 运行时注入)、diagnose 预校验 + 掩码、打包产物版本化可回滚

一个关键设计:values/sys_value.yml 生成时为整份注释模板——“没写“等于“用系统默认值”。于是“复制了一份默认值却忘了改“这类经典事故从根上消失:要覆盖才写,且只写差异。

边界

GOps 提供的是“让配置回到版本与责任闭环“的结构,但它不包办全部:

  • 它不强制你把 values/ 提交进 git——这仍是纪律(好在该提交的东西被压缩到极小、极明确);
  • 它不做漂移检测——有人绕过 gops 直接改现场文件,不会告警;
  • 变更审计依赖 git 提供历史。

换句话说,它把“需要人管的东西“从“整个客户环境“缩小到“几个值文件 + 一次 commit“。

2. 模块被聚合进多个系统:默认要能用、集成要能改、部署还要能再改

一个模块(如 postgresql)会被多个系统复用,而它的运行配置需要同时满足三件事:

  • 默认设定:模块自带一套能直接跑起来的默认值;
  • 系统集成时可改写:被某个系统聚合时,集成者能按该系统需要改写;
  • 部署时再次修改:到了客户现场,实施 / 客户还要能再改。

难点在于:把定制写进模块就会污染共享资产(又回到“每系统一份“的老路);而且三层改写必须有明确优先级,还要区分“哪些值允许被改、哪些不允许“。

根因:共享与定制的冲突 + 覆盖层级

  • 模块是共享资产,被 N 个系统复用;但配置需求是每个系统 / 每个客户各异的。
  • 改写点分布在三层,必须有单一、明确的优先级链。
  • 并非所有值都该被改:有些是身份 / 常量(如 app_name),必须锁死。

GOps 的应对:变量 + 可变性 + 分层覆盖点

层级拥有者载体作用
模块默认模块定义者mod/<model>/vars.yml能直接运行的默认值
系统集成覆盖系统集成者sys/setting/vars.yml → merge → sys/merged_vars.yml按系统需要改写
部署现场覆盖实施 / 客户values/sys_value.yml、values/value.yml按客户环境再改
  • 可变性(mutability):每个变量声明自己允许在哪些层被改——Immutable / System / Module。定义者用它划定“允许被改写的边界“(例如 app_name 声明为不可变)。部署时的交互式设置只遍历可变项。
  • 共享复用:模块以引用形式(ModuleSpecRef:名称 + 地址 + 模型 + 开关)被多个系统聚合,可改名、可选不同 ModelSTD,无需改动模块本体。

这样,同一模块的默认值只写一次,各系统 / 各客户的改写分别落在各自的层上,互不污染。

边界

  • 覆盖优先级的细节由运行时(orion-variate 的变量合并)决定,以实际行为为准;
  • “哪些项该在系统层改、哪些该留给客户层“仍需约定,工具不强制。

3. 同一系统需要多种部署形态:二进制 / K8S / Docker Compose

同一套系统,可能既要在客户机上以二进制(裸机 / 进程)部署,又要上 Kubernetes,还要能跑 Docker Compose。

难点:三种形态实现差异极大(进程 vs 编排 vs 容器),几乎无法复用同一份部署脚本;如果每种形态各自维护一套交付(值文件、操作命令、打包流程),就等于三份并行的运维体系——问题 1 的“时常修改、容易遗忘“会被放大三倍。而客户差异(域名、端口、规格)本应与形态无关。

根因:形态差异外溢成了交付体系的分叉

  • 形态的差异本是实现层的(怎么落地),却扩散到了交付层(值、命令、打包)。
  • 本应“一份值 + 一套命令“跨越三种形态,实际却变成三套。

GOps 的应对:分层表达形态

部署形态GOps 表达执行者
二进制(Host)kind: gxl + ModelSTD(RunSPC=Host)gx 执行模块的 host 工作流
Kuberneteskind: gxl + ModelSTD(RunSPC=K8S)gx 执行模块的 k8s 工作流
Docker Composekind: docker-compose(无 ModelSTD)本机 docker compose
  • 模块层承载“同一能力的多种落地形式“:同一模块可同时拥有 Host 与 K8S 的 mod/<model>/(不同 RunSPC),各自的 workflows/operators.gxl 提供该形态的实现。
  • 系统层选定形态:ModelSTD(Host / K8S)+ kind(gxl / compose)决定用哪种形态交付。
  • 三形态共享交付面:同一套值模型、同一个命令面(gops run start/stop/status/diagnose)、同一套打包 / 导入 / 保值流程。客户差异不随形态改变。

边界

  • 一个 System 绑定一个 ModelSTD + kind,没有“一份系统自动产出三种形态“;切换形态意味着另一个系统对象(但复用同一批模块与值定义)。
  • GOps 不做形态间的语义转换:不会把一份业务逻辑自动生成 host / k8s / compose 三份实现,各形态实现仍由模块作者分别编写;GOps 对齐的是对象、值、命令与交付流程,而非实现本身。

与开源机制的关系

“已经有 Helm / Ansible 了,为什么还要 GOps?”——先说结论:

开源机制解决的是“怎么覆盖“;GOps 想解决的是”谁来覆盖、覆盖了什么、以及别忘了“。前者是机制,后者是治理。

问题 2 拆成 7 个要求:R1 默认、R2 集成覆盖、R3 部署覆盖、R4 复用不 fork、R5 优先级链、R6 可变性、R7 记录保值。对照开源机制:

机制复用 + 多层覆盖优先级链可变性声明记录与保值跨运行时
Helm✅ chart 默认 + 覆盖 values✅❌🟡 升级可留用户 values❌ 绑 K8s
Kustomize✅ base + overlay✅❌🟡 靠 git❌ 绑 K8s
Ansible✅ role defaults + group/host vars✅ 20+ 级❌❌🟡 通用但与执行耦合
Terraform✅ module 变量 + tfvars✅❌🟡 state 非交付值❌ 面向基础设施
Nix modules✅ options + 覆盖✅✅ mkDefault/mkForce🟡❌ 整机配置范式
CUE / Jsonnet✅ 默认值 + 统一✅🟡 约束可禁覆盖❌❌ 是语言,不是交付系统

开源已解决得很好的:R1–R5(Helm 式分层 values、Ansible 式 role 复用)。GOps 的覆盖代数并不原创,本质与其同源。

开源至今的四个空白:

  1. 可变性 ≠ 所有权边界:开源工具把覆盖视为“谁在命令行传了什么“,没人把“产品 / 集成者 / 客户“表达成结构;Helm 里客户和集成者都只是传 -f,没有机制阻止客户覆盖集成者认为不可改的值。(只有 Nix 的 mkDefault / mkForce 把优先级做成了一等语义。)
  2. 交付对象模型:没有“系统 → N 个客户项目、各自维护客户值“的对象层。
  3. 记录与保值:没有工具原生提供“实际使用的值落盘入库 + 升级保护客户值“。
  4. 跨运行时统一:Helm / Kustomize 绑 K8s、Terraform 绑基础设施、Nix 绑整机,没有一套对象与覆盖链能在 host / k8s / docker compose 间共享。

GOps 的位置(诚实版):

  • 覆盖代数不是原创——可视为 Helm 式分层值 + Ansible 式复用的运维交付改写;
  • 真正补的是空白 1–4:把覆盖嵌进 Module → System → Ops Project 对象模型、用 Immutable / System / Module 把可变性变成声明式所有权边界、用 merged_vars.yml + 来源追踪做记录、用 kind 跨运行时统一;
  • 但它的可变性粒度比 Nix 粗(Nix 可对每个赋值定优先级并合并,GOps 按变量作用域分级),且闭环仍依赖 git 纪律。

有没有“满需求“的开源方案

把问题 1–3 合起来,“满需求“落在 6 个维度:

维度含义
D1 多层覆盖默认 → 集成 → 部署三级覆盖 + 优先级链 + 复用不 fork
D2 可变性 / 所有权“某值不允许在某一层被改“作为声明
D3 记录与保值实际用了什么可复现;升级不覆盖客户值
D4 密钥分离密钥不落盘、运行时注入
D5 多形态同一能力支持二进制 / K8S / Compose
D6 交付对象模型产品 → 系统 → 客户项目,含打包 / 导入闭环

主流方案对照:

方案 / 组合D1D2D3D4D5D6
Helm + GitOps(Argo/Flux) + SOPS✅❌🟡✅❌ 仅 K8s🟡
Ansible + Vault / AWX🟡 过程式❌❌✅🟡❌
Terraform / Pulumi🟡❌🟡 state🟡🟡 provider❌
Nix / Colmena✅✅ mkForce🟡🟡🟡 host 强❌
Crossplane🟡❌🟡🟡🟡 k8s 原生❌
Dagger❌❌❌🟡🟡 runner❌

结论:

  1. 单一开源项目:没有满需求的。
  2. K8s 单形态下最接近满需求的是 GitOps 栈(Git + Helm/Kustomize + SOPS/Sealed-Secrets + Argo CD/Flux):D1/D3/D4 都做到,甚至靠 reconcile 有了漂移检测;但 D2 失守(无可变性声明)、D5 失守(只服务 K8s)。
  3. 能横跨三种形态的只有 Ansible / Terraform / Pulumi,但它们是过程式 / 状态式的,没有 D6 对象模型,D2/D3 基本空白,且配置与执行耦合。
  4. 跨形态没有开源方案同时满足:要么绑死 K8s,要么退化成过程式的 Ansible。

GOps 自己也不是“满需求“:

D1D2D3D4D5D6
✅✅(粒度粗)🟡 靠 git 纪律✅🟡 需分别实现✅

它缺 GitOps 那种“强制以 Git 为真源 + 漂移检测 + 对账回滚“,也不做形态间自动转换。准确说法:开源里没有满需求,GOps 也没有;但它把“满需求“需要的维度装进了同一个对象模型,缺口集中在“强制入库 / 漂移检测 / 自动生成“。

GOps 与 GitOps 的差距

GOps 也依赖 Git,但 Git 在两边角色不同:

  • GitOps:Git 是控制回路的输入——被常驻控制器持续读取、对账、收敛。
  • GOps:Git 是版本化的载体——靠人 / CI 手动触发一次性动作。

一句话:GitOps 的 Git 驱动一个 loop,GOps 的 Git 只是仓库。

维度GitOps(Argo CD / Flux)GOps
Git 角色控制回路输入(活)协作 / 版本载体(存)
真源Git 是唯一真源,现场必须服从分层:默认来自系统产物,差异来自 values/,现场不强制收敛
执行方式常驻 controller 持续 reconcileCLI 手动 / CI 一次性触发
部署语义声明式终态(幂等 converge)可重复过程(gx workflow,未必终态)
漂移检测核心能力(OutOfSync → 自愈)无
回滚revert commit → 自动回滚重跑部署(人工)
多形态主流绑 K8s二进制 / K8S / Compose(kind)
密钥加密后仍进 Git(SOPS / Sealed-Secrets)不进 Git、不落盘,运行时注入
对象粒度manifest / release / overlayModule / System / Ops Project

三个本质差距:

  1. 有没有 reconcile loop:GitOps 有常驻控制器持续把现场拉回 Git;GOps 没有任何常驻组件,gops run start 跑完即止,不知道现场是否偏离默认值。
  2. 部署能否归约为声明式终态:GitOps 成立的前提是“期望状态可完整描述 + 幂等收敛“,这成立在容器 / 基础设施领域;二进制部署与 GXL 工作流走的是“可重复过程“,不假装是终态。
  3. 真源的权威性:GitOps 里现场是从属的,手改会被当 drift 冲掉;GOps 反而承认现场是权威之一——prj reimport 就是“重建系统、保留 values/“。两者哲学相反。

为什么二进制 / GXL 难以 GitOps 化

GitOps 需要四个前提同时成立,二进制 / host / GXL 恰好逐条违反:

前提含义二进制 / Host / GXL
终态可完整描述期望状态是一个 spec❌ 安装 / 迁移是“过程 / 历史“(数据库迁移只能按序 apply)
现实可观测能读到实际状态并与期望 diff❌ host 没有统一的“部署了什么“状态接口,系统异构
操作幂等可反复收敛而不产生副作用❌ 启动 / 迁移 / 一次性初始化不幂等;GXL workflow 是“程序“
资源可抛弃收敛 = 杀掉重建❌ 客户机器是有状态资产(数据 / license / 硬件),强收敛危险

同样是部署,Docker Compose 可以而 host 不行:

前提Docker Compose二进制 / Host
终态可完整描述✅ compose.yml❌ 安装 / 迁移是过程
可观测✅ docker compose ps❌ 无统一状态接口
幂等✅ up -d 近似幂等❌ 启动 / 迁移一次性
可抛弃✅ 容器可重建❌ 有状态资产

这也解释了为什么 GOps 的 docker-compose 形态最接近 GitOps——四个前提它占了三个半。

但并非“绝对不可能“:Puppet / Chef / Salt 证明了 host 收敛可行(装 agent + 状态模型 + 持续收敛),代价是 agent 重、OS 各异,且迁移 / 一次性步骤仍要退化成 exec / unless 这类逃逸阀。连 K8s 自己都得为非声明式步骤开逃逸阀(Helm hooks、Argo CD sync hooks、Job)——反过来说:凡是“过程“,GitOps 都得打补丁。

所以 GOps 的选择是取舍:既然四前提在二进制 / GXL 上凑不齐,就不去假装有终态收敛——部署 = 可重复的过程(GXL workflow),交给 gx;版本化的只是产物(tar.gz)+ 值(values/);它不承诺收敛,只承诺可复现与可追溯。代价是失去漂移检测与自动回滚,换来的是形态自由。

互补关系更准确:GitOps 管“收敛“,GOps 管“组织与交付“;GitOps 在单形态里做到极致,GOps 用放弃收敛换来覆盖不可收敛的世界。

独特价值

1. 三层对象模型:复用与客户差异物理隔离

Module → System → Ops Project 三层各司其职:

  • Module:最小可复用运维单元(变量 / 依赖 / 构件 / 工作流)。
  • System:由模块组合出的交付单元。
  • Ops Project:面向具体客户环境的运维项目。

同一个系统可以被多个客户项目导入,客户差异只落在 <project>/values/<system>/,不写死在系统定义里。

flowchart TD
    M["Module 最小可复用单元"] --> S["System 组合交付单元"]
    S --> P["Ops Project 客户现场"]
    S -->|gops sys package| PKG["交付包 tar.gz"]
    PKG -->|gops prj import| P
    P -->|gops prj reimport 保留 values| P

关键机制:在项目内的系统目录执行 gops sys localize / sys update 时,会依据上层 ops-prj.yml 反向解析出该项目为该系统维护的值目录,而不是使用系统自带的 values/。产品定义与客户现场在磁盘结构上天然分离。

2. 执行中立:同一命令面,两种后端

sys/sys_model.yml 的 kind 决定行为,但操作员的命令是同一套:

flowchart LR
    CMD["gops run start / stop / status / diagnose ..."] --> K{"sys_model.yml kind"}
    K -->|gxl| GX["gx run -e ENV -d N cmd"]
    K -->|docker-compose| DC["docker compose ..."]
    GX --> WF["系统工作流 GXL"]
    DC --> LOCAL["本机 docker compose"]
gops sys ...gxl 后端docker-compose 后端
downloadgx run downloaddocker compose pull
installgx run installdocker compose create
startgx run startdocker compose up -d
stopgx run stopdocker compose stop
uninstallgx run uninstalldocker compose down
statusgx run statusdocker compose ps
diagnosegx run diagnosedocker compose config

价值点:纯声明式 compose 系统(完全不依赖 gx)与模块化 GXL 工作流系统共享同一套创建、变量、打包、本地化、交付流程。

3. 多模型模块(ModelSTD):一个模块,多目标平台

ModelSTD = CpuArch × OsCPE × RunSPC,例如 x86-ubt22-k8s、arm-mac14-host、x86-ubt22-host。gops mod new 一次生成全部目标模型目录,每个模型有独立的 vars.yml / spec/ / workflows/。

即“一份模块定义,按 CPU / OS / 运行空间派生多套实现“,而不是为每个平台维护一个独立仓库。

4. 值分层 + “只写差异” + 可审计

flowchart TD
    MV["sys/merged_vars.yml 系统默认值"] --> ENV[".env"]
    SV["values/sys_value.yml 注释模板"] --> ENV
    UV["values/value.yml 客户覆盖"] --> ENV
    ENV --> DC["sys/docker-compose.yaml 消费"]
    SEC["~/.galaxy/sec_value.yml 密钥"] -->|运行时注入子进程环境| DC
  • .env = merged_vars 默认值 ⊕ values/sys_value.yml ⊕ values/value.yml
  • sys update 生成的 values/sys_value.yml 是整份注释模板:保持注释即“空覆盖“,取消注释才生效,默认值不会被钉死。
  • 优先级明确:value.yml(客户覆盖) > sys_value.yml(系统值) > merged_vars(默认)。
  • 来源可追踪:本地化会写出实际使用的值,能回答“这个最终值是谁给的“。

5. 密钥作为一等公民:不落盘、运行时注入、诊断掩码

compose 里用 ${SEC_xxx} 占位;gops run start 运行时从 ~/.galaxy/sec_value.yml(或 ./.galaxy/sec_value.yml)读取,只注入 docker compose 子进程环境,不写 .env、不入库;gops run diagnose(docker compose config)注入的是掩码值 ********。

配置与敏感值在生命周期上被彻底分开,而不是仅靠 .gitignore 约定。

6. 交付闭环:打包 → 导入 → 重导入保值

gops sys package   -> <name>-<version>.tar.gz(先 update 解析变量)
gops prj import    -> 导入客户项目
gops prj reimport  -> 按 ops-prj.yml 重建系统,保留 values/ 客户值

reimport 体现了核心主张:系统目录可被删除重建,但客户值永不丢失。产品升级与客户现场数据成为两个独立生命周期。

7. 单体 CLI,无历史包袱

一个 gops 二进制覆盖 mod / sys / prj,不存在 gmod / gsys 的历史分裂;文档以当前代码实现为唯一真源。

与常见工具的边界

工具主要职责与 GOps 的差异
Ansible过程式配置与编排执行GOps 不执行;客户差异靠值文件而非 playbook 分支
HelmKubernetes 包管理与模板GOps 跨 CPU / OS / 运行时,且含“系统 → 客户项目“对象层
Terraform基础设施状态收敛GOps 不做状态收敛,面向运维交付资产
docker compose单机声明式编排GOps 在其上加对象模型、打包、客户值、密钥、多模型

是 / 不是

是:运维能力的组织、配置、组合、交付;跨平台模块与系统的资产化;客户差异的集中管理。

不是:工作流执行引擎;配置管理 / 状态收敛工具。kind: gxl 系统的能力上限取决于 galaxy-flow / gx;kind: docker-compose 路径则把门槛降到“只要一台装了 docker 的机器“。

相关文档

GOps 改进方向

本文给出一份按“性价比“排序的改进清单。排序原则:高价值 ≠ 功能多,而是“把’靠人记住’的部分交给工具“。 因此优先做“把事后才发现变成事前就知道“的项,最后才考虑“再多一种后端 / 再多一套模板“。

“对应问题“一列指向 定位与价值 中的问题 1 / 2 / 3。每条都附现状证据,便于核对。

Tier 1:直接打痛点、代价低、收益高

改进点对应问题现状(代码证据)价值
① gops sys new --model <modelsdt>(非交互选型)采用前置ia_model_std() 只能交互;自动选型靠 TEST_MODE=1 这种 hack解锁 CI / 自动化,实现极小
② gops sys check 部署前校验问题 1(后果严重)sys localize 只导出 .env(export_env_file),不校验 sys/docker-compose.yaml 里的 ${VAR} 是否都有定义把“上线才炸“提前到“localize 前报错“
③ 密钥缺失 fail-fast问题 1(容易遗忘)run_compose_cmd 无脑 load_sec_dict() 注入,不校验被引用的 ${SEC_x} 是否存在挡住“空密码静默上线“
④ gops sys diff问题 1(容易遗忘)有值来源追踪(_used.json),但没有“客户值 vs 系统默认“的差异视图一眼看清“改了哪些、哪些还是默认“

这四条是同一主题:把“事后才发现“变成“事前就知道“——正是问题 1 的解药。

Tier 2:交付闭环与审计

改进点对应问题现状(代码证据)价值
⑤ 锁文件 / manifest问题 1、2(记录保值)merged_vars.yml 已入库,但未记录系统版本 / 模块版本 / 值哈希“部署的是哪一版、用了什么值“可复现,回滚有依据
⑥ 轻量漂移报告问题 1status / diagnose 不比对“值文件改动 vs 已生成的 .env“报“值变了但没重新 localize“,不必做完整 reconcile
⑦ values/ 提交检查(gops prj doctor 或 CI --check)问题 1无,全靠 git 纪律(定位页「边界」已承认)把“靠纪律“补成“靠工具提醒“

⑤⑥⑦ 的共同作用:把“记录与保值“从靠纪律变成靠工具提醒。

Tier 3:战略级(大投入,决定上限)

改进点对应问题现状价值
⑧ 多形态脚手架 gops sys export --form host / k8s / compose问题 3一个 System 只绑一个 ModelSTD + kind降低“同能力写三遍“的成本,哪怕只生成骨架 + 提示
⑨ 可选收敛(仅 docker-compose / k8s 形态)GitOps 缺口无常驻对账组件只在能声明终态的形态引入漂移检测 / 自愈,不放弃多形态

⑨ 是关键取舍:它补的正是 GOps 与 GitOps 的差距 里那块最短的板,同时不牺牲“覆盖不可收敛的世界“。

Tier 4:正确性 / 一致性小修(低价值但该修)

改进点现状(代码证据)
gops mod localize --value / --default 要么实现要么移除handle_localize 未读取这两个参数(声明未消费),文档已被迫标注“无效“
gops sys new 补 --debug / --logSysNewArgs 没有 debug_log,与其他命令不一致
docker-compose 形态支持 --modrun_compose_cmd 直接忽略并打印 note;可映射到 docker compose <service>
清理 todo!() 死代码ModulesList::add_mod 为 todo!();若干注释、allow(dead_code)

Tier 1 特性详述

下面把价值最高的四项(①–④)展开成可落地的设计:目标 / 现状证据 / 期望行为 / 代码落点 / 验收 / 成本。它们共享同一主题:把“事后才发现“变成“事前就知道“——也就是 问题 1 的解药。

约定:“现状证据“均以当前 galaxy-ops 代码为准;“期望行为“是设计意图,落地前需再确认实现细节。

① gops sys new --model <modelsdt>:非交互选型

目标:让 sys new 能在 CI / 脚本中无人值守创建系统,不再只能靠人肉点菜单。

现状证据

  • app/gops/commands/sys_cmd.rs::SysCommandHandler::handle_new 在 kind = gxl 分支调用 Self::ia_model_std()? 走交互选择。
  • SysNewArgs 只有 name 与 kind,没有 model;非交互只能靠 TEST_MODE 环境变量(ia_model_std / ia_kind 内部特判)这种测试后门。

期望行为

  • SysNewArgs 新增 --model <modelsdt>(取值须属于 ModelSTD::support(),如 x86-ubt22-k8s)。
  • 给定 --model 时跳过 ia_model_std,直接 SysOperator::make_new(&prj, name, model);未给定且非 TEST_MODE 时保持现有交互。
  • --model 与 --kind docker-compose 互斥:compose 系统没有 ModelSTD,组合出现时报错。
  • --model 非法时立即非 0 退出,并在 stderr 列出支持项。

代码落点

  • SysNewArgs 加字段;handle_new 中 args.model() 优先于 ia_model_std()。
  • 顺带补 --debug / --log(即 Tier 4 那项),让 configure_dfx_logging 与其他命令一致。

验收

  • 非 TTY 下 gops sys new --name demo --model x86-ubt22-k8s 成功生成系统,无 Select 提示。
  • --model bogus 退出码非 0,stderr 含支持列表。
  • 回归:无参数 + 真 TTY 时仍弹出交互选择。

成本 / 风险:S。低风险;注意 --model × --kind 的互斥校验。

② gops sys check:部署前变量校验

目标:在 localize 之后、start 之前,把“上线才炸“的未定义变量提前成一条明确报错。

现状证据

  • src/system/operator.rs::SysOperator::localize 只把合并后的值无条件写入 <sys>/.env(project::export_env_file(options.evaled_value(), env_path)),不校验 sys/docker-compose.yaml 里引用的 ${VAR} 是否都有定义。
  • 缺失时 docker compose 仅打印 The "X" variable is not set. Defaulting to a blank string. 然后带空值继续——正是“后果严重“的典型现场。

期望行为

  • 新增只读命令 gops sys check:扫描系统内 compose 文件(sys/docker-compose.{yaml,yml} 等)的插值占位
    • 形态:${VAR}、${VAR:-default}、${VAR-default}、$VAR;带 :- / - 默认值的视为可选;
    • 其余必须在“合并值字典(∪ 生成的 .env)“中存在;
    • 输出缺失清单(文件:行号 变量名),有缺失即非 0 退出。
  • 同逻辑以软校验接入 sys localize(默认仅告警;--strict 时失败),避免破坏既有流程。
  • kind: gxl 系统跳过变量校验。

代码落点

  • 直接复用 SysOperator::localize 里已算出的 options.evaled_value()(合并后的 OriginDict),无需另建变量解析。
  • 只需一个轻量 compose 插值扫描器(正则即可),与 src/project.rs::export_env_file 同族。
  • 与 diagnose(compose_subcommand → docker compose config)的区别:check 是不依赖 docker 的静态校验,能在无 docker 的 CI 机器上运行。

验收

  • 造一个引用 ${UNDEFINED} 的 compose:check 非 0 并指名到该行;在 values/sys_value.yml 补上后 check 通过。
  • ${OPTIONAL:-1} 不被判为缺失。

成本 / 风险:S–M。风险在 compose 插值语法细节($$ 转义、.env 与 shell 语义差异)——须对照官方文档,宁可漏报不可误报。

③ 密钥缺失 fail-fast

目标:挡住“空密码静默上线“。

现状证据

  • app/gops/commands/run_cmd.rs::RunCommandHandler::run_compose_cmd 无脑 orion_sec::load_sec_dict() 后 sec_env_pairs_for(cmd_name, &dict) 全量注入子进程环境,不检查 compose 文件里实际引用的 ${SEC_xxx} 是否都在 sec_dict 中。
  • sec_env_pairs_for 已知 diagnose 需要掩码(SECRET_MASK),说明“密钥注入“这一层已成型,只差一个“存在性“前置校验。

期望行为

  • 启动前交集校验:扫描 compose 的 ${SEC_*} 占位,逐一确认存在于 sec_dict;缺失则在真正启动之前报错,列出变量名与来源文件(不回显值)。
  • 提示语指向 ~/.galaxy/sec_value.yml(或 ./.galaxy/sec_value.yml)补键,但不得回显文件内容或密钥值。
  • diagnose 保持只读可运行:缺密钥时仅告警(不阻断诊断)。

代码落点

  • 与 ② 共用占位扫描器,仅筛选 SEC_ 前缀。
  • 在 run_compose_cmd 注入密钥之前插入 ensure_secrets_present(compose_files, &sec_dict) 即可。

验收

  • compose 引用 ${SEC_DB_PASSWORD} 而 sec_value.yml 无该键:start 非 0,且未真正执行 docker compose up。
  • 补键后 start 正常;diagnose 全程掩码。

成本 / 风险:S。风险:与 ② 共用扫描器,需保证只读、零副作用。

④ gops sys diff:客户值 vs 系统默认

目标:直打“容易遗忘“——一眼看清“改了哪些、哪些还是默认“。

现状证据

  • 已有值来源追踪:本地化写出 _used.json(const_vars.rs::USED_JSON)与可读版 .used_value.yml(USED_READABLE_FILE);src/project.rs::mix_used_value 会把 used ⊕ mod ⊕ global 合并。
  • 但没有“客户值 vs 系统默认“的差异视图;操作员只能肉眼比对 values/ 与 sys/merged_vars.yml。

期望行为

  • gops sys diff [--format table|yaml] [--only-changed]:以 sys/merged_vars.yml 的 system: 段为基线,逐项对 values/sys_value.yml ⊕ values/value.yml ⊕ 实际 .env 做对比,标注:
    • = 未改(取默认)、! 已覆盖、+ 客户新增键、- 系统已删但客户仍写、~ 类型/格式变化;
    • 每项附来源层(优先级 value.yml > sys_value.yml > merged_vars)。
  • 可选 --since <git-ref>:展示相对某提交的值变化(借 git 历史)。
  • 纯读命令,不改任何文件。

代码落点

  • 基线取 merged_vars.yml 的 system: 段 + 模块默认;覆盖层取 values/。
  • 若当前合并(mix_used_value)未保留“哪一层给的“信息,需要先让合并结果带上来源(不改变落盘格式)。

验收

  • 默认值 + 一处覆盖:diff 仅把该一处标为 !,其余标 =。
  • 删除一个客户键:显示 -(已回落默认),而非静默。

成本 / 风险:M。风险:需要“默认层“与“覆盖层“同时可见,可能触及值的合并表示(但不动落盘格式)。

后续(Tier 2 / 3)

⑤ 锁文件 / manifest、⑥ 轻量漂移报告、⑦ values/ 提交检查、⑧ 多形态脚手架、⑨ 可选收敛,留待下一轮展开。其中 ⑧ 的一部分已兑现:gops mod new 现已为 x86-ubt22-k8s 生成 Helm chart 脚手架(见 模块维护器)。

如果只做三件事

  1. gops sys new --model —— 解锁 CI / 自动化,门槛最低。
  2. gops sys check 部署前校验 —— 变量 + 密钥占位双校验,直打“后果严重“。
  3. gops sys diff —— 直打“容易遗忘“,且能作为对外卖点。

这三条合起来,正好把问题 1 的三个症状(时常修改 / 容易遗忘 / 后果严重)各自对应上一个可交付的功能,且都不动核心架构。

一个判断

按定位页的逻辑,高价值 ≠ 覆盖更多。所以 ①–⑦ 排在前面,把“再多一种部署后端““再写一套模板“这类排在最后——后者只会扩大覆盖,不会降低遗忘与事故。

说明:本文是改进建议,不是当前能力的描述;每条“现状“以现有代码为准,落地前需再次确认实现细节。

System Operator 指南

概述

在当前 galaxy-ops 实现里,系统通过 gops sys 管理,不存在独立的 gsys CLI。

System 是模块之上的组合层。它负责:

  • 维护系统模型定义(含部署类型 kind)
  • 维护模块列表(GXL 类型)
  • 维护系统级设置和值
  • 生成 .env 等本地化产物
  • 提供下载、安装、启动、停止、状态、诊断等系统操作入口

当前命令

# gops sys —— 定义 / 交付 / 工件
gops sys new --name <name> [--kind gxl|docker-compose]
gops sys update [--force]
gops sys package [--force] [--output <path>] [--full]
gops sys localize [--mod <module>] [--only]
gops sys setting --init
gops sys check

# gops run —— 运行时运维(在环境里落地/运行)
gops run download [--mod <module>] [--env <env>]
gops run install [--mod <module>] [--env <env>]
gops run uninstall [--mod <module>] [--env <env>]
gops run start [--mod <module>] [--env <env>]
gops run stop [--mod <module>] [--env <env>]
gops run status [--mod <module>] [--env <env>]
gops run diagnose [--mod <module>] [--env <env>]

部署类型(kind)

sys/sys_model.yml 的 kind 字段决定 gops run 的行为(kind 缺省时按 gxl 处理,兼容 1.2.0 及更早的系统):

  • gxl:部署命令委托外部 gx 执行,要求 sys/workflows/operators.gxl 与可用的 gx。映射为 gx run -e <ENV> -d <N> [--cmd-arg <MOD>] <cmd>;gx 取自 $HOME/bin/gx,最低版本 0.13.0。

  • docker-compose:部署命令直接映射到 docker compose,无需 gx(--mod 参数会被忽略):

    gops sys ...docker compose ...
    downloadpull
    installcreate
    startup -d
    stopstop
    uninstalldown
    statusps
    diagnoseconfig

创建系统

gops sys new --name web-stack                       # 不指定 --kind:交互式选择部署类型,选 gxl 后再选择系统型号
gops sys new --name gateway --kind docker-compose   # 纯 compose(无型号)

--kind 缺省时会在终端交互式选择部署类型(TEST_MODE 下直接按 gxl 处理);gxl 还需要再交互选择 ModelSTD。

两种类型生成的结构不同,见 目录结构。

关键文件

  • sys-prj.yml:系统对象根配置
  • sys/sys_model.yml:系统模型定义(name / model(gxl 必填)/ kind / vender)
  • sys/mod_list.yml:模块列表(GXL;纯 compose 可省略)
  • sys/setting/vars.yml:系统设置变量定义(源)
  • sys/setting/list.yml:按模块的本地化列表(可选)
  • sys/merged_vars.yml:聚合变量(sys update 生成:模块变量 ⊕ 系统变量,需入库)
  • sys/workflows/operators.gxl:系统级工作流(GXL)
  • values/sys_value.yml:值文件(sys update 生成注释模板,取消注释即覆盖)
  • values/value.yml:额外覆盖层(适合入库的客户覆盖)
  • sys/docker-compose.yaml:系统级 compose 定义(用 ${VAR} 占位;放在系统根(旧布局)仍受支持)
  • .env:sys localize 生成的非密钥配置(供 compose 消费)

值 / 本地化流程

gops sys update   -> sys/merged_vars.yml(系统默认值)+ values/sys_value.yml(注释模板)
gops sys localize -> .env = merged_vars 默认值 ⊕ values/sys_value.yml ⊕ values/value.yml

两个值文件都是可选、可部分覆盖:只写需要修改的项,其余取系统默认值。保持注释模板原样时等价于空覆盖。

sys localize 默认总是先解析变量(等价于先跑一次 update,含解析/下载模块),再生成 .env;--only 跳过解析(用现有 sys/merged_vars.yml,缺失则明确报错)。

密钥

密钥不写入 .env:在 sys/docker-compose.yaml 里用 ${SEC_xxx} 占位,gops run start 运行时从 ~/.galaxy/sec_value.yml(或当前目录 ./.galaxy/sec_value.yml)读取并注入子进程环境(key 会归一化为大写并加 SEC_ 前缀)。gops run diagnose(docker compose config)只读校验,注入的是掩码值 ********。详见 galaxy-ops 仓库的 src/system/README.md。

常见流程

更新系统本地引用

gops sys update
gops sys update --force

本地化系统

gops sys localize            # 默认先解析变量(等价于先 update),再生成 .env
gops sys localize --only     # 只 localize,不解析/下载模块(用现有 merged_vars.yml)
gops sys localize --mod nginx

打包交付

gops sys package             # 先 update 再打包 → ../<name>-<version>.tar.gz

初始化系统设置

gops sys setting --init

执行系统操作

gops run start --env default
gops run status --env default

与模块和项目的关系

gops mod new      -> 创建模块
gops sys new      -> 组合模块形成系统
gops prj new      -> 创建运维项目
gops prj import   -> 把系统导入项目
gops prj reimport -> 按 ops-prj.yml 重新导入(保留 values/)
gops prj update   -> 同步项目本地引用

导入到运维项目后,项目值放在 <project>/values/<system>/。在项目内的系统目录执行 gops sys localize / gops sys update 时,会依据上层 ops-prj.yml 直接使用该项目值目录,不依赖 <sys>/values 符号链接是否完整。

现实边界

  • gxl 系统的工作流执行仍依赖 gx
  • docker-compose 系统只依赖本机 docker compose,不需要 gx

sys_model.yml 说明

sys_model.yml 是 System 对象的核心定义文件,位于:

sys/sys_model.yml

字段

gxl 系统实际生成的内容(kind 为默认值 gxl 时会被省略,不写入文件):

name: web-stack          # 系统名(必填)
model: arm-mac14-host    # 目标型号(kind=gxl 必填;docker-compose 无型号)
vender: ''               # 供应商标记(可选)

字段含义:

  • name:系统名(必填)
  • kind:部署类型:gxl(默认)| docker-compose;gxl 是默认值,序列化时省略
  • model:目标型号(kind=gxl 必填,写入文件;docker-compose 无型号,字段省略)
  • vender:供应商标记(可选)

纯 docker-compose 系统的实际内容示例:

name: gateway
kind: docker-compose
vender: ''

kind

kind 决定 gops sys 的行为:

kind说明
gxl(默认)模块式系统,部署命令委托外部 gx 执行
docker-compose声明式 compose 系统,部署命令直接映射到 docker compose(无需 gx)
  • kind 缺省时按 gxl 处理(兼容 1.2.0 及更早的系统)
  • kind 只在此文件里声明,不要写进 sys-prj.yml

与其它文件的关系

  • sys/mod_list.yml:模块列表(仅 gxl 需要)
  • sys/setting/vars.yml:系统设置变量定义(源)
  • sys/merged_vars.yml:gops sys update 解析出的聚合变量(需入库)

在流程中的作用

  • gops sys new 会初始化它;--kind docker-compose 会写入 kind: docker-compose 且不生成 GXL 骨架
  • gops run 的部署命令按 kind 分派
  • gops prj import / prj reimport 用它确定系统名与类型

如果要核对字段细节,优先以当前仓库代码和 gops sys new 的生成结果为准,而不是旧版文档示例。

System 示例:多模块系统

这里给出一个和当前实现一致的最小示例流程,用来说明 System 如何组合多个模块。

1. 创建模块

gops mod new --name gateway
gops mod new --name user-service
gops mod new --name postgres

2. 创建系统

gops sys new --name microservice-stack
cd microservice-stack

3. 维护系统模块列表

在 sys/mod_list.yml 中把需要的模块加入系统。

4. 初始化系统设置(可选)

gops sys setting --init

5. 解析变量并本地化

gops sys update      # 解析变量 -> sys/merged_vars.yml,并生成 values/sys_value.yml(注释模板)
gops sys localize    # 生成 .env(默认先解析变量,等价于先 update)

如果只想处理某个模块:

gops sys localize --mod gateway

值文件采用“只写差异”的风格:

# values/sys_value.yml —— 整份默认是注释,取消注释即覆盖
HTTP_PORT: 8081

也可以在同目录放 values/value.yml 作为额外覆盖层(优先级最高,适合入库的客户覆盖)。

6. 打包交付

gops sys package     # -> ../microservice-stack-<version>.tar.gz

7. 在运维项目中使用(客户差异)

cd ..
gops prj new --name customer-a
cd customer-a
gops prj import --path ../microservice-stack-0.1.0.tar.gz
cd microservice-stack
gops sys localize    # 值取自 <project>/values/microservice-stack/

8. 执行系统操作

gops run download --env default
gops run install --env default
gops run start --env default
gops run status --env default

说明

这个示例强调的是当前实现中的责任边界:

  • 模块定义在 gops mod
  • 系统组合在 gops sys
  • 客户导入和交付在 gops prj

System 示例:纯 docker-compose 系统

纯 compose 系统不组合模块、不使用 GXL 工作流,gops sys 直接驱动本机 docker compose。

1. 创建系统

gops sys new --name gateway --kind docker-compose
cd gateway

生成的是精简结构(无 _gal/、mod_list.yml、workflows/、setting/list.yml),见 目录结构。

sys/sys_model.yml:

name: gateway
kind: docker-compose
vender: ''

2. 编写 compose 与变量定义

sys/docker-compose.yaml 用 Docker Compose 原生 ${VAR} 占位(sys new 会生成一份可修改的模板):

services:
  app:
    image: ${SERVICE_IMAGE}
    ports:
      - "${SERVICE_PORT}:80"
    deploy:
      replicas: ${REPLICAS}

compose 文件默认位于 sys/,也兼容放在系统根(旧布局)。无论文件在哪,compose 项目目录都锚定系统根,${VAR} 由系统根的 .env 注入。

非密钥变量在 sys/setting/vars.yml 的 system: 段声明(源定义,随系统版本化):

system:
  - name: SERVICE_IMAGE
    value: nginx:alpine
  - name: SERVICE_PORT
    value: 8080
  - name: REPLICAS
    value: 1

密钥不要写在这里:在 compose 里用 ${SEC_xxx} 占位,运行时由 gops run start 从 ~/.galaxy/sec_value.yml(或当前目录 ./.galaxy/sec_value.yml)注入(不落盘)。

services:
  db:
    environment:
      POSTGRES_PASSWORD: ${SEC_POSTGRES_PASSWORD}

~/.galaxy/sec_value.yml(不在项目里、不入库):

postgres_password: "your-secret"

key 会归一化为大写并加 SEC_ 前缀:postgres_password → SEC_POSTGRES_PASSWORD。

3. 生成 .env

gops sys localize        # 默认先解析变量(等价于先 update),再生成 .env
cat .env

规则:

.env = sys/merged_vars.yml 默认值 ⊕ values/sys_value.yml ⊕ values/value.yml
  • values/sys_value.yml 是 sys update 生成的注释模板:取消注释要覆盖的项即可,其余取默认值。
  • values/value.yml 是更高优先级的覆盖层。

例如只想改端口与副本数:

# values/sys_value.yml
SERVICE_PORT: 9090
REPLICAS: 3

.env 只包含非密钥配置,随时可以用 docker compose config 校验。

4. 部署

kind: docker-compose 下,部署命令映射到 docker compose:

gops run diagnose    # docker compose config(密钥以 ******** 掩码注入)
gops run download    # docker compose pull
gops run install     # docker compose create
gops run start       # docker compose up -d(密钥注入子进程环境)
gops run status      # docker compose ps
gops run stop        # docker compose stop
gops run uninstall   # docker compose down

kind: docker-compose 下 --mod 参数会被忽略(没有模块概念);--env 仍可传入。

5. 交付给客户(运维项目)

gops sys package                          # 先 update 再打包 -> ../gateway-<version>.tar.gz
cd ..
gops prj new --name customer-a
cd customer-a
gops prj import --path ../gateway-0.1.0.tar.gz
cd gateway
gops sys localize                         # 使用 <project>/values/gateway/ 下的客户值
gops run start

客户差异写在 <project>/values/gateway/(例如 value.yml)。在项目内的系统目录执行 gops sys localize / sys update 时,会依据上层 ops-prj.yml 直接使用该项目值目录。

System 目录结构

本文档以当前 gops sys new 的真实生成结果为准。系统有两种部署类型,目录结构不同。

GXL 系统(默认)

gops sys new --name <name>
<system-root>/
├── .gitignore
├── sys-prj.yml              # 系统根配置
├── version.txt
├── _gal/                    # GXL 工程目录
│   ├── adm.gxl
│   ├── project.toml
│   └── work.gxl
├── values/                  # 值文件目录(本地化输入)
└── sys/
    ├── .gitignore
    ├── sys_model.yml        # name / model / vender(kind 缺省 = gxl)
    ├── docker-compose.yaml  # sys new 默认生成的 compose 定义(用 ${VAR} 占位)
    ├── mod_list.yml         # 模块列表
    ├── workflows/
    │   └── operators.gxl
    └── setting/
        ├── list.yml
        └── vars.yml

纯 docker-compose 系统

gops sys new --name <name> --kind docker-compose
<system-root>/
├── .gitignore
├── sys-prj.yml
├── version.txt
└── sys/
    ├── sys_model.yml        # name / kind: docker-compose / vender
    ├── docker-compose.yaml  # 系统级 compose 定义
    └── setting/
        └── vars.yml

compose 类型不生成 _gal/、values/、mod_list.yml、workflows/、setting/list.yml。

compose 文件默认位于 sys/,gops sys 按 sys/compose.{yaml,yml} → sys/docker-compose.{yaml,yml} → 系统根同名文件的顺序查找。无论文件在哪,compose 项目目录都锚定系统根(项目名 = 根目录名,相对挂载路径与 .env 均相对系统根)。把文件放在系统根(旧布局)仍受支持:此时 gops 不加 -f,交由 docker 自动发现(docker-compose.override.yml 自动合并、COMPOSE_FILE 环境变量继续生效);sys/ 布局下由 gops 显式合并 <sys>/<stem>.override.{yaml,yml}。

运行时生成的文件

gops sys update / gops sys localize 会在需要时补齐:

  • sys/merged_vars.yml:聚合变量(模块 ⊕ 系统),需入库
  • values/sys_value.yml:值文件(注释模板;取消注释需要覆盖的项即可)
  • values/setting/mod_value.yml:本地化辅助值文件
  • .env:sys localize 导出的非密钥配置(供 compose 消费)

可选文件

下列文件缺失时按空处理,纯 compose 系统可以完全不提供:

  • sys/mod_list.yml
  • sys/workflows/
  • sys/setting/list.yml

现实说明

旧文档里常见的这些内容,不应再视为当前最小骨架的一部分:

  • sys/vars.yml
  • sys/<model>/mods/(由 gops sys update 生成,不是初始结构)
  • test_res/
  • 独立 gsys CLI 生成目录

System 文件组织

系统围绕下面几类文件组织。其中 _gal/、mod_list.yml、workflows/、setting/list.yml 只属于 GXL 类型(见 目录结构)。

根目录文件

  • sys-prj.yml:系统根配置
  • version.txt:版本标记
  • .gitignore

_gal/(仅 GXL 系统)

  • adm.gxl:管理流程入口
  • work.gxl:执行流程入口
  • project.toml:GXL 工程配置

sys/

  • sys_model.yml:系统模型定义(name / model / kind / vender)
  • docker-compose.yaml:系统级 compose 定义(sys new 默认生成,用 ${VAR} 占位;放在系统根(旧布局)仍受支持)
  • mod_list.yml:模块列表定义(GXL;可选)
  • merged_vars.yml:聚合变量(sys update 生成,需入库)
  • setting/list.yml:设置列表(可选)
  • setting/vars.yml:设置变量定义(源)
  • workflows/operators.gxl:系统操作工作流(GXL;可选)

values/(本地化输入)

  • sys_value.yml:值文件。sys update 首次生成的是注释模板(可用变量全部以注释列出),取消注释需要覆盖的项即可;保持注释的项取系统默认值。
  • value.yml:额外覆盖层,优先级最高(适合入库的客户覆盖)。
  • setting/mod_value.yml、<mod>/mod_value.yml:本地化辅助值文件。

.env

gops sys localize 生成的非密钥配置(KEY=VALUE),供 docker compose 消费。密钥不写入 .env。compose 项目目录锚定系统根,因此 .env 位于系统根(而非默认的 sys/)。

文件职责与本地化

.env = sys/merged_vars.yml 默认值 ⊕ values/sys_value.yml ⊕ values/value.yml

后两者都是可选、可部分覆盖:只写需要修改的项,其余取系统默认值。

  • sys_model.yml:描述系统本身(含 kind),属于系统对象定义层
  • mod_list.yml:描述系统包含哪些模块,属于系统组合层
  • setting/vars.yml / setting/list.yml:系统设置层
  • merged_vars.yml:已解析的聚合变量(系统默认值的来源)
  • operators.gxl:工作流层

当前 CLI 与文件关系

  • gops sys new:初始化文件骨架(按 kind 决定是否生成 GXL 骨架)
  • gops sys update:解析变量 → sys/merged_vars.yml,并初始化 values/
  • gops sys package:先 update 再打包为 <name>-<version>.tar.gz
  • gops sys localize:按上述规则生成 .env
  • gops sys setting --init:初始化系统设置相关文件

不再使用的旧说法

  • SYS_BIN = "gsys" / MOD_BIN = "gmod"(GXL 模板中已改为 "gops sys" / "gops mod")
  • “系统级 vars.yml 必然位于 sys/ 根目录”
  • “sys/mods/ 是固定初始结构”(模块现在按目标模型分组到 sys/<model>/mods/<mod>/,由 gops sys update 生成)
  • “系统变量文件叫 sys/sys_vars.yml”(已重命名为 merged_vars.yml,旧名仅作读取兼容)

System 命名约定

系统目录

系统通过下面命令创建:

gops sys new --name <name> [--kind gxl|docker-compose]

建议:

  • 使用小写字母
  • 单词之间使用连字符
  • 避免空格和中文目录名

示例:

  • web-stack
  • customer-edge
  • db-core

文件名

当前实现里关键文件名是固定的:

  • sys-prj.yml
  • sys/docker-compose.yaml
  • sys_model.yml
  • mod_list.yml
  • merged_vars.yml
  • operators.gxl
  • list.yml
  • vars.yml
  • values/sys_value.yml、values/value.yml

这些名字最好不要随意改动,否则会影响 gops sys 的加载逻辑。

sys_vars.yml 是 merged_vars.yml 的旧名(1.2.0 及更早),当前仅作读取兼容。

kind 取值

sys/sys_model.yml 的 kind 只使用这两个值(省略时按 gxl):

  • gxl
  • docker-compose

模块名

系统命令里如果使用:

gops sys localize --mod <module>
gops run start --mod <module>

这里的 <module> 应与 mod_list.yml 中声明的模块名一致。

环境名

系统操作命令支持:

--env <env>

当前默认值是:

default

建议环境名保持简单稳定,例如:

  • default
  • dev
  • staging
  • prod

System 常见问题

1. gops sys new 卡在选择系统型号

原因:

  • kind: gxl 的系统会交互选择 ModelSTD

建议:

  • 正常在交互终端选择
  • 自动化测试场景可设置 TEST_MODE=1
  • 不需要型号的纯 compose 系统用 gops sys new --kind docker-compose(不询问型号)

2. gops sys setting --init 没有生成预期文件

确认点:

  • 当前目录必须是系统根目录
  • sys/setting/ 目录是否存在

3. gops sys localize 失败

常见原因与报错:

  • 系统变量未解析:缺少 .../sys/merged_vars.yml → 先执行 gops sys update 解析变量;或去掉 --only,让 localize 自动先 update。
  • sys_model.yml 缺失
  • 值文件内容不是合法 YAML (提示:全注释 / 空文件会被视为空覆盖,不会报错)

建议:

gops sys localize --debug 2

先打开调试输出定位是哪一层配置缺失。

4. 值文件写了却没生效

确认点:

  • values/sys_value.yml 里对应的行已取消注释——sys update 生成的是整份注释模板,保持注释等价于空覆盖
  • 优先级:values/value.yml > values/sys_value.yml > sys/merged_vars.yml 的系统默认值
  • 在运维项目内执行时,值来自 <project>/values/<system>/(依据上层 ops-prj.yml 解析),而不是系统自带的 <sys>/values

5. 日志出现 unexpanded variable in localize path 且本地化被跳过

原因:sys/setting/list.yml 里的路径模板引用了未设置的变量(常见是 ${GXL_PRJ_ROOT})。

说明:

  • GXL_PRJ_ROOT 由 gops 进程启动时按当前目录向上查找 _gal/project.toml 设置一次
  • 路径里仍残留 ${...} 时会告警并跳过;不会再创建字面量 ${...} 目录

建议:确认是在系统目录内执行,且该目录(或其上层)存在 _gal/project.toml。

6. download/install/start 等系统命令失败

分两种情况(由 sys/sys_model.yml 的 kind 决定):

  • kind: gxl:最终依赖系统工作流和 gx
    • 先确认 sys/workflows/operators.gxl 存在
    • 再确认 gx 可执行:gops 使用 $HOME/bin/gx,且要求版本 >= 0.13.0
    • 实际映射为 gx run -e <env> -d <debug> [--cmd-arg <mod>] <cmd>,检查 --env 与 --mod 传参
  • kind: docker-compose:直接调用本机 docker compose
    • 确认 docker compose 可用
    • 确认 .env 已生成(gops sys localize)
    • --mod 会被忽略(纯 compose 系统没有模块)

7. docker compose 报变量未定义

确认点:

  • 已执行 gops sys localize 生成 .env
  • .env 位于系统根;compose 文件默认在 sys/(项目目录锚定系统根,${VAR} 由系统根的 .env 注入)
  • 密钥类变量用 ${SEC_xxx} 占位,由 gops run start 从 ~/.galaxy/sec_value.yml 注入;直接用 docker compose up 不会自动注入密钥

8. 文档和目录树不一致

处理原则:

  • 以当前 gops sys new 真实生成结果为准
  • 以当前仓库代码为准
  • 不再使用旧版 gsys 文档作为依据

Module Operator 指南

概述

在当前 galaxy-ops 实现里,模块通过 gops mod 管理,不存在独立的 gmod CLI。

Module 是最小可复用运维单元。它负责沉淀:

  • 模块变量
  • 模块依赖
  • 模块构件
  • 模块工作流
  • 模块本地化输出

模块本身不直接面向客户交付,它先被组合成 System,再由 Ops Project 导入和交付。

当前命令

gops mod example
gops mod new --name <name>
gops mod update
gops mod localize [--value <file> | --default]

典型工作流

1. 创建模块

gops mod new --name nginx

当前实现会在目标目录下生成类似结构:

nginx/
├── .gitignore
├── version.txt
├── mod-prj.yml
├── _gal/
│   ├── adm.gxl
│   ├── project.toml
│   └── work.gxl
└── mod/
    ├── arm-mac14-host/
    │   ├── vars.yml
    │   ├── _gal/work.gxl
    │   ├── spec/
    │   │   ├── artifact.yml
    │   │   └── depends.yml
    │   └── workflows/
    │       └── operators.gxl
    ├── x86-ubt22-host/        # 结构同 arm-mac14-host
    └── x86-ubt22-k8s/         # 结构同 arm-mac14-host

注意:

  • 当前骨架一定会生成 mod-prj.yml
  • 当前骨架会按支持的 ModelSTD 生成 mod/<model>/...;gops mod new 默认生成三个模型目录:arm-mac14-host、x86-ubt22-host、x86-ubt22-k8s
  • 每个 mod/<model>/ 下会直接生成 vars.yml、spec/artifact.yml、spec/depends.yml、workflows/operators.gxl 与 _gal/work.gxl
  • setting.yml 不在 gops mod new 的初始骨架中(仅 gops mod example 会带);初始模板比较轻,后续通过 update / localize / 手工补充逐步完善

2. 更新模块本地引用

gops mod update
gops mod update --force 2

update 主要用于同步依赖、本地引用和相关生成内容。--force 支持不同强度的覆盖策略。

3. 本地化模块

gops mod localize

localize 会读取模块根目录下 values/<model>/ 里的值文件(sys_value.yml、mod_value.yml)生成本地化结果(mod/<model>/local/),用于后续系统组合或实际交付。

说明:gops mod localize 虽然声明了 --value / --default 参数,但当前实现并未消费它们,实际值来自 values/<model>/。

模块在整体分层中的位置

gops mod   -> 定义和维护模块
gops sys   -> 组合模块形成系统
gops prj   -> 导入系统形成具体交付项目
galaxy-flow -> 执行工作流

文档索引

Module Operator 开发流程

当前开发入口

模块开发从 gops mod 开始,而不是 gmod。

gops mod new --name <module-name>

推荐流程

1. 创建模块骨架

mkdir demo-work && cd demo-work
gops mod new --name postgresql
cd postgresql

2. 补齐模块模型内容

先检查 mod/ 下生成的模型目录(gops mod new 默认生成三个):

mod/
├── arm-mac14-host/
├── x86-ubt22-host/
└── x86-ubt22-k8s/

每个模型目录已包含以下文件,按需修改即可:

  • vars.yml
  • spec/artifact.yml
  • spec/depends.yml
  • workflows/operators.gxl
  • _gal/work.gxl

setting.yml 不在 gops mod new 的初始骨架中,需要自定义本地化行为时再手工补充。

3. 更新本地引用

gops mod update

需要强覆盖时:

gops mod update --force 2

4. 本地化验证

先准备好值文件(gops mod update 会在模块根生成 values/<model>/ 下的模板):

values/
└── x86-ubt22-k8s/
    ├── sys_value.yml
    └── mod_value.yml

然后执行本地化:

gops mod localize

本地化会读取 values/<model>/ 生成 mod/<model>/local/。

--value / --default 参数虽然可用,但当前 gops mod localize 实现并未消费它们;实际值始终来自 values/<model>/。

5. 进入系统组合

模块完成后,通常不直接交付,而是继续:

gops sys new --name demo-system

把模块纳入系统对象中。

调试参数

当前模块命令统一支持调试参数:

gops mod new --name nginx --debug 1
gops mod update --debug 2 --log debug
gops mod localize --debug 3

现实边界

当前实现里,模块开发流程要注意几点:

  • gops mod new 生成的是模板骨架,业务文件仍需按需修改
  • localize 依赖 values/<model>/ 下的值文件和 vars.yml 变量定义,先补齐 vars.yml 再做本地化
  • 模块是系统的输入,不是交付终点
  • 执行类工作流能力最终仍由 galaxy-flow / gx 承担

Module Operator 配置说明

本文档只描述当前 galaxy-ops 代码中已经存在的模块配置对象和文件名。

核心文件

创建模块后,当前实现会生成这些关键文件:

<module-root>/
├── .gitignore
├── mod-prj.yml
├── version.txt
├── _gal/
│   ├── adm.gxl
│   ├── project.toml
│   └── work.gxl
└── mod/
    └── <model>/
        ├── vars.yml
        ├── _gal/work.gxl
        ├── spec/
        │   ├── artifact.yml
        │   └── depends.yml
        └── workflows/
            └── operators.gxl

运行 gops mod update / gops mod localize 后,模块目录还会出现这些约定目录或文件:

  • mod/<model>/local/:gops mod localize 生成的本地化输出
  • mod/<model>/_used.json:gops mod localize 生成的实际使用值
  • values/<model>/sys_value.yml、values/<model>/mod_value.yml:值文件(注意在模块根 values/ 下,不在 mod/<model>/ 里)
  • values/<model>/.used_value.yml:本地化时导出的可读值
  • mod/<model>/setting.yml:本地化行为设置(可选;gops mod new 不生成,gops mod example 或手工补充时才有)

这些名字来自当前代码常量:

  • spec/
  • artifact.yml
  • depends.yml
  • setting.yml
  • values/
  • workflows/
  • local/

文件职责

mod-prj.yml

模块项目根配置。它是模块对象的入口配置文件,ModOperator::load / save 都围绕它工作。

_gal/adm.gxl

管理类工作流入口。

_gal/work.gxl

执行类工作流入口。

_gal/project.toml

当前生成模板里的 GXL 工程配置文件。

mod/<model>/vars.yml

某个 ModelSTD 下的模块变量定义。当前模块骨架至少会生成这个文件。

mod/<model>/spec/artifact.yml

模块构件定义,通常用于描述下载资源、源码包或依赖包。

mod/<model>/spec/depends.yml

模块依赖定义,用于组织本地依赖、仓库依赖或附加资源。

mod/<model>/setting.yml

模块本地化行为相关设置(可选,gops mod new 不生成)。

values/<model>/

模块值文件目录(位于模块根目录下,不是 mod/<model>/values/)。gops mod update 会在此生成 sys_value.yml 与 mod_value.yml,gops mod localize 会读取它们执行本地化。

mod/<model>/workflows/

模块工作流目录,通常放模块级 operators.gxl 等流程文件。

mod/<model>/local/

模块本地化结果或局部输出目录。

ModelSTD 目录

模块目录下按模型拆分。ModelSTD 当前支持三种组合(gops mod new 会全部生成):

  • arm-mac14-host(CpuArch::Arm + OsCPE::MAC14 + RunSPC::Host)
  • x86-ubt22-host(CpuArch::X86 + OsCPE::UBT22 + RunSPC::Host)
  • x86-ubt22-k8s(CpuArch::X86 + OsCPE::UBT22 + RunSPC::K8S)

模型名由 ModelSTD 决定,表示 CPU / OS / 运行空间组合(来自 CpuArch / OsCPE / RunSPC 三个枚举)。

当前配置边界

当前代码里,模块配置的真实边界是:

  • 模块根配置:mod-prj.yml
  • 模型级配置:mod/<model>/...(vars.yml / spec/ / workflows/ / _gal/work.gxl)
  • 值文件和本地化输出:模块根 values/<model>/ 与模型内 mod/<model>/local/
  • 工作流入口:_gal/*.gxl 与 workflows/operators.gxl

不要再按旧文档理解为独立 gmod 工具或多套历史模板系统。

Module Operator 参考

CLI 参考

gops mod

gops mod <COMMAND>

子命令:

  • example
  • new
  • update
  • localize

gops mod new

gops mod new --name <NAME> [--debug <0..3>] [--log <level>]

gops mod update

gops mod update [--debug <0..3>] [--log <level>] [--force <0..3>]

--force 当前含义:

  • 0:正常
  • 1:跳过确认
  • 2:覆盖文件
  • 3:强制拉取

gops mod localize

gops mod localize [--value <file>] [--default]

注意:--value / --default 参数已声明,但当前实现未消费;实际值来自模块根 values/<model>/ 下的值文件。

目录参考

最小模块骨架

gops mod new 按支持的 ModelSTD 生成三个模型目录(arm-mac14-host / x86-ubt22-host / x86-ubt22-k8s),每个模型结构相同:

<module>/
├── .gitignore
├── version.txt
├── mod-prj.yml
├── _gal/
│   ├── adm.gxl
│   ├── project.toml
│   └── work.gxl
└── mod/
    └── <model>/
        ├── vars.yml
        ├── _gal/work.gxl
        ├── spec/
        │   ├── artifact.yml
        │   └── depends.yml
        └── workflows/
            └── operators.gxl

运行 / 本地化后新增

<module>/
├── values/
│   └── <model>/
│       ├── sys_value.yml
│       ├── mod_value.yml
│       └── .used_value.yml
└── mod/<model>/
    ├── local/                 # gops mod localize 输出
    ├── _used.json             # gops mod localize 生成
    └── setting.yml            # 可选,非 gops mod new 生成

代码参考

当前模块相关实现主要在这些文件:

  • app/gops/commands/mod_cmd.rs
  • src/module/operator.rs
  • src/module/spec.rs
  • src/module/model.rs
  • src/module/refs.rs
  • src/module/depend.rs

术语参考

  • Module:模块对象
  • ModOperator:模块对象的代码实现入口
  • ModelSTD:模型标识,描述 CPU / OS / 运行空间组合
  • localize:根据变量和值文件生成本地结果
  • update_local:同步本地依赖和引用

当前限制

下面这些内容不再视为当前实现的一部分:

  • 独立 gmod CLI
  • 旧版多工具拆分说明
  • 推断型 Rust API 文档
  • 未在当前代码里出现的模板系统和扩展点

Module Operator 故障排除

1. gops mod new 创建后文件很少

现象:

  • 每个 mod/<model>/ 下只有模板文件(vars.yml / spec/ / workflows/operators.gxl / _gal/work.gxl)
  • 没有 setting.yml,也没有 values/

原因:

  • 当前 mod new 生成的是模板骨架,不是完整业务模板
  • setting.yml 和 values/ 不由 mod new 生成

处理:

  • 按需修改 mod/<model>/ 下的模板文件
  • 执行 gops mod update 生成 values/<model>/ 值文件模板
  • 需要自定义本地化行为时再手工补充 setting.yml

2. gops mod localize 失败

常见原因:

  • vars.yml 未定义完整
  • 模块根 values/<model>/ 下的 sys_value.yml / mod_value.yml 缺失或结构不匹配
  • 尚未执行 gops mod update,导致值文件模板未生成

建议:

gops mod update
gops mod localize --debug 2

先生成 values/<model>/ 值文件,再用 --debug 2 定位问题。

注意:gops mod localize 声明的 --value / --default 目前未被实现消费,值始终来自 values/<model>/。

3. gops mod update 覆盖了本地内容

原因:

  • 使用了较强的 --force 级别

建议:

  • 默认先不用 --force
  • 必要时先试 --force 1
  • 只有明确要覆盖时再用 --force 2 或 3

4. 模块目录模型不符合预期

现象:

  • mod/ 下生成的模型目录和预想的平台不同

原因:

  • 当前模板和 ModelSTD 支持集合由代码决定,不由文档静态列死

建议:

  • 以生成结果为准
  • 不要继续沿用旧文档里的目标平台列表

5. 工作流无法执行

现象:

  • 模块骨架存在,但后续执行工作流失败

原因:

  • galaxy-ops 负责组织和生成
  • 真正的工作流执行依赖 galaxy-flow / gx

建议:

  • 先确认模块和系统对象已本地化成功
  • 再检查 gx 是否可执行、工作流入口是否存在

配置

📖 NetAccessCtrl 简约配置指南(非开发者版)

什么是 NetAccessCtrl?

NetAccessCtrl 是一个网络访问控制模块,可以在使用orino_variate 时自动将您的网络请求重定向到更快的镜像服务器,支持认证、超时设置和代理配置。它可以帮助您:

  • 🚀 加速 GitHub、GitLab 等国外服务访问
  • 🔐 安全管理认证信息
  • ⏱️ 控制网络请求超时时间
  • 🌐 配置代理服务器
  • 📝 使用环境变量动态配置

快速开始

1. 创建配置文件

在您的项目根目录创建 net-accessor_ctrl.yaml 文件:

# 基础配置示例
enable: true
units:
  - rules:
      - pattern: "https://github.com/*"
        target: "https://mirror.ghproxy.com/"
    # 可选:添加认证信息
    auth:
      username: "your_username"
      password: "your_token"

2. 常用场景配置

GitHub 加速访问

enable: true
units:
  - rules:
      - pattern: "https://github.com/*"
        target: "https://mirror.ghproxy.com/"
      - pattern: "https://raw.githubusercontent.com/*"
        target: "https://raw.ghproxy.com/"

GitLab 镜像

enable: true
units:
  - rules:
      - pattern: "https://gitlab.com/*"
        target: "https://gitlab-mirror.com/"

NPM 包管理器加速

enable: true
units:
  - rules:
      - pattern: "https://registry.npmjs.org/*"
        target: "https://registry.npmmirror.com/"

3. 完整配置示例

enable: true
units:
  # GitHub 配置
  - rules:
      - pattern: "https://github.com/*"
        target: "https://ghproxy.com/"
      - pattern: "https://raw.githubusercontent.com/*"
        target: "https://raw.ghproxy.com/"
    auth:
      username: "${GITHUB_USER}"
      password: "${GITHUB_TOKEN}"
    timeout:
      connect-timeout: 30
      read-timeout: 60
      total-timeout: 300
    proxy:
      url: "http://proxy.company.com:8080"

  # 其他服务配置
  - rules:
      - pattern: "https://api.example.com/*"
        target: "https://internal-api.example.com/"

配置参数说明

基本参数

  • enable: true 或 false,是否启用网络访问控制
  • units: 配置单元列表,每个单元包含重定向规则和配置

单元配置 (units)

每个 unit 包含:

  • rules: 重定向规则列表
  • auth: 可选的认证信息(用户名和密码)
  • timeout: 可选的超时设置
  • proxy: 可选的代理配置

规则配置 (rules)

每个 rule 包含:

  • pattern: 要匹配的URL模式(支持 * 通配符)
  • target: 重定向的目标地址

环境变量支持

您可以使用环境变量来动态配置,避免硬编码敏感信息:

enable: true
units:
  - rules:
      - pattern: "https://${GITHUB_DOMAIN:github.com}/*"
        target: "https://${MIRROR_DOMAIN:ghproxy.com}/"
    auth:
      username: "${GITHUB_USER}"
      password: "${GITHUB_TOKEN}"
    proxy:
      url: "${PROXY_URL:http://proxy.default:8080}"

环境变量语法:

  • ${VARIABLE_NAME}: 使用环境变量
  • ${VARIABLE_NAME:default_value}: 使用环境变量,如果不存在则使用默认值

使用方法

1. 设置环境变量(可选)

# Linux/Mac
export GITHUB_USER="your_username"
export GITHUB_TOKEN="your_token"
export PROXY_URL="http://proxy.company.com:8080"

# Windows
set GITHUB_USER=your_username
set GITHUB_TOKEN=your_token
set PROXY_URL=http://proxy.company.com:8080

2. 将配置文件放在正确位置

  • 系统级配置:/etc/net-access.yaml
  • 用户级配置:~/.config/net-access.yaml
  • 项目级配置:项目根目录/net-access.yaml

3. 验证配置

配置完成后,您可以通过以下方式验证是否生效:

# 测试 GitHub 访问
curl -I "https://github.com/user/repo/releases"

# 查看是否重定向到镜像服务器

常见问题

Q: 如何添加多个镜像服务器?

A: 在 units 中添加多个配置单元,系统会按顺序尝试:

enable: true
units:
  # 第一个镜像
  - rules:
      - pattern: "https://github.com/*"
        target: "https://mirror1.github.com/"

  # 备用镜像
  - rules:
      - pattern: "https://github.com/*"
        target: "https://mirror2.github.com/"

Q: 如何设置不同的超时时间?

A: 在 timeout 部分配置:

timeout:
  connect-timeout: 30    # 连接超时(秒)
  read-timeout: 60       # 读取超时(秒)
  total-timeout: 300     # 总超时(秒)

Q: 如何处理认证?

A: 在 auth 部分配置用户名和密码,推荐使用环境变量:

auth:
  username: "${YOUR_USERNAME}"
  password: "${YOUR_PASSWORD}"

Q: 配置不生效怎么办?

A: 检查以下几点:

  1. 确保 enable: true
  2. 检查配置文件路径是否正确
  3. 验证 YAML 语法是否正确
  4. 检查 URL 模式是否匹配

Q: 如何配置代理?

A: 在 proxy 部分配置:

proxy:
  url: "http://proxy.example.com:8080"

Q: 支持哪些通配符?

A: 目前支持 * 通配符,可以匹配任意字符序列。例如:

  • https://github.com/* 匹配所有 GitHub 地址
  • https://raw.githubusercontent.com/* 匹配所有 GitHub 原始文件地址

配置示例合集

常用镜像服务

GitHub 全家桶加速

enable: true
units:
  - rules:
      - pattern: "https://github.com/*"
        target: "https://ghproxy.com/"
      - pattern: "https://raw.githubusercontent.com/*"
        target: "https://raw.ghproxy.com/"
      - pattern: "https://gist.github.com/*"
        target: "https://gist.ghproxy.com/"

Python 包管理器 (PyPI)

enable: true
units:
  - rules:
      - pattern: "https://pypi.org/*"
        target: "https://pypi.doubanio.com/"

Docker 镜像加速

enable: true
units:
  - rules:
      - pattern: "https://registry-1.docker.io/*"
        target: "https://dockerhub.azk8s.cn/"

RubyGems 加速

enable: true
units:
  - rules:
      - pattern: "https://rubygems.org/*"
        target: "https://gems.ruby-china.com/"

企业内部配置

内部服务映射

enable: true
units:
  - rules:
      - pattern: "https://external-api.company.com/*"
        target: "https://internal-api.company.com/"
    auth:
      username: "${INTERNAL_API_USER}"
      password: "${INTERNAL_API_PASSWORD}"
    timeout:
      connect-timeout: 10
      read-timeout: 30
      total-timeout: 60

多环境配置

# 开发环境配置
enable: ${ENABLE_NET_ACCESS:true}
units:
  - rules:
      - pattern: "https://api.${ENV:dev}.company.com/*"
        target: "http://localhost:8080/"
    timeout:
      connect-timeout: 5
      read-timeout: 15
      total-timeout: 30

故障排除

检查配置文件语法

使用在线 YAML 验证工具检查配置文件语法:

  1. 访问 https://www.yamllint.com/
  2. 粘贴您的配置文件内容
  3. 检查是否有语法错误

常见错误及解决方案

1. 配置文件不生效

症状: 配置修改后没有效果 解决方案:

  • 检查配置文件路径是否正确
  • 确认 enable: true
  • 重启应用程序
  • 检查文件权限

2. 环境变量未生效

症状: 环境变量没有正确替换 解决方案:

  • 确认环境变量已正确设置
  • 检查环境变量名称是否正确
  • 使用 echo $VARIABLE_NAME 验证环境变量
  • 重新启动终端或应用程序

3. 网络连接超时

症状: 请求经常超时 解决方案:

  • 增加 timeout 配置中的时间值
  • 检查网络连接状态
  • 尝试更换镜像服务器

4. 认证失败

症状: 401 或 403 错误 解决方案:

  • 检查用户名和密码是否正确
  • 确认认证信息是否有权限访问目标服务
  • 检查 token 是否已过期

调试技巧

启用详细日志

如果应用程序支持日志,可以启用详细日志来查看重定向过程:

# 示例:启用调试日志
export RUST_LOG=debug
your_application

手动测试重定向

使用 curl 命令手动测试重定向是否工作:

# 测试重定向
curl -v "https://github.com/user/repo"

# 查看是否被重定向到镜像服务器

检查配置加载

如果可能,查看应用程序启动时的日志,确认配置文件是否正确加载。

最佳实践

安全性建议

  1. 使用环境变量: 避免在配置文件中硬编码敏感信息
  2. 设置文件权限: 确保配置文件只有授权用户可读
    chmod 600 net-access.yaml
    
  3. 定期更新认证信息: 定期更换密码和访问令牌
  4. 使用 HTTPS: 确保所有目标地址使用 HTTPS 协议

性能优化建议

  1. 规则排序: 将最常用的规则放在前面
  2. 合理设置超时: 根据网络环境调整超时时间
  3. 使用就近镜像: 选择地理位置较近的镜像服务器
  4. 避免过度重定向: 不要配置过多的重定向层级

维护建议

  1. 版本控制: 将配置文件纳入版本控制(排除敏感信息)
  2. 文档记录: 记录配置文件的用途和变更历史
  3. 定期测试: 定期测试配置是否仍然有效
  4. 备份配置: 保留配置文件的备份

获取帮助

如果遇到问题,可以通过以下方式获取帮助:

检查清单

在寻求帮助前,请先检查:

  • 配置文件语法是否正确
  • 环境变量是否正确设置
  • 网络连接是否正常
  • 认证信息是否有效
  • 目标服务器是否可访问

常见资源

  • YAML 语法验证: https://www.yamllint.com/
  • 环境变量设置指南: 搜索 “环境变量设置 [您的操作系统]”
  • 网络连接测试: 使用 ping 和 curl 命令测试
  • 镜像服务状态: 查看镜像服务的官方状态页面

联系支持

如果以上方法都无法解决问题,请联系技术支持并提供以下信息:

  1. 操作系统和版本
  2. 配置文件内容(去除敏感信息)
  3. 错误信息或日志
  4. 重现问题的步骤

附录

配置文件模板

基础模板

# NetAccessCtrl 基础配置模板
enable: true
units:
  - rules:
      - pattern: "https://example.com/*"
        target: "https://mirror.example.com/"

完整模板

# NetAccessCtrl 完整配置模板
enable: true
units:
  - rules:
      - pattern: "https://service1.com/*"
        target: "https://mirror1.service1.com/"
      - pattern: "https://service2.com/*"
        target: "https://mirror2.service2.com/"
    auth:
      username: "${SERVICE1_USER}"
      password: "${SERVICE1_PASSWORD}"
    timeout:
      connect-timeout: 30
      read-timeout: 60
      total-timeout: 300
    proxy:
      url: "${PROXY_URL:http://proxy.default:8080}"

  - rules:
      - pattern: "https://another-service.com/*"
        target: "https://internal.another-service.com/"
    # 此单元无认证、超时和代理配置

常用镜像服务器列表

服务类型原地址推荐镜像地址
GitHubhttps://github.com/*https://ghproxy.com/
GitHub Rawhttps://raw.githubusercontent.com/*https://raw.ghproxy.com/
PyPIhttps://pypi.org/*https://pypi.doubanio.com/
NPMhttps://registry.npmjs.org/*https://registry.npmmirror.com/
Docker Hubhttps://registry-1.docker.io/*https://dockerhub.azk8s.cn/
RubyGemshttps://rubygems.org/*https://gems.ruby-china.com/

注意:镜像服务地址可能会发生变化,请以最新信息为准。


快速开始总结:

  1. 创建 net-access.yaml 文件
  2. 复制相应场景的配置示例
  3. 设置环境变量(可选)
  4. 放置配置文件到正确位置
  5. 验证配置是否生效

祝您使用愉快!🎉

GXL 帮助(对齐当前实现)

1. 最小可运行示例

mod envs {
  env default {
    ROOT = "./";
  }
}

mod main {
  flow conf {
    gx.echo(value: "hello galaxy flow");
  }
}

2. 常用结构

2.1 模块与继承

mod base {
  flow setup {
    gx.echo(value: "setup");
  }
}

mod main : base {
  flow conf {
    gx.echo(value: "conf");
  }
}

2.2 环境与 gx.vars

mod envs {
  env base {
    gx.vars {
      APP = "galaxy";
      STAGE = "dev";
    };
  }

  env default : base;
}

2.3 flow 编排

mod main {
  flow prepare {
    gx.echo(value: "prepare");
  }

  flow deploy {
    gx.echo(value: "deploy");
  }

  flow @release | prepare | deploy {
    gx.echo(value: "release");
  }
}

2.4 函数与活动

mod sys {
  fn echo_tag(tag = "INFO", *msg) {
    gx.echo(value: "[${tag}] ${msg}");
  }

  activity copy {
    src = "";
    dst = "";
    executer = "copy_act.sh";
  }
}

mod main {
  flow conf {
    sys.echo_tag(msg: "start");
    sys.copy(src: "a.txt", dst: "b.txt");
  }
}

3. 控制流

3.1 if/else if/else

flow conf {
  if defined(${DEPLOY}) && ${DEPLOY} == "true" {
    gx.echo(value: "deploy");
  } else if ${STAGE} == "test" {
    gx.echo(value: "test");
  } else {
    gx.echo(value: "skip");
  }
}

3.2 for

flow conf {
  for ${CUR} in ${DATA} {
    gx.echo(value: "item=${CUR}");
  }
}

4. 内置能力写法

当前实现统一是函数调用形式:

gx.cmd(cmd: "echo hi");
gx.shell(shell: "./demo.sh", out_var: "OUT");
gx.read_file(file: "./var.yml", name: "DATA");
gx.tpl(tpl: "./tpls", dst: "./out", file: "./vars.json");

不要使用旧文档中的 gx.xxx { ... } 形式。

5. gx.patch_file 快速示例

gx.patch_file(
  file: "./Cargo.toml",
  action: "set",
  marker: "version",
  value: "0.12.3"
);

对应 marker 行:

version = "0.12.2"   # @gxl:set(version)

更多参数见:docs/gxl/inner/patch_file.md

变量定义

1. 赋值

flow conf {
  ONE = "one";
  SYS_A = { MOD1: "A", MOD2: "B", MOD3: 1, MOD4: 2 };
  SYS_B = ["C", "D"];
  SYS_C = ${SYS_B[1]};
  SYS_D = ${SYS_A.MOD1};
}

2. 数据类型

支持:

  • 字符串:"text" 或 r#"raw text"#
  • 布尔:true/false
  • 数字:整数、浮点
  • 对象:{ KEY: VALUE, ... }
  • 列表:[VALUE, VALUE, ...]
  • 变量引用:${VAR}、${OBJ.KEY}、${ARR[0]}

3. 大小写规则

运行时变量键按不区分大小写处理(内部统一大写键)。

例如:

  • ${SYS_A.MOD1} 与 ${sys_a.mod1} 读取同一个值。

4. 典型遍历

mod envs {
  env default {
    DATA_LIST = ["JAVA", "RUST", "PYTHON"];
    DATA_OBJ = {
      JAVA: { NAME: "JAVA", SCORE: 80 },
      RUST: { NAME: "RUST", SCORE: 100 },
      PYTHON: { NAME: "PYTHON", SCORE: 200 }
    };
  }
}

mod main {
  flow list_do {
    for ${CUR} in ${ENV_DATA_LIST} {
      gx.echo(value: "CUR=${CUR}");
    }
  }

  flow obj_do {
    for ${CUR} in ${ENV_DATA_OBJ} {
      gx.echo(value: "${CUR.NAME}:${CUR.SCORE}");
    }
  }
}

GXL 内置常量

以下常量由运行时自动注入到变量空间。

  • GXL_PRJ_ROOT

    • 从当前目录向上查找 _gal/project.toml 所在目录。
    • 找不到时值为 UNDEFIN。
  • GXL_GIT_BRANCH

    • 以 GXL_PRJ_ROOT(或当前启动目录)为起点探测 git 分支名。
    • detached HEAD 或非 git 仓库时值为 UNDEFIN。
  • GXL_START_ROOT

    • 启动 gx 时的工作目录。
  • GXL_CUR_DIR

    • 当前执行目录;在 gx.run 切换目录时可能与 GXL_START_ROOT 不同。
  • GXL_CMD_ARG

    • CLI 透传参数(来自 --cmd-arg)。
  • GXL_CMD_DRYRUN

    • CLI dryrun 标记。
  • GXL_CMD_MODUP

    • CLI 模块更新标记。
  • GXL_OS_SYS

    • 系统标识字符串(由架构/系统/主版本组合)。

GXL 语法(对齐当前代码)

本文档按当前解析器实现整理(src/parser/*)。

1. 顶层结构

GXL 文件由多个 mod 组成:

mod main {
  env default {
    ROOT = "./";
  }

  flow conf {
    gx.echo(value: "hello");
  }
}

也支持 extern mod(外部模块引用):

extern mod os,ssh { path = "./_gal/mods"; }
extern mod net { git = "https://example.com/repo.git", branch = "main"; }

2. 语法骨架

GxlFile      = { ExternMod | Module } ;

ExternMod    = "extern" "mod" ModNameList ModAddr ;
ModNameList  = Name { "," Name } ;
ModAddr      = "{" ( "path" "=" String
                 | "git" "=" String [ "," ("branch"|"channel") "=" String ] [ "," "tag" "=" String ] ) "}" ;

Module       = [Annotation] "mod" Name [":" MixList] "{" { Prop | Env | Flow | Fun | Activity } "}" [";"] ;
Env          = [Annotation] "env" Name [":" MixList] (";" | "{" { Prop | EnvStmt } "}" [";"]) ;
Flow         = [Annotation] "flow" FlowHead (";" | Block [";"]) ;
Fun          = "fn" Name "(" [FunParams] ")" (";" | Block [";"]) ;
Activity     = "activity" Name "{" { FormalParam [","|";" ] } "}" ;

FlowHead     = Name [":" FlowList [":" FlowList]]
             | [FlowPipe "|"] "@" Name ["|" FlowPipe]
             | Name ["|" FlowPipe] ;
FlowPipe     = FlowRef { "|" FlowRef } ;
FlowList     = FlowRef { "," FlowRef } ;
FlowRef      = Name | Name "." Name | VarRef ;
MixList      = MixItem { "," MixItem } ;
MixItem      = Name | VarRef ;

Block        = "{" { Prop | IfStmt | ForStmt | Builtin | Call | CmdBlock } "}" ;
IfStmt       = "if" Expr Block { "else" "if" Expr Block } [ "else" Block ] ;
ForStmt      = "for" VarRef "in" VarRef Block ;
CmdBlock     = "```cmd" <raw text> "```" ;

Prop         = Name "=" GxlObject (","|";") ;
GxlObject    = VarRef | Scalar | List | Object ;
Object       = "{" [ ObjItem {"," ObjItem} ] "}" ;
ObjItem      = Name ":" ScalarOrNested ;
List         = "[" [ ScalarOrNested {"," ScalarOrNested} ] "]" ;

Builtin      = gx.xxx call syntax ;
Call         = Path "(" [ActualParams] ")" [";"] ;
Annotation   = "#[" AnnFun {"," AnnFun} "]" ;

3. Flow 头部支持形式

3.1 旧式(冒号)

flow test : pre1,pre2 : post1,post2 {
  gx.echo(value: "run");
}

3.2 管道 + @ 指定主 flow

flow pre1 | pre2 | @test | post1 | post2 {
  gx.echo(value: "run");
}

3.3 简写管道

flow test | post1 | post2 {
  gx.echo(value: "run");
}

4. 参数与调用约定

所有内置能力统一使用调用形式:

gx.cmd(cmd: "echo hello");
gx.echo("hello");              // 等价,匿名参数映射到 default

说明:

  • 调用参数分隔符是 ,。
  • 命名参数使用 :,如 name: "v"。
  • 很多能力支持 default(匿名首参数)写法。

5. 条件表达式

支持:

  • 比较:== != > >= < <= =*(=* 为通配)
  • 逻辑:&& || !
  • 函数:defined(${VAR})

示例:

if defined(${CUR.ENABLE}) && ${CUR.ENABLE} == true {
  gx.echo(value: "enabled");
} else {
  gx.echo(value: "disabled");
}

6. 目前块内可直接识别的内置能力

  • gx.cmd
  • gx.shell
  • gx.run
  • gx.echo
  • gx.assert
  • gx.ver
  • gx.read_file
  • gx.read_cmd
  • gx.read_stdin
  • gx.tpl
  • gx.tar
  • gx.untar
  • gx.download
  • gx.upload
  • gx.patch_file

补充:

  • gx.vars 只在 env 块中使用。
  • defined(...) 是表达式函数,不是 gx.defined 命令。

GXL 示例索引(对齐当前 examples)

以下示例对应 galaxy-flow/examples/* 当前目录中的真实 work.gxl:

  • assert.md:断言、变量访问、auto_load
  • dryrun.md:#[dryrun(...)]
  • fun.md:函数、参数、模块调用
  • read.md:gx.read_file / gx.read_cmd
  • shell.md:gx.shell
  • template.md:gx.tpl 与 cmd 代码块
  • transaction.md:#[transaction] / #[undo(...)]
  • vars.md:对象、列表、for、if

说明:

  • 这些页面只保留“当前示例在做什么”和“如何运行”。
  • 语法规则请以 gxl/help.md、gxl/syntax.md 和 gxl/inner/* 为准。

Assert 示例

对应目录:

  • galaxy-flow/examples/assert
  • 入口:_gal/work.gxl
  • 常用 flow:assert_main、assert_parent

这个示例主要验证三类能力:

  • gx.assert(...) 的相等断言
  • 对象、数组与大小写不敏感变量访问
  • #[auto_load(entry/exit)] 与模块 flow 组合

示例代码:

extern mod os { path= "../../_gal/mods"; }
mod base_env {
    env _common {
      gx.vars {
        DOMAIN    = "domain" ;
      }
    }
    env cli : _common {
      ROOT   = "./";

    }
    env unit_test : _common {
      ROOT   = "./example";
    }
}
mod envs : base_env {
    #[usage(desp="default")]
    env default : cli ;
    env empty {}
    env ut : unit_test  ;
}
mod base{
  mod_val = "1";
  flow define {
    base = "BASE";
  }
  #[auto_load(entry)]
  flow base_into  {
    base_begin = "BASE_INTO";
  }
  #[auto_load(exit)]
  flow base_exit {
    base_end = "BASE_EXIT";
  }
}
mod other {
  flow def1 {
    other_val = "OTHER_DEF";
  }
  flow def2{
    other_val = "OTHER_DEF2";
  }
}
mod main   {
  conf = "${ENV_ROOT}/conf" ;

  #[auto_load(entry)]
  flow __into  | other.def1  {
    other_val = "OTHER_DE1";
  }
  #[auto_load(exit)]
  flow __exit | other.def2 ;
  #[usage(desp="main")]
  flow assert_main {
    one= "one";
    sys_a = { mod1 : "A", mod2 : "B" };
    sys_b =  [ "C", "D" ];
    sys_c = ${SYS_B[1]} ;
    sys_d = ${SYS_A.MOD1} ;
    gx.assert ( value : "${MAIN_CONF}" , expect : "${ENV_ROOT}/conf" );
    gx.assert ( value : "${OTHER_VAL}" , expect : "OTHER_DEF" );
    gx.assert ( value : "${SYS_A.MOD1}" , expect : "A" );
    gx.assert ( value : "${sys_a.mod1}" , expect : "A" );
    gx.assert ( value : "${sys_b[0]}" , expect : "C" );
    gx.assert ( value : "${sys_d}" , expect : "A" );
  }

  flow base.define | @assert_parent   {
    gx.assert ( value : "${MAIN_CONF}" , expect : "${ENV_ROOT}/conf" );
    gx.assert ( value : "${BASE_MOD_VAL}" , expect : "1" );
    gx.assert ( value : "${OTHER_VAL}" , expect : "OTHER_DEF" );
    gx.assert ( value : "${BASE}" , expect : "BASE" );
    gx.assert ( value : "${BASE_BEGIN}" , expect : "BASE_INTO" );
  }

}

运行方式:

gx assert_main
gx assert_parent

Dryrun 示例

对应目录:

  • galaxy-flow/examples/dryrun
  • 入口:_gal/work.gxl
  • 常用 flow:start

这个示例演示:

  • #[dryrun(_step3)] 在 dryrun 模式下替换目标 flow
  • 非 dryrun 时原 flow 继续执行,且断言失败

示例代码:

mod main {

env default {}

flow _step1 {
    gx.echo ("step1");
}

#[dryrun(_step3)]
flow _step2 {
    gx.echo ("step2");
    gx.assert ( value : "true" , expect : "false" );
}

flow _step3 {
    gx.echo ("dryrun setp2");
}

flow start | _step1 | _step2 ;

}

运行方式:

gx start --dryrun
gx start

Function 示例

对应目录:

  • galaxy-flow/examples/fun
  • 入口:_gal/work.gxl
  • 常用 flow:conf

这个示例演示:

  • fn 定义与模块内调用
  • 默认参数与可变参数
  • 函数中继续调用其他函数与 for

示例代码:

extern mod os { path = "../../_gal/mods"; }

mod sys {
    fn echo( *value ) {
        gx.echo ( "${value}");
    }
    fn echo_obj( *value , msg = "object") {
        gx.echo ( "${value}:${msg}");
    }
    fn echo_list( *value , list_msg  ) {
      prefix = "galaxy";
      sys.echo_obj("sys.echo_obj");
      echo_obj("echo_obj");
      for ${item} in ${list_msg}  {
          gx.echo ( "${prefix}-${value}-${item}");
      }
    }
}

运行方式:

gx conf

Read 示例

对应目录:

  • galaxy-flow/examples/read
  • 入口:_gal/work.gxl
  • 常用 flow:conf

这个示例演示:

  • gx.read_file(...) 把 ini 文件读入变量空间
  • gx.read_cmd(...) 捕获命令输出
  • 读取命名对象后用 for 遍历

示例代码:

extern mod os { path= "../../_gal/mods"; }
mod envs {
    env _dev_local {
        gx.read_file ( file : "./var.ini" );
    }
    env default : _dev_local ;
}
mod main   {
  flow conf  {
    gx.echo (  "${RUST}" );
    gx.echo (  "${JAVA}" );
    gx.assert ( value : "${JAVA}" , expect : "90"  );

    gx.read_cmd (
        //fail!
        //cmd  : r#"git branch --show-current |  sed -E "s/(feature|develop|ver-dev|release|master|issue)(\/\.*)?/_branch_\1/g" "# ,
        //suc!
        cmd  : "git branch --show-current | sed -E 's/release/rls/g'" ,
        name : "GIT_BRANCH" );

    gx.echo ( "what:${GIT_BRANCH}" );

    gx.read_file ( file : "./var2.ini" , name : "DATA");

    for ${CUR} in ${DATA} {
        gx.echo ( value : "${CUR}" );
    }
  }



}

运行方式:

gx conf

Shell 示例

对应目录:

  • galaxy-flow/examples/shell
  • 入口:_gal/work.gxl
  • 常用 flow:conf、do_obj

这个示例演示:

  • gx.shell(...) 运行脚本并回填 out_var
  • arg_file 的使用
  • 列表、对象遍历中重复执行 shell

示例代码:

extern mod os { path = "../../_gal/mods"; }

mod envs {
    env _dev_local {}
    env default : _dev_local;
}

mod main {
    flow conf {
        gx.read_file(file: "./var.yml", name: "VAR");
        gx.echo("what:${VAR.MEMBER.JAVA}");

        gx.shell(
            arg_file: "./var.json",
            shell: "./demo.sh",
            out_var: "SYS_OUT");

        gx.echo("what:${SYS_OUT}");

        gx.read_file(file: "./var_list.yml", name: "DATA");
        for ${CUR} in ${DATA.DEV_LANG} {
            gx.shell(
                shell: "./demo_ex.sh ${CUR}",
                out_var: "SYS_OUT");
            gx.echo("what:${SYS_OUT}");
        }

        gx.read_file(file: "./var_obj.yml", name: "DATA");
        for ${CUR} in ${DATA} {
            gx.shell(
                shell: "./demo_ex.sh ${CUR.SYS.NAME}",
                out_var: "SYS_OUT");
            gx.echo("what:${SYS_OUT}");
        }
    }
    flow do_obj {
        gx.read_file(file: "./var_obj.yml", name: "DATA");
        for ${CUR} in ${DATA} {
            //gx.echo( "CUR:${CUR.SYS.NAME}" );
            gx.shell(
                shell: "./demo_ex.sh ${CUR.SYS.NAME}",
                out_var: "SYS_OUT");
            gx.echo("what:${SYS_OUT}");
        }
    }
}

运行方式:

gx conf
gx do_obj

Template 示例

对应目录:

  • galaxy-flow/examples/template
  • 入口:_gal/work.gxl
  • 常用 flow:conf

这个示例演示:

  • gx.tpl(...) 渲染模板目录
  • 先用 gx.cmd(...) 准备输出目录
  • cmd 代码块的写法

示例代码:

extern mod os { path = "../../_gal/mods"; }

mod base_env {
    env _common {
        gx.vars {
            DOMAIN = "domain";
            SOCK_FILE = "socket";
            GXL_PRJ_ROOT = "./";
        }
    }
    env cli : _common {
        ROOT = "./";
    }
    env unit_test : _common {
        ROOT = "./example";
    }
}

mod envs : base_env {
    #[usage(desp = "default")]
    env default : cli;
    env empty {}
    env ut : unit_test;
}

mod main {
    conf = "${ENV_ROOT}/conf";
    flow conf {
        os.path(dst: "${MAIN_CONF}/used", keep: "true");
        gx.tpl(
            tpl: "${MAIN_CONF}/tpls/",
            dst: "${MAIN_CONF}/used/",
            file: "${MAIN_CONF}/value.json");

        ```cmd
        echo "hello";
        cp ./conf/value.json ./conf/used/back.json;
        ```
    }
}

运行方式:

gx conf

Transaction 示例

对应目录:

  • galaxy-flow/examples/transaction
  • 入口:_gal/work.gxl
  • 外部模块:_gal/base.gxl
  • 常用 flow:trans1、trans2

这个示例演示:

  • #[transaction] 事务式 flow
  • #[undo(...)] 回滚 flow
  • 引入外部模块后的跨模块事务步骤

示例代码:

extern mod base { path = "./_gal/"; }

mod envs {
    env default {};
}

mod main {
    flow trans1 | step1 | step2 | base.base_step1 | step3;
    flow trans2 | step1 | step3 | step2;

    #[transaction, undo(_undo_step1)]
    flow step1 {
        gx.echo(" step1 ");
    }
    #[undo(_undo_step2)]
    flow step2 {
        gx.echo(" step2 ");
    }
    #[undo(_undo_step3)]
    flow step3 {
        gx.echo(" step3 ");
        gx.assert(value: "true", expect: "false");
    }

    flow _undo_step1 {
        gx.echo(" undo step1 ");
    }
    flow _undo_step2 {
        gx.echo(" undo step2 ");
    }
    flow _undo_step3 {
        gx.echo(" undo step3 ");
    }
}

运行方式:

gx trans1
gx trans2

Vars 示例

对应目录:

  • galaxy-flow/examples/vars
  • 入口:_gal/work.gxl
  • 常用 flow:array_do、obj_do

这个示例演示:

  • env 中定义列表与对象变量
  • for 遍历数组和对象
  • if 条件判断与变量比较

示例代码:

mod envs {
    env default {
        data_list = [
            "JAVA",
            "RUST",
            "PYTHON",
        ];
        data_obj = {
            JAVA: { NAME: "JAVA", SCORE: 80 },
            RUST: { NAME: "RUST", SCORE: 100 },
            PYTHON: { NAME: "PYTHON", SCORE: 200 },
        };
    }
}

mod main {
    flow array_do {
        for ${CUR} in ${ENV.DATA_LIST} {
            gx.echo("CUR:${CUR}");
        }
    }
    flow obj_do {
        for ${CUR} in ${ENV.DATA_OBJ} {
            gx.echo("CUR:${CUR.NAME} : ${CUR.SCORE}");
        }
    }
}

运行方式:

gx array_do
gx obj_do

GXL 内置能力总览(对齐当前实现)

以下为当前 block parser 直接支持的内置能力:

  • gx.assert:docs/gxl/inner/assert.md
  • gx.cmd:docs/gxl/inner/cmd.md
  • gx.echo:docs/gxl/inner/echo.md
  • gx.read_file / gx.read_cmd / gx.read_stdin:docs/gxl/inner/read.md
  • gx.vars(仅 env 内):docs/gxl/inner/vars.md
  • gx.tpl:docs/gxl/inner/tpl.md
  • gx.ver:docs/gxl/inner/ver.md
  • gx.run:docs/gxl/inner/run.md
  • gx.shell:docs/gxl/inner/shell.md
  • gx.tar / gx.untar:docs/gxl/inner/tar_untar.md
  • gx.download / gx.upload:docs/gxl/inner/download_upload.md
  • gx.patch_file:docs/gxl/inner/patch_file.md

表达式函数:

  • defined(${VAR}):docs/gxl/inner/defined.md

兼容别名说明:

  • 解析器中部分能力存在 rg.xxx 兼容解析入口,但在 block/env 语句分发层并未统一开放。
  • 建议始终使用 gx.xxx。

未作为当前内置 block 能力接入:

  • gx.artifact(见 docs/gxl/inner/artifact.md)

gx.artifact(当前未作为内置 block 能力接入)

当前 BlockAction 与 stc_blk 未直接识别 gx.artifact。

如果需要 artifact 流程,请通过外部模块/活动调用方式实现,例如:

os.artifact(file: "./target/a", dst: "./artifacts");

建议将该能力放在 _gal/mods 中以模块调用方式维护。

gx.assert

作用

断言比较,默认比较“相等应成立”。

语法

gx.assert(
  value: "<实际值>",
  expect: "<期望值>",
  err: "<失败提示>",
  result: "true|false"
);

参数:

  • value:实际值
  • expect:期望值
  • err:失败时消息(可选)
  • result:"true" 表示期望相等;"false" 表示期望不相等

示例

gx.assert(value: "${ENV}", expect: "prod");
gx.assert(value: "${ENV}", expect: "prod", result: "false");

gx.cmd

作用

执行一条命令字符串。

语法

gx.cmd(
  cmd: "<command>",
  err: "<err var>",
  suc: "<success message>",
  ok_codes: "0,2",
  sudo: "true|false",
  log: "1|2|3",
  silence: "true|false",
  quiet: "true|false"
);

也支持匿名首参数:

gx.cmd("echo hello");

代码块命令

```cmd
cp a b
ls -al
```

示例

gx.cmd(cmd: "git branch --show-current");
gx.cmd("echo ${HOME}");
gx.cmd(cmd: "grep foo missing.txt", ok_codes: "0,1");

defined(…)

作用

条件表达式函数,判断变量是否已定义。

语法

if defined(${HOME}) {
  gx.echo(value: "has home");
}

if !defined(${NO_SUCH_VAR}) {
  gx.echo(value: "missing");
}

说明:

  • 这是表达式函数,不是 gx.defined 命令。

gx.download / gx.upload

gx.download

gx.download(
  url: "https://example.com/a.txt",
  local_file: "./temp/a.txt",
  username: "user",
  password: "pass"
);

gx.upload

gx.upload(
  url: "https://example.com/upload",
  local_file: "./temp/a.txt",
  method: "put",
  username: "user",
  password: "pass"
);

说明:

  • local_file 的父目录必须已存在。
  • gx.download 若 local_file 是目录,会按 URL 文件名落盘。

gx.echo

作用

输出一段文本到 stdout。

语法

gx.echo(value: "<text>");

也支持匿名首参数:

gx.echo("hello");

说明:

  • 当前实现仅支持输出文本,不支持旧文档中的 file/export/inc 参数。

gx.patch_file

作用

基于 marker 对文件做受控修改,支持:

  • set
  • comment_line
  • uncomment_line
  • comment_block
  • uncomment_block

语法

gx.patch_file(
  file: "./Cargo.toml",
  action: "set",
  marker: "version",
  value: "0.12.3",
  strict: "true",
  dry_run: "false",
  backup: "false",
  comment_prefix: "#"
);

参数:

  • file:目标文件(必填)
  • action:操作类型(必填)
  • marker(或 id):marker id(必填)
  • value:仅 set 需要
  • strict:默认 true
  • dry_run:默认 false
  • backup:默认 false
  • comment_prefix(或 comment):默认 #

marker 约定

  • set:@gxl:set(<id>)
  • line:@gxl:line(<id>)
  • block start:@gxl:block(<id>)
  • block end:@gxl:end(<id>)

兼容写法:

  • # @gxl:...
  • #@gxl:...
  • // @gxl:...
  • //@gxl:...

strict 语义

strict=true 时,任何 marker 结构异常都失败,例如:

  • marker 命中数不是 1
  • block 嵌套
  • 只有 end 没有 block
  • 缺少 end

comment_prefix 约束

  • comment_prefix 不能为空字符串。

示例

1) set

version = "0.12.2"   # @gxl:set(version)
gx.patch_file(
  file: "./Cargo.toml",
  action: "set",
  marker: "version",
  value: "\"0.12.3\""
);

2) comment/uncomment block

# @gxl:block(res_depend_test)
[features]
res_depend_test = []
# @gxl:end(res_depend_test)
gx.patch_file(file: "./Cargo.toml", action: "comment_block", marker: "res_depend_test");
gx.patch_file(file: "./Cargo.toml", action: "uncomment_block", marker: "res_depend_test");

3) line toggle

res_depend_test = []   # @gxl:line(res_depend_test)
gx.patch_file(file: "./Cargo.toml", action: "comment_line", marker: "res_depend_test");
gx.patch_file(file: "./Cargo.toml", action: "uncomment_line", marker: "res_depend_test");

gx.read_file / gx.read_cmd / gx.read_stdin

gx.read_file

读取配置文件到变量空间。

gx.read_file(
  file: "./var.yml",
  name: "DATA"
);

参数:

  • file(或匿名首参数)
  • name:可选;不传时对象字段会并入全局变量
  • entity:解析层接受,当前执行层未使用

格式支持:

  • ini
  • json
  • yml

gx.read_cmd

执行命令并把 stdout 写入变量。

gx.read_cmd(
  name: "BRANCH",
  cmd: "git branch --show-current",
  err: "ERR_MSG",
  ok_codes: "0,1",
  log: "1"
);

gx.read_stdin

从标准输入读取值。

gx.read_stdin(
  prompt: "input your name:",
  name: "USER_NAME"
);

gx.run

作用

在子目录中执行另一个 GXL 配置。

语法

gx.run(
  local: "<run dir>",
  conf: "<gxl file>",
  env: "<env name>",
  flow: "a,b,c",
  isolate: "true|false"
);

参数:

  • local:运行目录
  • conf:目标配置文件(默认 ./_gal/work.gxl)
  • env:目标环境
  • isolate:是否隔离变量空间
  • flow:解析层可接受;当前执行层未实际覆盖 flow 列表(保留参数)

gx.shell

作用

执行 shell 命令/脚本,可加载参数文件,可回填输出变量。

语法

gx.shell(
  shell: "<command or script>",
  arg_file: "<json|yml|yaml|toml|ini>",
  out_var: "<var name>",
  err: "<err var>",
  ok_codes: "0,2",
  log: "1|2|3",
  sudo: "true|false",
  silence: "true|false"
);

也支持匿名首参数:

gx.shell("./demo.sh");

gx.tar / gx.untar

gx.tar

gx.tar(src: "./src", file: "./dist/src.tar.gz");

gx.untar

gx.untar(file: "./dist/src.tar.gz", dst: "./dist/unpack");

说明:

  • gx.untar 解压前会处理目标路径(存在时清理)。

gx.tpl

作用

模板渲染(当前仅 handlebars 引擎)。

语法

gx.tpl(
  tpl: "<模板文件或模板目录>",
  dst: "<目标文件或目标目录>",
  data: "<json string>",
  file: "<json file>",
  engine: "handlebars"
);

参数:

  • tpl:模板路径
  • dst:输出路径
  • data:内联 JSON 字符串(可选)
  • file:JSON 数据文件(可选)
  • engine:handlebars|helm(当前执行层仅支持 handlebars)

示例

gx.tpl(
  tpl: "./conf/tpls",
  dst: "./conf/used",
  file: "./conf/value.json"
);

gx.vars

作用

批量定义变量。

语法

env default {
  gx.vars {
    APP = "galaxy";
    STAGE = "dev";
  };
}

说明:

  • 当前语法是 = 赋值,支持 ;/, 分隔。
  • gx.vars 只在 env 中作为 env item 使用。

gx.ver

作用

读取并递增版本号(写回文件,并导出变量)。

语法

gx.ver(
  file: "./version.txt",
  inc: "build|bugfix|feature|main|null"
);

版本格式:

  • major.minor.patch
  • major.minor.patch.build

说明:

  • 默认导出变量为 VERSION。
  • export 参数在当前解析层存在实现偏差,不建议使用。