Skip to content

Instantly share code, notes, and snippets.

@dims
Last active June 6, 2026 22:53
Show Gist options
  • Select an option

  • Save dims/8fdfd022d555525490384eddd6aed611 to your computer and use it in GitHub Desktop.

Select an option

Save dims/8fdfd022d555525490384eddd6aed611 to your computer and use it in GitHub Desktop.
Kubernetes Dependency Analysis (v1.37.0-alpha / master vs v1.36.1) -- depstat

Kubernetes Dependency Analysis

Generated by depstat at commit 643e407efef on branch master (the v1.37 development cycle). Analysis date: 2026-06-06. Compared against: v1.36.1 (latest stable patch of the 1.36 line). depstat version: 45eb8b409b5280a128d6bcbc974952c599954e1d (Fix why --svg/--dot timeout on highly-connected deps like OTel).


1. Executive Summary

Metric Value
Total unique dependencies 269
Direct dependencies 187
Transitive dependencies 234
Test-only dependencies 34
Non-test dependencies 235
Dependency graph max depth 18
Dependency cycles 17
Archived dependencies 5
Main modules (go.work) 34 (1 root + 33 staging)

Direct and transitive overlap — a module can be required both directly by a workspace module and transitively through others. Test-only (34) + non-test (235) partition the 269 total exactly.

