Skip to content

drop client-go for kubernetes access#6

Merged
solsson merged 3 commits intomainfrom
drop-client-go
Apr 29, 2026
Merged

drop client-go for kubernetes access#6
solsson merged 3 commits intomainfrom
drop-client-go

Conversation

@solsson
Copy link
Copy Markdown
Contributor

@solsson solsson commented Apr 29, 2026

To save 30 MB binary size after we switched to shellout for yconverge in #3. Maybe not worth the added lines of code.

Yolean k8s-qa and others added 3 commits April 28, 2026 14:25
… poll

Replaces the SharedInformerFactory + Secret watch with a vanilla
http.Client poll against /api/v1/namespaces/<ns>/secrets. The
backend's public surface (Routes, ServeHTTP, Health, Close) is
unchanged; the test suite's behaviour assertions all still pass.

Why:
- 4 MB shaved off the stripped binary today (77 MB -> 73 MB).
  More to come once pkg/k8sapply / pkg/k8swait / pkg/kubeconfig
  also drop client-go in steps 2 and 3 of the migration.
- A long watch with apiserver-side timeouts, 410 Gone resume,
  resourceVersion bookkeeping and Bookmark events is ~200 lines
  of careful state machine. For our scale (a handful of Secrets,
  consumer tolerates seconds of staleness) a 5-second poll is
  ~40 lines that anyone can read.

Implementation:
- pkg/serve/kubeclient.go is rewritten end-to-end. It builds a
  k8sClient (server URL + http.Client + bearer + namespace) from
  either in-cluster mounts (SA token + CA + KUBERNETES_SERVICE_HOST)
  or a kubeconfig file (hand-rolled YAML schema, no clientcmd).
  Same auth resolution chain as before: explicit Kubeconfig/Context,
  then in-cluster, then default kubeconfig location.
- pkg/serve/ykustomizeincluster.go drops the informer in favour
  of a goroutine that ticks every PollInterval (default 5s) and
  calls listSecrets. The route table swap is the same atomic
  RWMutex pattern. Refresh errors are logged and the loop
  continues -- a transient apiserver hiccup keeps serving the
  last known routes.
- YKustomizeInClusterConfig gains a PollInterval field
  (time.Duration, default 5s).

Test rewiring:
- Unit tests: replace the fake.Clientset path with a fakeSecretStore
  that implements the new secretLister interface against an
  in-memory map. testPoll = 50ms keeps mutations propagating fast
  enough for the existing waitForRouteCount deadlines.
- New unit tests cover the kubeconfig parser (the kwok-shape
  HTTP-no-auth schema) and the labelSelector URL encoding on the
  http.Client GET.
- E2E TestServe_InCluster: unchanged; passes against kwok with
  the new HTTPS poll path. mutation-to-served propagation lands
  in <5s on the default poll interval, well under the existing
  30s deadline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…swait

envoygateway.Install was the only consumer of pkg/k8sapply.ApplyYAML
and pkg/k8swait.RolloutStatus. Switching them to kubectl shellouts
matches what yconverge already does and lets us delete both
packages along with their k8s.io/client-go dependency surface.

Apply path:

    kubectl --context=X apply --server-side --force-conflicts \
      --field-manager=y-cluster -f -

with the manifest piped on stdin. CRD-then-CR ordering is handled
by kubectl itself: it retries on RESTMapping errors so the EG
release manifest's leading CRD section is in place by the time
the in-namespace objects land. Field manager `y-cluster` matches
yconverge's so a re-apply under either path doesn't fight.

Wait path:

    kubectl --context=X rollout status deployment/envoy-gateway \
      -n envoy-gateway-system --timeout=<dur>

Stdout / stderr forward to the host process so the operator
sees the same `<kind>/<name> serverside-applied` and rollout
progress lines kubectl prints when run directly.

pkg/k8sapply and pkg/k8swait are removed wholesale.

Binary size after this step: 39 MB stripped, down from 73 MB
(after step 1) and 77 MB at origin/main. The bulk of the drop is
k8s.io/client-go's typed API + apimachinery -- pkg/kubeconfig
and pkg/cluster still use clientcmd, that gets handled in step 3.

E2E coverage:
- e2e/envoygateway_test.go: TestEnvoyGateway_InstallAgainstKwok
  and TestEnvoyGateway_InstallSkipGatewayClass run unchanged
  against kwok and pass with the kubectl-shellout path. The
  test asserts CRDs land, namespace + deployment + service
  exist, and the GatewayClass points at EG's controller.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…o entirely

Replaces the last two consumers of k8s.io/client-go/tools/clientcmd
with a typed kubeconfig schema (sigs.k8s.io/yaml under the hood):

- pkg/kubeconfig: new schema.go declares File / NamedCluster /
  NamedContext / NamedUser etc. with the kubeconfig YAML field
  tags; Load / Parse / Save read and round-trip the format. The
  Manager (CleanupStale / Import / CleanupTeardown) now operates
  on those typed structs. Empty cluster/context/user lists serialise
  as `[]` (kubie-friendly) directly from initialised-empty slices,
  so the post-write fixNullLists string-replace pass is gone.
- pkg/cluster/lookup.go's readClusterName: switched from
  clientcmd.NewDefaultClientConfigLoadingRules + cfg.Contexts
  map to kubeconfig.Load + ContextCluster. Honors the same
  $KUBECONFIG -> ~/.kube/config search.

Binary size: 35 MB stripped, down from 39 MB after step 2 and
77 MB at origin/main. End state: no k8s.io/client-go imports
anywhere; the only remaining k8s.io refs are an indirect
kube-openapi pull through kustomize and sigs.k8s.io/json --
both light, neither typed-API surface.

Test coverage:
- pkg/kubeconfig: existing Import / CleanupStale tests still
  exercise the merge + rename paths through the new schema.
  fixNullLists tests dropped (the post-write fix is no longer
  needed); replaced with TestSave_EmptyListsAsBrackets pinning
  the `[]` output shape and TestLoad_MissingFileEmptyConfig
  pinning the "fresh KUBECONFIG" baseline.
- pkg/cluster: lookup tests pass unchanged.
- e2e: full kwok-tag suite green (yconverge ordering,
  envoygateway, converge-mode, converge-progress, serve-incluster
  -- everything that touches kubeconfig parsing or apiserver
  HTTP).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@solsson solsson merged commit 6c21aca into main Apr 29, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant