You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There are multiple compile-time dependencies between sibling components in the Go modules of this monorepo, implemented via go.mod replace directives pointing at sibling directories. As a result, "deployable components" and "shared libraries" are indistinguishable in the directory layout, which leads to a series of downstream costs in builds, CI, and releases.
Current dependency graph
(The dashed box marks pure shared libraries — no cmd/main, not deployable.)
1. Shared libraries are mixed in as top-level components
CubeDB and cubelog are pure libraries: no cmd/main, not deployable
Yet they sit at the top level alongside real components like CubeMaster and Cubelet
The directory layout gives no way to tell "components" from "libraries"
2. Components depend on components
CubeMaster only uses 2 small packages inside Cubelet (the volumeplugin proto contract and one utility function)
Yet it replaces the entire Cubelet module for them
Inheriting Cubelet's full heavy dependency set (k8s, etc.)
Downstream costs this creates:
Docker build contexts must be the repository root, with Dockerfiles explicitly COPY-ing sibling directories (CubeMaster/docker/Dockerfile:20-29; the comment at Cubelet/Dockerfile:6 says "Build context MUST be the repository root").
Release builds are forced to serialize: Cubelet's make proto rewrites .pb.go files in place while the CubeMaster compiler is reading them (deploy/one-click/build-release-bundle-builder.sh:85-98: "can tear a .pb.go while the cubemaster compiler is reading it").
CI cross-component mappings are maintained by hand and have gaps (.github/workflows/unit-test-check.yml:170-200): CubeDB changes re-run CubeOps tests, but CubeMaster — which equally depends on CubeDB/Cubelet/cubelog — is not covered.
Dead config accumulates: the cubevs replace in CubeMaster/go.mod has no matching require; migration-check.yml has a path trigger pointing at the no-longer-existing CubeMaster/pkg/base/dao/migrate/**.
Proposed Solution
Introduce a top-level libs/ directory to gather shared libraries, with the target layout:
Key change: CubeMaster no longer replaces Cubelet, and shared dependencies are consolidated under libs/. cubevs is the eBPF datapath contract between Cubelet and CubeNet and is intentionally left out of this proposal.
Alternatives Considered
Keep as-is + document it: lowest cost, but the root build context, serialized releases, and CI mapping gaps remain, and the component-vs-library ambiguity persists.
go.work only, no directory changes: simplifies local development, but does not solve CubeMaster depending on the entire Cubelet module, nor CubeDB/cubelog sitting at the top level.
Publish versioned modules to a remote: full decoupling, but a heavy release process and slower iteration; a local libs/ is a prerequisite step toward it, not a conflict.
Additional Context
Extraction is low-risk: the two Cubelet packages CubeMaster actually imports are both leaf packages (generated pb code + a utility package depending only on strings), with no transitive dependency burden.
Problem / Motivation
There are multiple compile-time dependencies between sibling components in the Go modules of this monorepo, implemented via go.mod
replacedirectives pointing at sibling directories. As a result, "deployable components" and "shared libraries" are indistinguishable in the directory layout, which leads to a series of downstream costs in builds, CI, and releases.Current dependency graph
(The dashed box marks pure shared libraries — no cmd/main, not deployable.)
graph TD subgraph components ["Deployable components"] CubeMaster["CubeMaster"] CubeOps["CubeOps"] Cubelet["Cubelet"] ExampleRPC["examples/volume/cos/rpc"] end subgraph libs ["Pure shared libraries (no cmd/main, not deployable)"] CubeDB["CubeDB"] cubelog["cubelog"] cubevs["CubeNet/cubevs"] end CubeMaster --> CubeDB CubeMaster --> cubelog CubeMaster --> Cubelet CubeMaster -.-> cubevs CubeOps --> CubeDB CubeOps --> cubelog Cubelet --> cubevs Cubelet --> cubelog ExampleRPC --> Cubelet classDef lib fill:#f6f8fa,stroke:#999,stroke-dasharray: 5 5; class CubeDB,cubelog,cubevs lib;How each dependency is actually used (all via go.mod
replacepointing at sibling directories):CubeMaster/pkg/base/db/db.go:21etc.CubeMaster/pkg/volume/plugin/rpc/driver.go:19-20CubeMaster/go.mod:191CubeDB/daoetc.CubeOps/internal/store/db.go:10-13CubeOps/go.mod:18Cubelet/network/runtime/cubevs_adapter.go:13Cubelet/go.mod:210examples/volume/cos/rpc/go.mod:23The problems boil down to two points:
1. Shared libraries are mixed in as top-level components
2. Components depend on components
Downstream costs this creates:
CubeMaster/docker/Dockerfile:20-29; the comment atCubelet/Dockerfile:6says "Build context MUST be the repository root").make protorewrites.pb.gofiles in place while the CubeMaster compiler is reading them (deploy/one-click/build-release-bundle-builder.sh:85-98: "can tear a .pb.go while the cubemaster compiler is reading it")..github/workflows/unit-test-check.yml:170-200): CubeDB changes re-run CubeOps tests, but CubeMaster — which equally depends on CubeDB/Cubelet/cubelog — is not covered.replaceinCubeMaster/go.modhas no matching require;migration-check.ymlhas a path trigger pointing at the no-longer-existingCubeMaster/pkg/base/dao/migrate/**.Proposed Solution
Introduce a top-level
libs/directory to gather shared libraries, with the target layout:Dependencies after the change:
graph TD subgraph components ["Deployable components"] CubeMaster["CubeMaster"] CubeOps["CubeOps"] Cubelet["Cubelet"] ExampleRPC["examples/volume/cos/rpc"] end subgraph libs ["libs/"] cubedb["cubedb"] cubelog["cubelog"] volumeplugin["volumeplugin"] end cubevs["CubeNet/cubevs (unchanged)"] CubeMaster --> cubedb CubeMaster --> cubelog CubeMaster --> volumeplugin CubeOps --> cubedb CubeOps --> cubelog Cubelet --> cubelog Cubelet --> cubevs ExampleRPC --> volumeplugin classDef lib fill:#f6f8fa,stroke:#999,stroke-dasharray: 5 5; class cubedb,cubelog,volumeplugin lib;Key change: CubeMaster no longer replaces Cubelet, and shared dependencies are consolidated under
libs/. cubevs is the eBPF datapath contract between Cubelet and CubeNet and is intentionally left out of this proposal.Alternatives Considered
libs/is a prerequisite step toward it, not a conflict.Additional Context
strings), with no transitive dependency burden.libs/vspkgs/— open for discussion.