Key Findings

  • The total rose +14 (255 → 269), but that is mostly a counting artifact — not real new surface. depstat counts module paths, and the net +14 is exactly the go-openapi family's 14 new module paths: 12 swag/* sub-modules + 2 go-openapi/testify modules (all v0.25.4), produced when go-openapi split its formerly-monolithic swag module into per-directory modules. Same functionality, more nodes — no new upstream projects. The only genuinely-new non-go-openapi modules number 3 (golang.org/x/perf + aclements/go-moremath, and otel/metric/x), and they are cancelled one-for-one by the 3 removals (§7.2). So the distinct-upstream-project count is effectively flat — a softer reading than the raw "+14", and a contrast with the previous cycle, which trimmed 11 outright. (The +8 direct / +12 transitive split moves with the same go-openapi additions.)
  • The swag split, and its upside. go-openapi re-published swag's subdirectories as 12 independent module paths (11 of them vendored, plus a jsonutils/fixtures_test helper; swag itself v0.23.0 → v0.25.4) so callers import only the piece they need (swag/conv, swag/jsonutils, swag/mangling, …). The payoff is real: it let Kubernetes drop swag's old reflection-based helpers mailru/easyjson, josharian/intern, and stoewer/go-strcase (§7.4). So by distinct-project count the tree is arguably leaner, even as the module count rose.
  • github.com/cenkalti/backoff/v4 is fully retired. The previous analysis flagged it as a vendor-only leftover after the v5 migration; it is now gone from the module graph entirely — the migration completed.
  • github.com/golang/groupcache removed — an unwanted-list module eliminated — along with github.com/grpc-ecosystem/go-grpc-middleware.
  • etcd jumped to a 3.7 release candidate: go.etcd.io/etcd/{api,client/pkg,client,pkg,server}/v3 v3.6.8 → v3.7.0-rc.0, raft/v3 → v3.7.0-rc.1, bbolt → v1.5.0-rc.0. Master is now tracking pre-release etcd ahead of the 1.37 storage work.
  • gRPC v1.79.3 → v1.81.1; OpenTelemetry core v1.41.0 → v1.44.0 (contrib instrumentation v0.65 → v0.68); a broad golang.org/x/* refresh.
  • golang.org/x/net pinned to a HEAD pseudo-version (v0.55.1-0.20260602153038-42abb857022c) to pick up the Go 1.27 HTTP/2 "wrap" fixes — a forward-looking toolchain-compatibility pin, not yet a tagged release.
  • 17 cycles, down from 19. The previously-detected onsi/ginkgo/v2 ↔ onsi/gomega and stretchr/objx ↔ stretchr/testify test-framework cycles are gone — only the forward edges survive; the reverse requirements dropped out at gomega v1.40.0 / objx v0.5.2. All 17 remaining cycles are upstream; OpenTelemetry accounts for 8.
  • Archived count steady at 5, but the membership changed. github.com/kr/pty dropped out (the call sites moved to creack/pty); github.com/envoyproxy/protoc-gen-validate v1.3.3 newly appears — it is simultaneously archived upstream and on Kubernetes' unwanted list.
  • sigs.k8s.io/randfill (v1.0.0) has reached 54 fan-in. The google/gofuzz replacement that the last analysis flagged as "in progress" is now the standard — gofuzz has 0 first-party imports and survives only as a transitive dep of json-iterator/go.
  • github.com/go-logr/logr (v1.4.3) remains the single highest-fan-in non-plumbing external library — 79 direct dependents (63 k8s.io/*).
  • gopkg.in/yaml.v3 fan-in fell 91 → 81 (k8s.io 54 → 46) as modules migrate to go.yaml.in/yaml and sigs.k8s.io/yaml; it stays on the unwanted list and persists purely transitively via etcd, OTel, testify, and Prometheus.
  • Go toolchain steady at 1.26.0 — no bump in this window (the 1.25 → 1.26 jump landed in the previous cycle).

2. Module Architecture

Kubernetes uses a go.work monorepo with vendored dependencies and a staging publication mechanism unique in the Go ecosystem.

k8s.io/kubernetes/
├── go.work              -> workspace covering root + 33 staging modules (go 1.26.0)
├── go.mod               -> k8s.io/kubernetes  (root module)
├── vendor/              -> vendored copy of all external dependencies (217 modules)
└── staging/src/         -> 33 k8s.io/* staging repos
    ├── k8s.io/api/
    ├── k8s.io/apimachinery/
    ├── k8s.io/apiserver/
    ├── k8s.io/client-go/
    └── ... 29 more

Key architectural properties:

  • All k8s.io/* staging modules are part of the workspace and share a single vendor directory.
  • External dependencies are vendored at the root and deduplicated across all 34 modules.
  • depstat traverses the full go.work graph, not just the root module.

34 modules detected in go.work (unchanged set since v1.36.1 — no new staging modules in 1.37-dev yet; cri-streaming and streaming, new last cycle, are now established): k8s.io/api, k8s.io/apiextensions-apiserver, k8s.io/apimachinery, k8s.io/apiserver, k8s.io/cli-runtime, k8s.io/client-go, k8s.io/cloud-provider, k8s.io/cluster-bootstrap, k8s.io/code-generator, k8s.io/component-base, k8s.io/component-helpers, k8s.io/controller-manager, k8s.io/cri-api, k8s.io/cri-client, k8s.io/cri-streaming, k8s.io/csi-translation-lib, k8s.io/dynamic-resource-allocation, k8s.io/endpointslice, k8s.io/externaljwt, k8s.io/kms, k8s.io/kube-aggregator, k8s.io/kube-controller-manager, k8s.io/kube-proxy, k8s.io/kube-scheduler, k8s.io/kubectl, k8s.io/kubelet, k8s.io/kubernetes, k8s.io/metrics, k8s.io/mount-utils, k8s.io/pod-security-admission, k8s.io/sample-apiserver, k8s.io/sample-cli-plugin, k8s.io/sample-controller, k8s.io/streaming


3. Dependency Statistics

Direct Dependencies:    187
Transitive Dependencies: 234
Total (deduplicated):   269
Max Depth:               18

Test-only:               34
Non-test:               235

Test-only fraction: 34 of 269 total dependencies (12.6%) are test-only — up 3 since the 1.36 line (31), tracking the go-openapi/testify/v2 and golang.org/x/perf test additions. Max depth dropped by one (19 → 18).


4. Fan-in Ranking (Top External Dependencies)

Fan-in = number of edges in go mod graph pointing into a package (a proxy for how many modules pull it). Higher fan-in = more structurally load-bearing. The synthetic go toolchain node (155) tops the raw list and is excluded as plumbing.

Rank Fan-in Module
1 97 github.com/davecgh/go-spew ⚠️ unwanted
2 90 github.com/pmezard/go-difflib
3 88 google.golang.org/protobuf
3 88 github.com/stretchr/testify
5 83 gopkg.in/yaml.v3 ⚠️ unwanted
6 79 github.com/go-logr/logr
7 63 github.com/google/go-cmp
8 61 go.yaml.in/yaml/v2
9 54 sigs.k8s.io/randfill 🆕
9 54 go.yaml.in/yaml/v3 🆕
9 54 github.com/modern-go/reflect2 ⚠️ unwanted
9 54 github.com/modern-go/concurrent ⚠️ unwanted
13 53 github.com/json-iterator/go ⚠️ unwanted, archived
13 53 github.com/google/uuid
15 52 sigs.k8s.io/structured-merge-diff/v6
15 52 sigs.k8s.io/json
15 52 gopkg.in/inf.v0
15 52 google.golang.org/genproto/googleapis/rpc
15 52 github.com/x448/float16
20 51 sigs.k8s.io/yaml
20 51 github.com/spf13/pflag
20 51 github.com/fxamacker/cbor/v2
23 49 go.opentelemetry.io/otel
24 48 google.golang.org/grpc

⚠️ = listed in hack/unwanted-dependencies.json; 🆕 = notable mover vs. the previous analysis.

Two structural shifts stand out versus the prior cycle:

  • sigs.k8s.io/randfill (54) has entered the top tier. It is the actively-developed replacement for the archived github.com/google/gofuzz, and its fan-in now rivals the modern-go and json-iterator cluster.
  • The YAML story is fragmenting deliberately. go.yaml.in/yaml/v2 (61) and go.yaml.in/yaml/v3 (54) — the maintained canonical paths — now sit alongside the still-present-but-unwanted gopkg.in/yaml.v3 (83). The high fan-in of the unwanted go-spew (97), yaml.v3 (83), and json-iterator/go (53) continues to reflect how deeply embedded these are transitively (testify, etcd, OTel all require them).

5. Dependency Cycles

17 cycles detected (down from 19 in the previous analysis). Every cycle originates in upstream ecosystem packages; Kubernetes' own k8s.io/* staging repos maintain perfectly acyclic internal layering.

Cycle Length Count
2 9
3 4
4 3
5 1

All 17 Cycles

# Cycle
1 github.com/golang/protobufgoogle.golang.org/protobufgithub.com/golang/protobuf
2 github.com/prometheus/client_golanggithub.com/prometheus/commongithub.com/prometheus/client_golang
3 go.opentelemetry.io/auto/sdkgo.opentelemetry.io/otelgo.opentelemetry.io/auto/sdk
4 auto/sdkotelotel/metricauto/sdk
5 auto/sdkotel/traceotelauto/sdk
6 auto/sdkotel/traceotelotel/metricauto/sdk
7 go.opentelemetry.io/otelotel/metricotel
8 otelotel/metricotel/traceotel
9 go.opentelemetry.io/otelotel/traceotel
10 go.opentelemetry.io/otel/sdkotel/sdk/metricotel/sdk
11 golang.org/x/cryptogolang.org/x/netgolang.org/x/crypto
12 golang.org/x/cryptogolang.org/x/textgolang.org/x/toolsgolang.org/x/netgolang.org/x/crypto
13 golang.org/x/cryptogolang.org/x/textgolang.org/x/modgolang.org/x/toolsgolang.org/x/netgolang.org/x/crypto
14 golang.org/x/modgolang.org/x/toolsgolang.org/x/mod
15 golang.org/x/modgolang.org/x/toolsgolang.org/x/netgolang.org/x/textgolang.org/x/mod
16 golang.org/x/netgolang.org/x/textgolang.org/x/toolsgolang.org/x/net
17 google.golang.org/genproto/googleapis/apigoogle.golang.org/grpcgoogle.golang.org/genproto/googleapis/api

What changed: two test-framework cycles dissolved

The previous analysis listed onsi/ginkgo/v2 ↔ onsi/gomega and stretchr/objx ↔ stretchr/testify as cycles. Both are gone. Only the forward edges remain in the graph (ginkgo@v2.28.3 → gomega@v1.40.0, testify@v1.11.1 → objx@v0.5.2); the reverse requirements (gomega → ginkgo, objx → testify) are no longer present at the selected versions, so the loops no longer close. This is the entire 19 → 17 delta.

Top Cycle Participants

Module Cycle Count
go.opentelemetry.io/otel 7
golang.org/x/net 5
golang.org/x/tools 5
go.opentelemetry.io/auto/sdk 4
go.opentelemetry.io/otel/metric 4
go.opentelemetry.io/otel/trace 4
golang.org/x/text 4
golang.org/x/crypto 3
golang.org/x/mod 3

OpenTelemetry accounts for 8 of the 17 cycles. This is a known upstream design: the OTel Go SDK splits its API across otel, otel/metric, otel/trace, and the no-op auto/sdk, which mutually reference each other for interface definitions. All API modules resolve to v1.44.0, while auto/sdk v1.2.1 still pins down-level v1.38.0 requirements that Go's minimal-version selection raises to v1.44.0 (the dashed red edges below):

OTel dependency cycles

The golang.org/x/* packages account for 6 cycles through the well-known x/cryptox/netx/textx/toolsx/mod web of mutual test and toolchain imports.


6. Archived Dependencies

Current State (5 archived modules)

Module Version Risk Notes
github.com/envoyproxy/protoc-gen-validate v1.3.3 Medium 🆕 Archived upstream and on the unwanted list. Superseded by buf.build/go/protovalidate; pulled transitively by google.golang.org/grpc (xDS/Envoy proto validation).
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 Low Simple shell lexer; stable, minimal attack surface.
github.com/google/btree v1.1.3 Low Functionally complete B-tree; no security surface.
github.com/google/gofuzz v1.0.0 Low First-party migration to sigs.k8s.io/randfill (54 fan-in) is complete (0 first-party uses); now survives only as a transitive dep of json-iterator/go.
github.com/json-iterator/go v1.1.12 Medium 0 first-party imports; enters the build only via sigs.k8s.io/structured-merge-diff/v6 (server-side apply). The 53 fan-in is transitive (and pulls modern-go/*). See §10.

What changed since v1.36.1

  • Removed from the archived set: github.com/kr/pty — the call sites moved to the maintained github.com/creack/pty, so kr/pty left the graph.
  • Newly flagged: github.com/envoyproxy/protoc-gen-validate v1.3.3 — envoyproxy archived the repository in favor of buf.build/go/protovalidate. It was bumped v1.3.0 → v1.3.3 in this window even as it became archived.

The count is unchanged at 5, but it is not the same 5.

Unresolved (non-GitHub hosts — 11)

depstat archived can only verify GitHub-hosted repos. These are hosted elsewhere and were not checked programmatically (all are actively maintained): bitbucket.org/bertimus9/systemstat, buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go, cyphar.com/go-pathrs 🆕, gonum.org/v1/gonum, google.golang.org/protobuf, gopkg.in/check.v1, gopkg.in/evanphx/json-patch.v4, gopkg.in/go-jose/go-jose.v2, gopkg.in/inf.v0, gopkg.in/natefinch/lumberjack.v2, gopkg.in/yaml.v3.

cyphar.com/go-pathrs is new this cycle — it is runc's safe-path-resolution library, pulled in through the container runtime stack.


7. Release Diff: v1.36.1 → master (643e407efef)

Summary Metrics

┌────────────────────────┬──────────┬─────────────────┬─────────┐
│ Metric                 │  v1.36.1 │  master HEAD    │  Delta  │
├────────────────────────┼──────────┼─────────────────┼─────────┤
│ Direct Dependencies    │      179 │             187 │      +8 │
│ Transitive Dependencies│      222 │             234 │     +12 │
│ Total (deduplicated)   │      255 │             269 │     +14 │
│ Max Depth              │       19 │              18 │      −1 │
└────────────────────────┴──────────┴─────────────────┴─────────┘

Module graph: +17 added, −3 removed, ~69 version changes. Vendor: +11 added, −3 removed, ~55 version changes. Note: v1.36.1 sits at 255 total — essentially identical to the master snapshot the previous analysis measured (the 1.36 line shipped at that surface). But the +14 is not genuinely new dependency surface — see §7.1: it is the go-openapi module-count expansion (one module re-published as many), with the handful of real new deps offset one-for-one by removals.

7.1 Dependencies Added (+17)

The 17 additions split into 14 go-openapi-family modules and 3 genuinely-new ones:

  • 14 go-openapi — 12 swag/* sub-modules + 2 go-openapi/testify modules, all v0.25.4. This is a granularity change: go-openapi re-published one module as many, inflating the module count without adding a new upstream dependency or new functionality.
  • 3 genuinely newgolang.org/x/perf, its aclements/go-moremath statistics dependency, and the experimental otel/metric/x. These are exactly offset by the 3 removals in §7.2, so the count of distinct upstream projects is effectively flat.

Full list:

Module Category Notes
github.com/go-openapi/swag/conv OpenAPI swag split into granular sub-modules (v0.25.4)
github.com/go-openapi/swag/fileutils OpenAPI "
github.com/go-openapi/swag/jsonname OpenAPI "
github.com/go-openapi/swag/jsonutils OpenAPI "
github.com/go-openapi/swag/loading OpenAPI "
github.com/go-openapi/swag/mangling OpenAPI "
github.com/go-openapi/swag/netutils OpenAPI "
github.com/go-openapi/swag/stringutils OpenAPI "
github.com/go-openapi/swag/typeutils OpenAPI "
github.com/go-openapi/swag/yamlutils OpenAPI "
github.com/go-openapi/swag/cmdutils OpenAPI "
github.com/go-openapi/swag/jsonutils/fixtures_test OpenAPI test fixture sub-module
github.com/go-openapi/testify/v2 Test go-openapi's vendored testify fork
github.com/go-openapi/testify/enable/yaml/v2 Test "
golang.org/x/perf Benchmarking benchmark/statistics tooling
github.com/aclements/go-moremath Benchmarking statistics lib pulled by x/perf
go.opentelemetry.io/otel/metric/x Observability experimental OTel metric extensions (pulled by otel/sdk/metric v1.44)

7.2 Dependencies Removed (−3)

Module Notes
github.com/cenkalti/backoff/v4 v5 migration completed — previously a vendor-only leftover, now fully gone
github.com/golang/groupcache Unwanted-list caching library eliminated
github.com/grpc-ecosystem/go-grpc-middleware Removed (the /v2 and /providers/prometheus sub-modules remain)

7.3 Notable Version Bumps

Module Before After Notes
go toolchain 1.26.0 1.26.0 Unchanged this cycle
google.golang.org/grpc v1.79.3 v1.81.1 +2 minor
go.opentelemetry.io/otel (+ metric/trace) v1.41.0 v1.44.0 core OTel
go.opentelemetry.io/otel/sdk (+ sdk/metric) v1.40.0 v1.44.0 +4
go.opentelemetry.io/contrib/.../otel{restful,grpc,http} v0.65.0 v0.68.0 instrumentation
go.etcd.io/etcd/*/v3 v3.6.8 v3.7.0-rc.0 release candidate
go.etcd.io/raft/v3 v3.6.0 v3.7.0-rc.1 RC
go.etcd.io/bbolt v1.4.3 v1.5.0-rc.0 RC
golang.org/x/net v0.49.0 v0.55.1-0.20260602…42abb857022c HEAD pseudo-version (Go 1.27 http2 fixes)
golang.org/x/crypto v0.47.0 v0.52.0 + broad x/{sys,text,tools,mod,term,oauth2,sync,time} refresh
github.com/go-openapi/swag v0.23.0 v0.25.4 drove the module split (§7.1)
github.com/go-openapi/jsonpointer v0.21.0 v0.22.4
github.com/go-openapi/jsonreference v0.20.2 v0.21.4
github.com/google/cel-go v0.26.0 v0.27.0 CEL engine
github.com/google/cadvisor v0.56.2 v0.57.0 cAdvisor
github.com/moby/moby/api / client v1.52.0 / v0.2.1 v1.54.1 / v0.4.0 Moby split modules
sigs.k8s.io/structured-merge-diff/v6 v6.3.2 v6.4.0 SSA core
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 v2.29.0
cloud.google.com/go/compute/metadata v0.9.0 v0.7.0 rare downgrade, but not vendored → no build impact

