How-to guide Adopt existing resources
Take ownership of kubectl-managed resources
Move an existing kubectl-managed workload under Kix without changing immutable selectors.
Use a one-time server-side apply takeover when an existing resource was
applied with kubectl and should now be managed by Kix.
This guide uses a Deployment as the example. Back up the live resource first, and perform the takeover during a normal change window.
Record the live resource
Section titled “Record the live resource”Save the resource before changing its ownership:
❱ kubectl get deployment legacy-web -n takeover -o yaml --show-managed-fields > legacy-web.before.yaml Keep any fields your workload relies on, especially immutable selectors,
Service selectors, volume claims, and identity-bearing names. The
managedFields section also shows which manager owns each part of the object.
Make the Kix definition match
Section titled “Make the Kix definition match”Configure the package instance with the live Deployment’s selector and the state you want Kix to manage:
instances.takeover.legacy-web = { package = webPackage;
# Keep the live Deployment's immutable selector. selectorLabels = { app = "legacy-web"; tier = "frontend"; };
config = { replicas = 2; environment = "production"; message = "This workload is managed by Kix"; }; };The example retains the existing app and tier selector. Its desired replica
count is two, while the kubectl-managed fixture has one replica.
Check the cluster before contacting Kubernetes:
❱ kix check how-to-adoption-takeover
TOOL RESULT DETAILS
eval pass 11 manifests evaluated
scorecard pass 0 errors, 6 warnings, 1 info Inspect the rendered Deployment:
❱ kix build how-to-adoption-takeover --output json
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "legacy-web",
"namespace": "takeover"
},
"spec": {
"replicas": 2,
"selector": {
"matchLabels": {
"app": "legacy-web",
"tier": "frontend"
}
},
"template": {
"metadata": {
"labels": {
"app": "legacy-web",
"app.kubernetes.io/name": "legacy-web",
"tier": "frontend"
}
},
"spec": {
"containers": [
{
"name": "nginx",
"image": "docker.io/library/nginx:1.27-alpine"
}
]
}
}
}
} Compare it with legacy-web.before.yaml. Do not continue if the rendered
resource changes an immutable selector or omits a field the workload still
needs. Correct the package configuration first.
Confirm the ownership conflict
Section titled “Confirm the ownership conflict”Run an API-server dry run without taking ownership:
❱ kix deploy how-to-adoption-takeover --dry-run -y Show outputHide output · 4 lines
⚠ Deployment/legacy-web@takeover cannot update Deployment/legacy-web@takeover: another tool owns fields that Kix is trying to change. Review the fields listed below. If Kix should manage them, rerun with --force-conflicts to take ownership; if the other tool is meant to own them, declare them on the resource with `ownership.cede`. Kubernetes reported: ApiError: Apply failed with 1 conflict: conflict with "kubectl": .spec.replicas: Conflict (ErrorResponse { status: "Failure", message: "Apply failed with 1 conflict: conflict with \"kubectl\": .spec.replicas", reason: "Conflict", code: 409 })
✗ halt-on-first-failure: cannot update Deployment/legacy-web@takeover: another tool owns fields that Kix is trying to change. Review the fields listed below. If Kix should manage them, rerun with --force-conflicts to take ownership; if the other tool is meant to own them, declare them on the resource with `ownership.cede`. Kubernetes reported: ApiError: Apply failed with 1 conflict: conflict with "kubectl": .spec.replicas: Conflict (ErrorResponse { status: "Failure", message: "Apply failed with 1 conflict: conflict with \"kubectl\": .spec.replicas", reason: "Conflict", code: 409 })
Dry run complete: 3 created, 2 configured, 0 unchanged, 1 failed, 4 cancelled
(exit code: 1) Kix discovers live state through its management labels, so kix diff does not
compare a resource that Kix has not managed before. The deployment dry run
sends the intended manifests to the API server without persisting them.
The API server rejects a change when another field manager owns a field Kix is
trying to change. The error identifies the resource and points to
--force-conflicts.
The dry run carries on past a conflict, so the plan lists every conflicting
resource with the manager that owns each field. Review every reported field
against the saved resource before using --force-conflicts.
Take ownership once
Section titled “Take ownership once”When the diff and conflicting fields are expected, deploy with
--force-conflicts:
❱ kix deploy how-to-adoption-takeover --force-conflicts -y
~ Deployment/legacy-web@takeover configured
✔ Deployment/legacy-web@takeover ready
• activation 'how-to-adoption-takeover-3gdjlxrhh7h4' → Active
Deploy complete: 6 created, 4 configured, 0 unchanged, 0 failed The flag tells server-side apply to transfer conflicting fields in the Kix
manifest to the kix field manager. Fields that Kix does not specify remain
with their existing managers.
Check the result and save its field ownership:
❱ kix status how-to-adoption-takeover❱ kubectl get deployment legacy-web -n takeover -o yaml --show-managed-fields > legacy-web.after.yaml Use ordinary kix deploy how-to-adoption-takeover commands after the takeover.
Do not leave --force-conflicts enabled for routine deployments, because a
later conflict may represent another controller making an intentional change.