Take ownership of Helm-managed resources
Use a one-time server-side apply takeover when an existing Helm release should become part of a Kix cluster. The Kix definition must render the same resources before you transfer ownership.
This guide uses the Reflector chart. Perform the takeover during a normal change window.
Save the release configuration
Section titled “Save the release configuration”Record the installed chart and values:
❱ helm list --namespace reflector-system❱ helm get values reflector --namespace reflector-system --all --output yaml > reflector.values.yaml❱ helm get manifest reflector --namespace reflector-system > reflector.manifest.yaml Keep these files until the migrated release has been deployed and checked. They provide the inputs and rendered resources you need for comparison.
Define the same chart in Kix
Section titled “Define the same chart in Kix”Pin the installed chart version and use the same release name:
instances.reflector-system.reflector = { package = kix.helmChart { repo = "https://emberstack.github.io/helm-charts"; name = "reflector"; version = "10.0.60"; hash = "sha256-UdCVcUqJogyUYmGo1HnQ1fMxY7ZEV56+9wQSJfWOhVM="; releaseName = "reflector"; }; };Copy the release’s non-default values into config.values. Do not proceed with
different chart values merely because the Kix definition evaluates.
Check the cluster without contacting Kubernetes:
❱ kix check how-to-helm-bridge
TOOL RESULT DETAILS
eval pass 11 manifests evaluated
kubeconform pass skipped (this validation tool is not yet integrated with Kix)
pluto pass skipped (this validation tool is not yet integrated with Kix)
kyverno pass skipped (this validation tool is not yet integrated with Kix)
scorecard pass 0 errors, 5 warnings, 2 info Inspect the rendered Deployment:
❱ kix build how-to-helm-bridge --output json
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "reflector",
"namespace": "reflector-system"
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"app.kubernetes.io/instance": "reflector",
"app.kubernetes.io/name": "reflector"
}
},
"serviceAccountName": "reflector",
"containers": [
{
"name": "reflector",
"image": "docker.io/emberstack/kubernetes-reflector:10.0.60"
}
]
}
} Save the complete Kix output, then compare each resource from the Helm manifest with the resource of the same kind, namespace, and name:
❱ kix build how-to-helm-bridge --output yaml > reflector.kix.yaml The Kix output also contains Kix tracking resources. Chart resources gain Kix management metadata and lose Helm release metadata, test hooks, and fields that only repeat Kubernetes defaults. Correct any other difference before deploying.
Confirm the ownership conflict
Section titled “Confirm the ownership conflict”Ask the API server to validate the takeover without persisting it:
❱ kix deploy how-to-helm-bridge --dry-run -y Show output
⚠ ClusterRole/reflector field-ownership conflict on ClusterRole/reflector: another field manager owns one or more fields kix is trying to set. Re-run with --force-conflicts to take ownership. Underlying error: ApiError: Apply failed with 1 conflict: conflict with "helm" using rbac.authorization.k8s.io/v1: .metadata.labels.app.kubernetes.io/managed-by: Conflict (ErrorResponse { status: "Failure", message: "Apply failed with 1 conflict: conflict with \"helm\" using rbac.authorization.k8s.io/v1: .metadata.labels.app.kubernetes.io/managed-by", reason: "Conflict", code: 409 })
✗ halt-on-first-failure: field-ownership conflict on ClusterRole/reflector: another field manager owns one or more fields kix is trying to set. Re-run with --force-conflicts to take ownership. Underlying error: ApiError: Apply failed with 1 conflict: conflict with "helm" using rbac.authorization.k8s.io/v1: .metadata.labels.app.kubernetes.io/managed-by: Conflict (ErrorResponse { status: "Failure", message: "Apply failed with 1 conflict: conflict with \"helm\" using rbac.authorization.k8s.io/v1: .metadata.labels.app.kubernetes.io/managed-by", reason: "Conflict", code: 409 })
Dry run complete: 2 created, 2 configured, 0 unchanged, 1 failed, 6 cancelled
(exit code: 1) The conflict identifies fields still owned by Helm. Review those fields against the saved manifest and values. If the Kix output is not meant to replace them, change the Kix definition instead of forcing the deployment.
By default, the run stops after the first conflict and ends with 1 failed, 6 cancelled. A chart takeover may conflict on several resources. Run the dry
run again with --on-error continue to check the remaining resources:
❱ kix deploy how-to-helm-bridge --dry-run -y --on-error continue This still skips resources that depend on a failed resource, but continues checking independent branches of the dependency graph.
Transfer resource ownership
Section titled “Transfer resource ownership”Once the rendered resources are equivalent, deploy once with
--force-conflicts:
❱ kix deploy how-to-helm-bridge --force-conflicts -y
~ Deployment/reflector@reflector-system configured
✔ Deployment/reflector@reflector-system ready
• activation 'how-to-helm-bridge-7zjjps55cybw' → Active
Deploy complete: 4 created, 7 configured, 0 unchanged, 0 failed Check the workload before changing the Helm release record:
❱ kix status how-to-helm-bridge❱ kubectl rollout status deployment/reflector --namespace reflector-system Remove the Helm release record
Section titled “Remove the Helm release record”Helm stores release records as Secrets. Delete the record only after Kix owns the resources and the workload is healthy:
❱ kubectl delete secret --namespace reflector-system --selector owner=helm,name=reflector
secret "sh.helm.release.v1.reflector.v1" deleted from reflector-system namespace This leaves the workload in place but makes the release unavailable to future
helm upgrade and helm uninstall commands. Retain the saved values and
manifest with your migration records.
Use ordinary kix deploy how-to-helm-bridge commands after the takeover. Do
not keep --force-conflicts in routine commands.
For more about defining chart-backed packages, see Use Helm charts through the Kix Helm bridge.