The cloud.google.com/go/compute/metadata downgrade (v0.9.0 → v0.7.0) is only a module-graph resolution shift: the module is not vendored at either ref, so nothing is compiled from it and there is no build impact. (It is a transitive requirement no vendored package imports; with module-graph pruning the graph-selected version can move either direction.)

7.4 Vendor Changes

Vendored Modules: 209 → 217 (+8)
Added (11):   all eleven github.com/go-openapi/swag/* sub-modules @ v0.25.4
Removed (3):  josharian/intern, mailru/easyjson, stoewer/go-strcase
Vendor-only removals (still in module graph, no longer vendored):
              josharian/intern, mailru/easyjson, stoewer/go-strcase

The three vendor removals are the old swag dependencies: mailru/easyjson (reflection-based JSON), its helper josharian/intern, and stoewer/go-strcase (case conversion). The rewritten swag (v0.25.x) replaced them with its own conv/jsonutils/mangling sub-packages. They remain in the module graph as unselected transitive requirements but no vendored package imports them — the same divergence pattern the previous analysis flagged for backoff/v4 (now resolved).

7.5 Diff Visualization

Green = added, Red = removed, Yellow = version changed.

Dependency diff: v1.36.1 → master HEAD

View raw SVG


8. Full Dependency Graph

Full Kubernetes dependency graph — 269 nodes, master HEAD 643e407efef

View raw SVG

The full graph shows the characteristic hub-and-spoke structure: k8s.io/kubernetes at the center with its 187 direct edges, surrounded by a ring of staging repos each pulling 60–110 dependencies, and an outer shell of third-party libraries. The k8s.io staging cluster is densely interconnected but perfectly acyclic — all detected cycles originate in upstream ecosystem packages (§5).


9. Why-Traces: Key Dependencies

Why-trace targets are chosen by fan-in rank (computed from go mod graph) plus architectural significance, excluding golang.org/x/* (toolchain cross-deps) and k8s.io/* (workspace-internal). The same seven targets as the previous analysis are used here so the two runs are directly comparable.

9.1 Why is github.com/go-logr/logr included?

Fan-in rank: #6 | Direct dependents: 79 total (63 k8s.io/*) | Selected version: v1.4.3

go-logr/logr is the structured-logging interface used throughout Kubernetes and nearly all of its staging modules, decoupling logging call sites from the backend (klog/v2 is the concrete implementation). It remains the single highest-fan-in non-plumbing external library. Unchanged in version since v1.36.1; stable and actively maintained, with no replacement on the horizon.

Why go-logr/logr

View raw SVG


9.2 Why is gopkg.in/yaml.v3 included?

Fan-in rank: #5 | Direct dependents: 81 total (46 k8s.io/*) | Selected version: v3.0.1

yaml.v3 is on Kubernetes' unwanted-dependencies list — the preferred alternatives are sigs.k8s.io/yaml and the maintained go.yaml.in/yaml/*. Its dependent count has fallen (91 → 81 total, 54 → 46 k8s.io/*) as workspace modules migrate, but it persists because major transitive dependencies still require it directly: go.etcd.io/etcd/*, go.opentelemetry.io/*, github.com/stretchr/testify, github.com/prometheus/common, github.com/google/cadvisor, and the gRPC-middleware packages. Eliminating it requires coordinated upstream changes.

Why gopkg.in/yaml.v3

View raw SVG


9.3 Why is google.golang.org/grpc included?

Fan-in rank: #24 | Direct dependents: 48 total (31 k8s.io/*) | Selected version: v1.81.1

gRPC is Kubernetes' core RPC transport: the API server (aggregated APIs, CRI, CSI, device plugins), the etcd client, OTel exporters, and konnectivity all depend on it. Bumped v1.79.3 → v1.81.1 in this window.

Why gRPC

View raw SVG


9.4 Why is go.opentelemetry.io/otel included?

Fan-in rank: #23 | Direct dependents: 49 total (35 k8s.io/*) | Selected version: v1.44.0

OTel is the tracing/metrics framework adopted for observability — the API server, kubelet, scheduler, and controller-manager all emit spans and metrics through it. The high k8s.io/* share (35 of 49) shows how pervasively the instrumentation is applied. Core OTel advanced v1.41.0 → v1.44.0 this cycle, and it is also pulled transitively by gRPC (which bundles OTel for metrics).

Why OpenTelemetry

View raw SVG


9.5 Why is github.com/prometheus/client_golang included?

Direct dependents: 33 total (27 k8s.io/*) | Selected version: v1.23.2

Prometheus client_golang is the metrics-exposition library — every Kubernetes component exposes a /metrics endpoint in Prometheus format. Also pulled transitively by the gRPC middleware and the OTel→Prometheus bridge. Unchanged in version since v1.36.1.

Why Prometheus client_golang

View raw SVG


9.6 Why is github.com/google/cel-go included?

Direct dependents: 20 total (19 k8s.io/*) | Selected version: v0.27.0

CEL (Common Expression Language) powers ValidatingAdmissionPolicy, authorization policy, and CRD validation rules. It is used only by apiserver-tier staging modules; the low absolute count (20) with a near-total k8s share (19) shows it is a first-party dependency with minimal transitive spread. Bumped v0.26.0 → v0.27.0.

Why cel-go

View raw SVG


9.7 Why is go.etcd.io/etcd/client/v3 included?

Direct dependents: 16 total (15 k8s.io/*) | Selected version: v3.7.0-rc.0

etcd is Kubernetes' primary storage backend. The API server depends on etcd/client/v3 directly, and integration-test utilities pull it too. The low fan-in (16) reflects that only apiserver-tier modules deal with etcd directly. This cycle moved the entire etcd stack onto a 3.7 release candidate (v3.6.8 → v3.7.0-rc.0) — a notable choice to track pre-release storage on master.

Why etcd client/v3

View raw SVG


10. Recommendations

Methodology note: each item below was checked against the actual module graph and first-party .go imports at this HEAD — not inferred from package names. Notably, none of the unwanted/archived libraries are imported by first-party Kubernetes code anymore (all are transitive), which is what makes the levers below upstream-shaped.

High Priority

  • Re-pin golang.org/x/net to a tagged release. It is currently a HEAD pseudo-version (v0.55.1-0.20260602…) carried for the Go 1.27 http2 "wrap" fixes. Move to the next tagged x/net once those land in a release, to satisfy verify-vendor/supply-chain expectations.
  • Land the etcd 3.7 line on final tags before the 1.37 freeze. Master tracks etcd/* v3.7.0-rc.0, raft v3.7.0-rc.1, bbolt v1.5.0-rc.0. Riding an RC on master is normal etcd co-development, but the pins should advance to GA (etcd 3.7.0, bbolt 1.5.0) before freeze.
  • Migrate sigs.k8s.io/structured-merge-diff/v6 off github.com/json-iterator/go — the single highest-leverage cleanup. json-iterator (archived) has zero first-party imports in Kubernetes; it enters the compiled build through exactly one importer — structured-merge-diff/v6 (value.go, fieldpath/serialize*.go), used in server-side apply. SMD is a kubernetes-sigs library, so this is in-scope, and it cascades: dropping json-iterator also removes github.com/modern-go/{concurrent,reflect2} (54 fan-in each) and github.com/google/gofuzz (which now survives only as json-iterator's transitive dep). Caveat: SMD uses json-iterator for SSA-serialization performance, so a replacement must be benchmarked. (prometheus/client_golang also lists json-iterator in go.mod, but its vendored code never imports it.)

Medium Priority

  • github.com/envoyproxy/protoc-gen-validate (archived + unwanted) — pulled by google.golang.org/grpc (its xDS/Envoy proto validation), not by first-party code. Nothing to migrate directly; it drops when gRPC moves to buf.build/go/protovalidate. Track the gRPC change.
  • gopkg.in/yaml.v3 (81 fan-in, unwanted) — also 0 first-party imports, trending down (91 → 81) as the ecosystem moves to go.yaml.in/yaml and sigs.k8s.io/yaml. Now purely transitive (etcd, OTel, testify, Prometheus), so removal depends on those upstreams. Keep blocking new direct uses in k8s code as policy.
  • github.com/google/btree, github.com/flynn/go-shlex (archived, low risk) — monitor for supply-chain events; no action needed.

Low Priority

  • First-party code is already clean — worth recording. Kubernetes' own packages import none of the high-fan-in unwanted/archived libraries: go-spew, yaml.v3, json-iterator, gofuzz, and modern-go/{concurrent,reflect2} all have 0 first-party imports. Every one persists purely transitively, so all remaining cleanup is upstream-driven (High/Medium above) — and on the first-party side, the gofuzzrandfill migration is effectively done.
  • github.com/davecgh/go-spew (97 fan-in, unwanted) — pulled by testify (test scope); disappears if/when testify drops it.
  • Vendor-only removals (mailru/easyjson, josharian/intern, stoewer/go-strcase) — removed from vendor/ but still in the module graph. Verify they don't re-vendor on the next go mod tidy; prune from go.mod if unneeded.

11. Reproducibility

All commands were run from a detached git worktree of k8s.io/kubernetes pinned at commit 643e407efef84a7bd37ef23d9ed4ec0ddc123571 (Merge pull request #139532 from serathius/watchcache-waituntilfresh-cleanup), go 1.26.0.

depstat version: 45eb8b409b5280a128d6bcbc974952c599954e1d (built from sigs.k8s.io/depstat).

Fan-in ranking command (determines why-trace selection):

go mod graph | awk '{print $2}' | sed 's/@.*//' \
  | grep -v '^k8s.io/' | grep -v '^golang.org/x/' \
  | sort | uniq -c | sort -rn | head -25

