Skip to content

[epic]: remove the eksctl binary dependency from the EKS distribution #7116

Description

@devantler

🤖 Generated with Claude Code in an interactive session with the maintainer.

User Story

As a KSail user targeting AWS,
I want ksail cluster create --distribution EKS to work with nothing installed but KSail itself,
So that EKS behaves like every other distribution instead of being the one that fails at the PATH lookup.

Context

KSail's stated contract is that it embeds its tooling as Go libraries: "Docker is the only required external dependency for local clusters". EKS is the single exception — pkg/svc/provisioner/cluster/eks shells out to an eksctl binary via pkg/client/eksctl, and pkg/apis/cluster/v1alpha1.ErrEksctlBinaryMissing is the error users hit when it is absent. GKE and AKS already use their native Go SDKs (pkg/client/gke, pkg/client/aks), so EKS is the odd one out in its own package family.

This is a migration, not a restart. #4328 is at 16/18 sub-issues and the native path is already half-built — this epic finishes the direction that repo has been travelling, it does not reverse it:

  • pkg/client/eks is already an AWS SDK v2 client doing DescribeCluster, EKS bearer-token minting (presigned STS GetCallerIdentity), nodegroup reads, and CloudFormation stack checks.
  • The control-plane upgrade already moved off the binary. ADR 0001 replaced eksctl upgrade cluster with the SDK's UpdateClusterVersion. eksctl.Client.UpgradeCluster now has no production callers — only tests. That is dead weight today.
  • The SDK dependencies are already in go.mod as direct requires: aws-sdk-go-v2 core, config, credentials, cloudformation, eks, sts (iam is indirect).

What still shells out

Every remaining call lives in pkg/client/eksctl/commands.go:

Operation Invocation Native replacement
Create cluster create cluster --config-file … --timeout 45m the hard one — see #7117
Create nodegroup create nodegroup --config-file … CreateNodegroup
Delete cluster delete cluster --config-file|--name … DeleteCluster + stack teardown
List/get clusters get cluster [--name] -o json ListClusters / DescribeCluster
List nodegroups get nodegroup --cluster … -o json ListNodegroups / DescribeNodegroup
Scale nodegroup scale nodegroup --nodes … UpdateNodegroupConfig
Upgrade cluster upgrade cluster --config-file … already done (ADR 0001) — shim is unused

Blast radius outside the client

pkg/svc/provisioner/cluster/eks/{creation,update,provisioner}.go · pkg/svc/provider/aws/{provider,nodegroup_state,errors}.go · pkg/svc/clusterdiscovery/{cloud,availability}.go (both gate EKS discovery on the binary being on PATH) · pkg/cli/cmd/cluster/info.go · pkg/apis/cluster/v1alpha1/errors.go · .github/workflows/system-test-eks.yaml (downloads an eksctl release) and .github/scripts/delete-eks-smoke-cluster.sh · seven pages under docs/src, plus docs/gen_docs_prose.go and AGENTS.md.

*.eksctl.io kubeconfig context parsing (pkg/svc/detector/cluster/context.go, pkg/cli/setup/localregistry/resolve.go, vsce/src/ksail/contexts.ts) is not in scope for removal — those contexts exist on every cluster the CLI ever created and must keep parsing forever.

Constraint: the eksctl declarative file stays authoritative

eks.yaml remains a valid eksctl ClusterConfig (apiVersion: eksctl.io/v1alpha5). This is non-negotiable and the migration should improve compliance, not weaken it.

Today creation.go parses the file with yaml.UnmarshalStrict into an untyped map[string]any plus a hand-rolled typed subset covering only managedNodeGroups — everything else is passed through to the binary unvalidated by KSail. The binary is currently the only thing that checks the schema.

github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5 publishes ClusterConfig along with ValidateClusterConfig, SetClusterConfigDefaults, SetNodeGroupDefaults and SetManagedNodeGroupDefaults. Adopting those types means KSail validates eks.yaml with the same code eksctl uses, so schema fidelity is guaranteed by construction rather than by re-implementation.

pkg.go.dev reports that package's import graph as light — k8s apimachinery, aws-sdk-go-v2, hashicorp/go-version, sigs.k8s.io/yaml, kris-nova/logger, and eksctl's own utils/awsapi — with no pkg/ctl, pkg/actions, kops, cfssl, kubicorn or amazon-ec2-instance-selector. That is the tree pkg/client/eksctl/doc.go cites as the reason not to embed, and it appears to apply to pkg/actions/cluster, not to the API types. Confirm with go mod graph before committing to it (#7117).

Licensing

KSail ships under PolyForm Shield 1.0.0 — source-available with a noncompete clause, not OSI-approved. That makes inbound license hygiene a real constraint rather than a formality.

  • eksctl (github.com/weaveworks/eksctl, still the module path) is reported by pkg.go.dev as Apache-2.0. Apache-2.0 is permissive with no copyleft, so linking it into a PolyForm-licensed binary is permitted.
  • The obligation is new, because shelling out distributes nothing. Today KSail ships no eksctl code. Embedding triggers Apache-2.0 §4 on every release artifact: include the license text, propagate any upstream NOTICE, retain copyright/patent notices, and mark modified files if anything is vendored or forked.
  • Apache-2.0 §6 grants no trademark rights. Keep "eksctl-compatible configuration" as a factual interoperability statement; never imply endorsement by eksctl, Weaveworks or AWS.
  • The actual risk is transitive, and it must be measured rather than assumed. A single GPL/AGPL/LGPL/SSPL/BUSL dependency reaching the linked binary is a genuine problem for a source-available product distributed via GoReleaser and Homebrew. KSail has no license scanning today — that gap is a prerequisite, not a footnote.

Migration plan

Each phase is independently shippable and leaves main releasable. Phases 2–7 become sub-issues once #7117 has sized them.

  • Phase 0 — cleanup and guardrail. Delete the unused UpgradeCluster shim. Add a CI license gate (go-licenses or equivalent) with an allowlist, so the dependency question is answered automatically from here on. No behaviour change.
  • Phase 1 — spike ([spike]: decide how KSail creates an EKS cluster without the eksctl binary #7117). Decide the create strategy: (a) import eksctl's CloudFormation template builders and drive CFN via the SDK, preserving eksctl-<cluster>-* stack names and full CLI interoperability; or (b) provision natively with EKS/EC2/IAM SDK calls, matching how pkg/client/gke and pkg/client/aks work. Output is an ADR plus follow-up issues — no PR.
  • Phase 2 — schema. Parse and validate eks.yaml through upstream v1alpha5 types. The binary still does the work; user-visible effect is better error messages, earlier.
  • Phase 3 — reads. Move get cluster / get nodegroup to the SDK. After this, ksail cluster info, cluster discovery and availability no longer need the binary at all.
  • Phase 4 — scale. scale nodegroupUpdateNodegroupConfig.
  • Phase 5 — create and delete, behind spec.cluster.eks.experimentalNativeProvisioning, default off, per the repo's existing spec.cluster.eks.experimental* convention. The binary path stays the default.
  • Phase 6 — flip the default after a green live smoke run. The binary path survives one release as an opt-out.
  • Phase 7 — removal. Delete pkg/client/eksctl and ErrEksctlBinaryMissing, drop the eksctl download from CI, update docs and AGENTS.md.

What "non-breaking" means here

  1. eks.yaml stays an eksctl ClusterConfig v1alpha5 — no KSail-proprietary schema, ever.
  2. Clusters created by the eksctl CLI stay fully manageable (CloudFormation stacks, eksctl-* stack names, *.eksctl.io contexts).
  3. Clusters created natively stay manageable by the eksctl CLI — or [spike]: decide how KSail creates an EKS cluster without the eksctl binary #7117 records precisely where that breaks and why the trade is worth it.
  4. No flag or config field is removed without a release of deprecation.
  5. Every behaviour-changing phase ships gated and is tested in both states.

Acceptance Criteria

  • CI fails on a dependency whose license is outside an explicit allowlist, and the current tree passes that gate.
  • Apache-2.0 §4 obligations are satisfied in the release artifacts: license text shipped, upstream NOTICE propagated, notices retained.
  • go mod graph confirms the embedded eksctl packages do not pull pkg/ctl, pkg/actions, kops, cfssl, kubicorn or amazon-ec2-instance-selector — or [spike]: decide how KSail creates an EKS cluster without the eksctl binary #7117 records the measured cost and the decision taken.
  • The unused eksctl.Client.UpgradeCluster shim is gone.
  • An ADR in docs/adr/ records the create strategy and its interoperability trade-offs.
  • eks.yaml is parsed and validated through upstream v1alpha5 types; a malformed config is rejected by KSail with a clear error before any AWS call.
  • ksail cluster info, cluster discovery and availability work with no eksctl on PATH.
  • ksail cluster create/delete/update complete end to end with no eksctl on PATH, proven by a green live EKS smoke run.
  • A cluster created by the eksctl CLI is still discoverable, updatable and deletable by KSail.
  • pkg/client/eksctl and ErrEksctlBinaryMissing are deleted; *.eksctl.io context parsing is retained.
  • The eksctl download is removed from .github/workflows/system-test-eks.yaml and .github/scripts/delete-eks-smoke-cluster.sh.
  • Docs and AGENTS.md no longer list eksctl as a prerequisite, and the support matrix reflects the native path.

Out of scope

Completing the remaining KSail-managed component installers on EKS (#4328) and the EKS Auto Mode question. This epic changes how KSail talks to AWS, not what it installs afterwards.

References

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions