Repository navigation
feat(lifecycle): standalone control plane lifecycle - #7344
cuisongliu merged 57 commits into
Conversation
Whoa! Easy there, Partner!This PR is too big. Please break it up into smaller PRs. |
There was a problem hiding this comment.
🟡 Changes recommended
Lease cancellation is not consistently propagated through remote I/O and Kubernetes API operations, allowing lifecycle mutations after lock ownership is lost.
6 open findings
Propagate lease context through bootstrap transport operations · New Propagate cancellation through all blocking transport operations · New Use maintenance context for upgrade readiness polling · New Use maintenance context for worker deletion API calls · New Use repository-standard nolint gosec suppression syntax · New Use repository-standard nolint gosec suppression syntax · New
What changed in this PR
Adds standalone control-plane lifecycle management, including mode conversion, upgrades, membership changes, recovery journals, and diagnostics.
Changes:
- Adds standalone bootstrap, upgrade, reset, routing, and worker lifecycle flows.
- Adds lifecycle locking, recovery, cancellation handling, and CLI commands.
- Expands unit, integration, and E2E coverage.
| File | Description |
|---|---|
lifecycle/test/e2e/testhelper/utils/utils.go |
Logs host diagnostics on failure. |
lifecycle/test/e2e/testhelper/utils/diagnostics.go |
Adds host and K3s diagnostics. |
lifecycle/test/e2e/testhelper/cmd/sealosCmdOpts_timeout_test.go |
Removes obsolete option tests. |
lifecycle/test/e2e/testhelper/cmd/sealosCmdOpts_test.go |
Strengthens command argument tests. |
lifecycle/test/e2e/k3s_test.go |
Updates K3s image and readiness handling. |
lifecycle/test/e2e/e2e_test.go |
Reserves Kubernetes service ports. |
lifecycle/pkg/types/v1beta1/zz_generated.deepcopy.go |
Adds generated route-controller copies. |
lifecycle/pkg/types/v1beta1/utils.go |
Adds mode helpers and rootfs replacement cleanup. |
lifecycle/pkg/types/v1beta1/utils_test.go |
Tests same-version rootfs replacement. |
lifecycle/pkg/types/v1beta1/cluster.go |
Defines standalone mode configuration. |
lifecycle/pkg/runtime/kubernetes/worker_maintenance.go |
Adds identity-safe worker maintenance. |
lifecycle/pkg/runtime/kubernetes/upgrade_test.go |
Extends upgrade configuration tests. |
lifecycle/pkg/runtime/kubernetes/standalone/TESTING.md |
Documents standalone validation. |
lifecycle/pkg/runtime/kubernetes/standalone/testdata/mode-controller.Dockerfile |
Builds controller test fixture. |
lifecycle/pkg/runtime/kubernetes/standalone/route_controller_test.go |
Tests generated controller manifests. |
lifecycle/pkg/runtime/kubernetes/standalone/reset_baseline.go |
Reconstructs reset state safely. |
lifecycle/pkg/runtime/kubernetes/standalone/mode_test.go |
Tests mode conversion invariants. |
lifecycle/pkg/runtime/kubernetes/standalone/mode_routes_other.go |
Rejects routing on non-Linux systems. |
lifecycle/pkg/runtime/kubernetes/standalone/mode_routes_linux.go |
Manages owned Linux routes. |
lifecycle/pkg/runtime/kubernetes/standalone/mode_csr_test.go |
Tests CSR approval races and identity. |
lifecycle/pkg/runtime/kubernetes/standalone/mode_config.go |
Converts and persists kubelet configuration. |
lifecycle/pkg/runtime/kubernetes/standalone/membership.go |
Manages etcd membership and quorum. |
lifecycle/pkg/runtime/kubernetes/standalone/maintenance.go |
Adds host maintenance locking. |
lifecycle/pkg/runtime/kubernetes/standalone/files.go |
Adds recoverable file replacement. |
lifecycle/pkg/runtime/kubernetes/standalone/files_test.go |
Tests partial replacement recovery. |
lifecycle/pkg/runtime/kubernetes/standalone/e2e_test.go |
Adds opt-in standalone fixture activation. |
lifecycle/pkg/runtime/kubernetes/standalone/controller_update.go |
Implements controller updates. |
lifecycle/pkg/runtime/kubernetes/standalone/bootstrap_validation.go |
Validates bootstrap layouts. |
lifecycle/pkg/runtime/kubernetes/standalone_removal.go |
Implements standalone master removal. |
lifecycle/pkg/runtime/kubernetes/standalone_removal_test.go |
Tests removal identity safeguards. |
lifecycle/pkg/runtime/kubernetes/standalone_mode_test.go |
Tests mode routing and membership validation. |
lifecycle/pkg/runtime/kubernetes/runtime.go |
Dispatches standalone lifecycle operations. |
lifecycle/pkg/runtime/kubernetes/runtime_version_test.go |
Tests Kubernetes version selection. |
lifecycle/pkg/runtime/kubernetes/runtime_getter.go |
Adds rootfs version fallback. |
lifecycle/pkg/runtime/kubernetes/node.go |
Makes worker joins/deletions resumable. |
lifecycle/pkg/runtime/kubernetes/maintenance_context.go |
Wraps SSH operations with cancellation. |
lifecycle/pkg/runtime/kubernetes/maintenance_context_test.go |
Tests maintenance cancellation. |
lifecycle/pkg/runtime/kubernetes/kubeconfig.go |
Restarts static-pod containers safely. |
lifecycle/pkg/runtime/kubernetes/kubeconfig_test.go |
Tests static-pod restart commands. |
lifecycle/pkg/runtime/kubernetes/kubeadm.go |
Preserves endpoints and runtime settings. |
lifecycle/pkg/runtime/kubernetes/control_plane_mode_test.go |
Tests cluster-wide mode conversion. |
lifecycle/pkg/runtime/kubernetes/certs.go |
Restarts API servers after certificate updates. |
lifecycle/pkg/guest/guest.go |
Skips conflicting hooks on standalone masters. |
lifecycle/pkg/clusterfile/pre_process.go |
Supports recovery inventory loading. |
lifecycle/pkg/clusterfile/maintenance.go |
Adds local lifecycle locks and atomic writes. |
lifecycle/pkg/clusterfile/maintenance_test.go |
Tests mode locking and journals. |
lifecycle/pkg/clusterfile/maintenance_api.go |
Adds API leases and transition guards. |
lifecycle/pkg/clusterfile/join_preflight.go |
Journals host preflight completion. |
lifecycle/pkg/clusterfile/join_preflight_test.go |
Tests resumable preflight checks. |
lifecycle/pkg/clusterfile/clusterfile.go |
Adds reset-recovery loading option. |
lifecycle/pkg/bootstrap/maintenance_context_test.go |
Tests bootstrap deadlines. |
lifecycle/pkg/bootstrap/context.go |
Propagates maintenance context. |
lifecycle/pkg/bootstrap/bootstrap.go |
Journals standalone rootfs preflights. |
lifecycle/pkg/apply/reset.go |
Enables interrupted reset recovery. |
lifecycle/pkg/apply/processor/standalone_test.go |
Tests reset and scaling recovery. |
lifecycle/pkg/apply/processor/standalone_reset.go |
Adds resumable reset pipeline. |
lifecycle/pkg/apply/processor/rootfs_selection_test.go |
Tests committed rootfs selection. |
lifecycle/pkg/apply/processor/maintenance_context.go |
Connects processors to cancellation. |
lifecycle/pkg/apply/processor/interface.go |
Removes obsolete rootfs mounts. |
lifecycle/pkg/apply/processor/install.go |
Propagates lifecycle context during installs. |
lifecycle/pkg/apply/processor/delete.go |
Uses resumable standalone deletion. |
lifecycle/pkg/apply/processor/create.go |
Propagates lifecycle context during creation. |
lifecycle/pkg/apply/applydrivers/standalone_lifecycle_test.go |
Tests inventory recovery and synchronization. |
lifecycle/pkg/apply/applydrivers/control_plane_mode_test.go |
Tests lifecycle mode guards. |
lifecycle/cmd/sealos/cmd/switch.go |
Adds the sealos switch command group. |
lifecycle/cmd/sealos/cmd/root.go |
Registers the switch command. |
lifecycle/cmd/sealos/cmd/control_plane_mode.go |
Adds cluster-wide mode-switch CLI. |
lifecycle/cmd/sealos/cmd/control_plane_mode_test.go |
Tests switch flags and confirmation. |
lifecycle/cmd/sealos/cmd/cert.go |
Guards certificate maintenance with locks. |
lifecycle/cmd/sealctl/cmd/standalone.go |
Adds host bootstrap/reset utilities. |
lifecycle/cmd/sealctl/cmd/standalone_upgrade.go |
Adds local standalone upgrades. |
lifecycle/cmd/sealctl/cmd/root.go |
Registers standalone sealctl commands. |
lifecycle/cmd/sealctl/cmd/control_plane_mode.go |
Adds host-local mode switching. |
lifecycle/cmd/sealctl/cmd/control_plane_mode_test.go |
Tests host switch flag isolation. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7344 +/- ##
==========================================
- Coverage 61.86% 61.49% -0.38%
==========================================
Files 8 8
Lines 653 657 +4
==========================================
Hits 404 404
- Misses 202 206 +4
Partials 47 47 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
e631e55 to
8d94416
Compare
Generate dedicated read-only controller credentials for installation and mode conversion. Preserve native kubeadm component decoding during bootstrap and upgrades, and remove stale mode state during registered reset.
Signed-off-by: zijiren233 <pyh1670605849@gmail.com>
Signed-off-by: zijiren233 <pyh1670605849@gmail.com>
Signed-off-by: zijiren233 <pyh1670605849@gmail.com>
Signed-off-by: zijiren233 <pyh1670605849@gmail.com>
Signed-off-by: zijiren233 <pyh1670605849@gmail.com>
Signed-off-by: zijiren233 <pyh1670605849@gmail.com>
…otstrap Signed-off-by: zijiren233 <pyh1670605849@gmail.com>
…ts and early RBAC Merging a Clusterfile that restates default values appended duplicate enforceNodeAllocatable entries; kubelet rejects the duplicated list and refuses to start during bootstrap. Deduplicate the list after each merge. The controller credential readiness probe aborted on Forbidden before a fresh API server bootstrapped its default RBAC roles, failing the whole apply. Keep polling instead; the host context still bounds the wait.
Add --delete-master-nodes to 'sealos switch control-plane standalone'. Each master deletes its own registered Node object right after its kubelet runs standalone, guarded by the recorded registration UID, so the pod garbage collector can remove orphaned workloads. The flag defaults to off and is rejected for registered mode; reruns are idempotent.
8d94416 to
ecbfafd
Compare
A conversion to standalone only inherited routeController.image from the committed Clusterfile, while a fresh standalone install honored every field. Custom kubeconfig, config, table and protocol selections were silently dropped: a conversion after adding a master fell back to managed credentials without any warning, and an operator-provided kubeconfig had to be repeated on every invocation. Conversions now inherit each committed setting the operator did not select with a flag, and the mode commit persists the effective settings next to controlPlaneMode so later conversions and node additions reuse them. Registered conversions keep leaving the committed settings untouched.
The --check-only conversion preflight validated host files but never exercised admission, so a policy denying the managed route-controller RBAC only surfaced after a conversion had started and paused mid-flight. Preflight now server-side dry-runs every object the managed credential flow creates: the ServiceAccount, ClusterRole, ClusterRoleBinding, Role, RoleBinding and the token Secret. Validating admission sees dry-run requests, so denials appear in --check-only output with the offending object and webhook, while nothing is persisted. Existing objects are accepted; controllers rendered with a custom kubeconfig keep skipping credential work entirely. The admin client construction is shared with the real credential flow, and the token Secret dry-run carries the service-account name annotation API validation requires.
Clusters on cloud or overlay CNIs never consume the host routing table the controller programs, and the control plane resolves pod IPs directly, so deploying it there only costs an image, a static pod, and a kubeconfig. Add --route-controller-enabled (spec.routeController. enabled; nil keeps today's behavior) to sealos and sealctl. Disabling stops the static pod, removes its manifest, and drops the routes the controller owned; managed credentials are left in place for a later re-enable. The choice is committed to the Clusterfile and inherited by later conversions, installs, and joins, and every bootstrap, readiness, and credential step is skipped while disabled. Masters lose direct Service ClusterIP access, which is the documented trade-off.
f0e79dd to
c6d0341
Compare
Disabling stopped the static pod, its manifest, and its routes, but left the managed kubeconfig on every host and the shared ServiceAccount, token Secret, and RBAC objects in the API. A disabled cluster therefore kept a live credential it no longer used. A disabling update now records whether the replaced deployment used managed credentials and drops the generated kubeconfig with the rest of the host state. Once every host of a switch finishes disabled, the operator-side sealos deletes the shared identity; deleting it per host would revoke the token controllers on the remaining hosts still use. Objects without the managed label are refused, missing ones count as removed, and re-enabling recreates everything from scratch.
7853c4e to
85a9d9d
Compare
The controller scopes its routes with --pod-cidr, --service-cidr and
--router-cidr, but sealos only offered a config file path: the file had
to be distributed to every host by hand, a later switch regenerated
the manifest around it, and a joining master failed its preflight
until the file appeared. Operator policy like the worker CIDR allowed
to serve as a next hop deserves first-class management.
Add --route-controller-{pod,service,router}-cidr to sealos and sealctl.
Values are validated at the CLI, rendered as controller arguments,
inherited from the committed Clusterfile by later conversions, installs
and joins, and written back as spec.routeController.{podCIDR,
serviceCIDR,routerCIDR}. Passing an explicit empty flag clears a
selection and removes the key, restoring automatic discovery; an unset
flag keeps the saved value. --interface stays per-host and is not
persisted.
Installing a standalone cluster with the controller disabled wrote a baseline state whose ControllerDisabled stayed false while its manifest was empty: controller-config then failed with an invalid baseline, and a joining master consumed that broken seed. The join path also tried to pre-pull the controller image before bootstrap even when the plan deployed none, failing on the empty image name. Record ControllerDisabled from the bootstrap plan next to the manifest it explains, and pull the controller image only when the plan enables it. Verified by reinstalling the cluster from scratch with the controller disabled and joining two masters: no manifest, no credentials, no readiness wait, and a usable controller-config.
The public ECR gallery caps anonymous data transfer and shared GitHub runner addresses have exhausted the quota, so every run fails the remote pull specs with 429 toomanyrequests. mirror.gcr.io serves the same Docker Hub images without an anonymous quota; all four benchmark tags are available there.
|
🤖 says: cherry pick action finished successfully 🎉! |
feat(lifecycle): standalone control plane lifecycle (#7344) * feat: add standalone control plane lifecycle * fix: do not block mode switch on route readiness * feat: add standalone control-plane lifecycle * chore(standalone): add fixture license headers * fix(standalone): preserve fixture shebang * fix(standalone): annotate intentional probes and commands * fix(standalone): complete security checks and lifecycle regression * test(e2e): allow K3s pods time to start * test(e2e): align command option tests with current CLI * test(e2e): capture host state before failure cleanup * test(e2e): retain failure diagnostics under sudo * fix(kubernetes): restart containers when reloading API certificates * test(e2e): reserve service ports from ephemeral allocation * test(e2e): capture K3s startup diagnostics before reset * test(e2e): use K3s release with CoreDNS cache fix * fix(lifecycle): preserve standalone recovery and reset behavior * style(lifecycle): format recovery tests with repository formatters * refactor: simplify standalone lifecycle helpers and documentation * refactor: simplify lifecycle inventory and worker identity checks * refactor(lifecycle): group control-plane switches under dedicated subcommand * fix(lifecycle): align standalone kubeconfig handling with upstream * fix(lifecycle): satisfy lint after upstream rebase * test(lifecycle): preallocate switch command arguments * fix(lifecycle): remove stale Nodes when deleting standalone masters * chore(lifecycle): use standard full license headers * feat(lifecycle): persist custom route controller images * fix lifecycle review findings * chore(lifecycle): align standalone gosec annotations * chore(lifecycle): annotate controlled upgrade command execution * fix(lifecycle): preserve newer etcd during standalone upgrades * style(lifecycle): format etcd preservation message * docs(lifecycle): record sequential upgrade validation and port requirements * fix(lifecycle): publish standalone worker config without a Node * docs(lifecycle): shorten standalone usage and testing guides * fix(lifecycle): sync sealctl before control-plane switch * style(lifecycle): format sealctl switch synchronization * fix(lifecycle): preserve best-effort standalone reset behavior * fix(lifecycle): discard previous reset completion on mode conversion * feat(lifecycle): provision standalone controller credentials Generate dedicated read-only controller credentials for installation and mode conversion. Preserve native kubeadm component decoding during bootstrap and upgrades, and remove stale mode state during registered reset. * refactor(lifecycle): reuse standalone reset file cleanup * docs(lifecycle): remove hard wrapping from standalone paragraphs * refactor(lifecycle): simplify standalone file checks and host execution * test(lifecycle): handle retained Nodes in membership checks * fix(lifecycle): refresh shared certificates before adding masters * test(lifecycle): cover both token cache refresh paths * fix(lifecycle): terminate temporary registry with sync context * docs(lifecycle): clarify regression coverage and network prerequisites * fix(lifecycle): preserve cluster signing material after standalone bootstrap * fix(lifecycle): recover fresh standalone installs from doubled defaults and early RBAC Merging a Clusterfile that restates default values appended duplicate enforceNodeAllocatable entries; kubelet rejects the duplicated list and refuses to start during bootstrap. Deduplicate the list after each merge. The controller credential readiness probe aborted on Forbidden before a fresh API server bootstrapped its default RBAC roles, failing the whole apply. Keep polling instead; the host context still bounds the wait. * feat(switch): opt-in Node object cleanup for standalone conversion Add --delete-master-nodes to 'sealos switch control-plane standalone'. Each master deletes its own registered Node object right after its kubelet runs standalone, guarded by the recorded registration UID, so the pod garbage collector can remove orphaned workloads. The flag defaults to off and is rejected for registered mode; reruns are idempotent. * fix(switch): inherit and commit route-controller settings A conversion to standalone only inherited routeController.image from the committed Clusterfile, while a fresh standalone install honored every field. Custom kubeconfig, config, table and protocol selections were silently dropped: a conversion after adding a master fell back to managed credentials without any warning, and an operator-provided kubeconfig had to be repeated on every invocation. Conversions now inherit each committed setting the operator did not select with a flag, and the mode commit persists the effective settings next to controlPlaneMode so later conversions and node additions reuse them. Registered conversions keep leaving the committed settings untouched. * feat(switch): admission preflight for managed credentials The --check-only conversion preflight validated host files but never exercised admission, so a policy denying the managed route-controller RBAC only surfaced after a conversion had started and paused mid-flight. Preflight now server-side dry-runs every object the managed credential flow creates: the ServiceAccount, ClusterRole, ClusterRoleBinding, Role, RoleBinding and the token Secret. Validating admission sees dry-run requests, so denials appear in --check-only output with the offending object and webhook, while nothing is persisted. Existing objects are accepted; controllers rendered with a custom kubeconfig keep skipping credential work entirely. The admin client construction is shared with the real credential flow, and the token Secret dry-run carries the service-account name annotation API validation requires. * feat(switch): allow disabling the route controller Clusters on cloud or overlay CNIs never consume the host routing table the controller programs, and the control plane resolves pod IPs directly, so deploying it there only costs an image, a static pod, and a kubeconfig. Add --route-controller-enabled (spec.routeController. enabled; nil keeps today's behavior) to sealos and sealctl. Disabling stops the static pod, removes its manifest, and drops the routes the controller owned; managed credentials are left in place for a later re-enable. The choice is committed to the Clusterfile and inherited by later conversions, installs, and joins, and every bootstrap, readiness, and credential step is skipped while disabled. Masters lose direct Service ClusterIP access, which is the documented trade-off. * feat(switch): clean up credentials when disabling route-controller Disabling stopped the static pod, its manifest, and its routes, but left the managed kubeconfig on every host and the shared ServiceAccount, token Secret, and RBAC objects in the API. A disabled cluster therefore kept a live credential it no longer used. A disabling update now records whether the replaced deployment used managed credentials and drops the generated kubeconfig with the rest of the host state. Once every host of a switch finishes disabled, the operator-side sealos deletes the shared identity; deleting it per host would revoke the token controllers on the remaining hosts still use. Objects without the managed label are refused, missing ones count as removed, and re-enabling recreates everything from scratch. * feat(switch): persist route-controller CIDR selection The controller scopes its routes with --pod-cidr, --service-cidr and --router-cidr, but sealos only offered a config file path: the file had to be distributed to every host by hand, a later switch regenerated the manifest around it, and a joining master failed its preflight until the file appeared. Operator policy like the worker CIDR allowed to serve as a next hop deserves first-class management. Add --route-controller-{pod,service,router}-cidr to sealos and sealctl. Values are validated at the CLI, rendered as controller arguments, inherited from the committed Clusterfile by later conversions, installs and joins, and written back as spec.routeController.{podCIDR, serviceCIDR,routerCIDR}. Passing an explicit empty flag clears a selection and removes the key, restoring automatic discovery; an unset flag keeps the saved value. --interface stays per-host and is not persisted. * fix(switch): keep the disabled baseline consistent on bootstrap Installing a standalone cluster with the controller disabled wrote a baseline state whose ControllerDisabled stayed false while its manifest was empty: controller-config then failed with an invalid baseline, and a joining master consumed that broken seed. The join path also tried to pre-pull the controller image before bootstrap even when the plan deployed none, failing on the empty image name. Record ControllerDisabled from the bootstrap plan next to the manifest it explains, and pull the controller image only when the plan enables it. Verified by reinstalling the cluster from scratch with the controller disabled and joining two masters: no manifest, no credentials, no readiness wait, and a usable controller-config. * test(e2e): pull benchmark images from mirror.gcr.io The public ECR gallery caps anonymous data transfer and shared GitHub runner addresses have exhausted the quota, so every run fails the remote pull specs with 429 toomanyrequests. mirror.gcr.io serves the same Docker Hub images without an anonymous quota; all four benchmark tags are available there. --------- Signed-off-by: zijiren233 <pyh1670605849@gmail.com> Co-authored-by: zijiren <84728412+zijiren233@users.noreply.github.com>


Adds a managed lifecycle for kubeadm control planes that run static Pods without Node registration or mirror Pods. Registered mode remains the default. Existing clusters can switch in either direction while retaining Sealos scaling, upgrade, certificate and reset commands.
Usage
Switching supports cluster selection, per-host timeout and the existing confirmation mechanism. Controller options belong to the
standalonesubcommand. Existing clusters must useswitchto change modes; changing the mode throughapplyis rejected.For a new cluster, set the mode in its Clusterfile and use
sealos apply -f Clusterfile:Sealos generates the controller manifest, dedicated ServiceAccount/read-only RBAC and a private kubeconfig on each master, including added masters. Kubernetes issues the token through a ServiceAccount token Secret; controller credentials contain no administrator certificate or key. An explicit
--route-controller-kubeconfigselects administrator-managed credentials instead. Existing custom deployments can select automatic credentials with--route-controller-kubeconfig=''and, if already standalone,--update-controller.--update-controllerupdates an active controller's image, credential/config paths or reserved route table/protocol. Unspecified settings retain their saved values; the image override is persisted in the Clusterfile. The default image isghcr.io/labring-sigs/route-controller:0.1.0.Lifecycle behavior
sealos run <kubernetes-image>Mode conversion and recovery
All masters pass preflight before sequential conversion. Host baselines preserve original kubelet settings and Node metadata; the Clusterfile mode is committed after all masters complete. Locks, an API Lease and persistent journals coordinate operations and retries. Lease cancellation propagates through active SSH/SFTP operations and Kubernetes mutations.
Standalone conversion updates the active kubelet configuration and installs a systemd override that clears API credentials and disables registration. It starts route-controller and restarts kubelet immediately. It does not drain or delete Nodes, and does not wait for controller readiness during conversion. Administrators handle workload migration, stale Node/network cleanup and host reboots. Explicit controller updates and joins into an established cluster wait for controller readiness.
Reverse conversion obtains fresh kubelet credentials through the CSR API, removes the controller and its owned routes, removes generated host credentials, and restores registered settings. Shared controller RBAC remains available for reuse. Node metadata is restored under a temporary scheduling taint, followed by Node Ready and mirror Pod checks. Previously registered hosts return to their original service configuration; fresh standalone hosts receive a managed registered baseline.
Upgrades use public kubeadm CLI phases, CRI v1, etcd v3 and client-go, without kubeadm internal imports. Only kubeadm documents enter configuration migration; component settings are preserved separately and checked through native phase decoding. This avoids rejecting newer default fields that older kubeadm/kubelet accept with warnings. This composition is maintained by Sealos; upstream kubeadm does not provide a standalone lifecycle. Manifest staging uses a private mount namespace. Configuration backups and local-etcd snapshots are retained, but failures do not automatically restore etcd or downgrade components. Workers are cordoned without eviction; administrator cordons are preserved.
Requirements and scope
unshareandmount.Validation
Relevant package tests and diff-scoped lint pass. Real-cluster tests of automatic credentials cover missing-file preflight without mutations, registered-to-standalone conversion, control-plane deletion/readdition, restricted API permissions and reverse-conversion cleanup. Two fresh multi-master installations on Kubernetes 1.28.15 completed with worker-only Node registration. Registered reset followed by reinstallation confirmed mode-state cleanup without manual intervention. A subsequent same-version
sealos runupgraded all masters and workers successfully. Native configuration checks accept newer unknown fields, reject invalid field types, and leave active kubelet configuration and process unchanged.Pod IP and DNS Service access passed in this round. API ClusterIP access from standalone hosts still requires CNI troubleshooting; this PR does not configure CNI forwarding or masquerading.
Earlier integration rounds cover ordinary/standalone scaling, repeated mode conversion, same-version retries and sequential Kubernetes upgrades from 1.28 through 1.33.6. These are historical coverage, not a full rerun of every scenario at the current head. External etcd, the 3.5-to-3.6 transition and broader failure/patch layouts still need dedicated coverage. Opt-in integration fixtures are separate from ordinary PR CI.
Operational details and test entry points are in
lifecycle/pkg/runtime/kubernetes/standalone/README.mdandTESTING.md. Current CI results are reported in the PR Checks tab.