Why-trace targets (data-driven from fan-in, held constant vs. the prior run for comparability):

  • github.com/go-logr/logr (79, rank #6)
  • gopkg.in/yaml.v3 (81, rank #5 — unwanted, shown to explain persistence)
  • google.golang.org/grpc (48, rank #24)
  • go.opentelemetry.io/otel (49, rank #23)
  • github.com/prometheus/client_golang (33)
  • github.com/google/cel-go (20)
  • go.etcd.io/etcd/client/v3 (16)

Exact commands:

# Build depstat
cd $HOME/go/src/sigs.k8s.io/depstat && go build -o /tmp/depstat .

# From the kubernetes worktree root:
/tmp/depstat stats -d .
/tmp/depstat stats -d . --split-test-only
/tmp/depstat cycles -d .
/tmp/depstat cycles -d . --summary
GITHUB_TOKEN="$(gh auth token)" /tmp/depstat archived -d . --json

# Release diff (--vendor bundles module-level + vendor-level diff)
/tmp/depstat diff -d . v1.36.1 HEAD --vendor

# SVGs (graph/diff print a module-detection prefix -> awk-filter to the SVG)
/tmp/depstat graph -d . --svg | awk '/^<\?xml/{f=1} /^<svg/{f=1} f' > k8s-full-graph.svg
/tmp/depstat diff  -d . v1.36.1 HEAD --svg | awk '/^<\?xml/{f=1} /^<svg/{f=1} f' > k8s-diff-v1361-master.svg

# Why-traces (why --svg emits clean SVG)
for t in github.com/go-logr/logr gopkg.in/yaml.v3 google.golang.org/grpc \
         go.opentelemetry.io/otel github.com/prometheus/client_golang \
         github.com/google/cel-go go.etcd.io/etcd/client/v3; do
  slug="${t//\//_}"; slug="${slug//./_}"
  /tmp/depstat why -d . "$t" --svg --max-paths 50 > "k8s-why-${slug}.svg"
done

# OTel cycles diagram is hand-authored (depstat cycles --svg is an unsupported placeholder):
#   graphviz dot built from `depstat cycles` + the inter-OTel edges of `go mod graph`.
dot -Tsvg k8s-otel-cycles.dot -o k8s-otel-cycles.svg

# Direct-dependent counts
for t in github.com/go-logr/logr gopkg.in/yaml.v3 google.golang.org/grpc \
         go.opentelemetry.io/otel github.com/prometheus/client_golang \
         github.com/google/cel-go go.etcd.io/etcd/client/v3; do
  go mod graph | grep " ${t}@" | awk -F'@' '{print $1}' | sort -u | wc -l
done
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment