design: component workload overrides - #587
Open
Philip Lombardi (plombardi89) wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
designs/component-workload-overrides.md, a proposal for letting userscustomize the Deployments and DaemonSets that unbounded-operator generates and
reconciles.
Design doc only. No code, no CRD changes, no
make generate.Why
Today a user's entire influence over operator-managed workloads is
spec.components.<c>.enabled,metalman.replicas,metalman.dhcpAutoInterface,and the cluster-wide
--image-registryflag. Because the operator applies withSSA and
ForceOwnership(internal/operator/component/env.go:242), there is noworkaround either: a
kubectl editis reverted on the next reconcile and aGitOps controller will fight the operator indefinitely.
The requirements collected from users and the team are resources, tolerations /
nodeSelector / affinity, sidecars and volumes, env vars, command arguments,
imagePullSecrets, labels / annotations / priorityClassName, and container
images.
Decisions this PR is asking you to ratify
1. Kustomize as a library is rejected. This was the team's initial
suggestion, so §4.1 argues it explicitly rather than dismissing it. Five
reasons, the two load-bearing ones being:
no pruning (
machina.go:57-69). An overlay that renames a DaemonSet orphansthe original permanently.
Siteis cluster-scoped and the operator SA installs CRDs, ClusterRoles,webhooks, and privileged host-networked DaemonSets. An overlay is arbitrary
object creation with those credentials. Patching an existing pod template is a
materially smaller grant.
Also: it would freeze
deploy/*/rendered/layout and every object name in it aspublic API, and promote
sigs.k8s.io/kustomize/apifrom transitive(
go.mod:336) to direct.2. Strategic merge patch against operator-emitted workloads instead.
apimachinery/util/strategicpatch, no new dependency. Everything in therequirements list lives inside a Deployment or DaemonSet the operator already
emits, so nothing needs object creation or renaming. Merge keys verified against
k8s.io/api@v0.36.3.3. Stored in a ConfigMap, not
Site.spec. Thenet/machina/gantrysingletons are resolved as "any Site enables it" (
machina.go:47-55), so aper-Site override field is ambiguous when Sites disagree. A cluster-scoped
ConfigMap dissolves that entirely and avoids a
v1beta1conversion obligation.4. The mechanism is supported; individual patches are not. §2 splits these
explicitly. The schema, merge semantics, validation, and revert behavior are
versioned and maintained. That any given patch stays correct as generated
manifests change, or that an overridden component works or upgrades, is not.
5. Image overrides are permitted. They break the version-lockstep invariant
(
main.go:207,manifests_guard_test.go), so §9 makes the drift loud via aversion-driftannotation, aReconciledWithOverridescondition reason, and anEvent, rather than blocking it.
6. This reverses a documented stance.
site_types.go:141-143andarchitecture.md:189both currently say components are not configurable. §1quotes both; PR 6 in the implementation plan amends them.
Consequence worth flagging early
kubectl unbounded overrides diffcannot diff against the live object, becausethe live object already has the override applied. It needs the operator's
pre-patch render, and today rendering is fused into applying: the mutators are
unexported (
net.go:115,machina.go:123,gantry.go:187,storage.go:223)and metalman's builder is unexported and typed (
metalman.go:98).So
diffrequires extracting aRendercapability from all five components.That is sequenced as its own behavior-preserving PR (§12, PR 4) ahead of
diff(PR 5). It stands on its own merits, but nobody should be surprised by it later.
Implementation sequence (§12)
ApplyObjectgate, watch. No component file changes.overrides listandoverrides validateoverrides diffarchitecture.md:189andsite_types.go:141-143Open questions for reviewers (§15)
Please reply against the numbers.
overrides diffoutput format: unified YAML diff, or path-oriented summaryby default?
ValidatingAdmissionPolicyon theConfigMap? It can only do partial validation, since resolving
componentandsitesneeds cluster state.spec.replicasin a patch vs the existing typedspec.components.metalman.replicas(site_types.go:167). Which wins, orshould overrides reject
spec.replicason metalman?siteSelector(label-based Site matching) is deferred in favour of asitesname list. Agree?
resources" case? It is more correct than patching resources to a fixed value.
Review notes
designs/is not published to the docs site (docs.yamlonly fires ondocs/**), so this is internal.ci.yamlhas no path filter, so the full matrix runs on this docs-only PR andshould pass trivially.
Draft for team review. It flips toAcceptedin a final commit onthis branch once the open questions are resolved, then squash merge.