Skip to content

Preserve existing selectors

This content is for the v0.1 version. Switch to the latest version for up-to-date documentation.

Kubernetes does not allow a Deployment or StatefulSet selector to change in place. Before Kix takes ownership of an existing workload, configure its instance to retain that selector.

Get the selector from the live workload:

❱ kubectl get deployment legacy-web -n apps -o jsonpath='{.spec.selector.matchLabels}'

Use the labels from spec.selector.matchLabels, not every label on the workload. Confirm that the Pod template has the same labels before continuing.

Copy those labels into selectorLabels:

how-to/adoption/cluster.nix (L69–L79)
apps.legacy-web = {
package = webPackage;
selectorLabels = {
app = "legacy-web";
tier = "frontend";
};
config = {
message = "Kix now manages this workload";
environment = "production";
};
};

View source on GitHub ↗

Kix passes this value to package builders as scope.selectorLabels. Workload helpers use it for both spec.selector.matchLabels and the Pod template labels, and Service helpers use it when selecting the workload.

The package must build its selectors from scope.selectorLabels for this instance option to take effect.

Evaluate the cluster:

Run in kix-examples/
❱ kix check how-to-adoption
 TOOL         RESULT  DETAILS                                                       
 eval         pass    20 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, 14 warnings, 4 info

Render the workload and compare both label sets with the live Deployment:

Run in kix-examples/ Output excerpt
❱ kix build how-to-adoption --output json
{
  "apiVersion": "apps/v1",
  "kind": "Deployment",
  "metadata": {
    "name": "legacy-web",
    "namespace": "apps"
  },
  "spec": {
    "selector": {
      "matchLabels": {
        "app": "legacy-web",
        "tier": "frontend"
      }
    },
    "template": {
      "metadata": {
        "labels": {
          "app": "legacy-web",
          "tier": "frontend"
        }
      }
    }
  }
}

The rendered selector and Pod labels contain the existing app and tier values. Compare them against the kubectl get output from the first step.

kix diff cannot make this comparison. It finds live resources through Kix’s management labels, which the existing workload does not yet have. The diff therefore shows the workload as a new resource and never compares the selectors.

Ask the API server instead:

Run in kix-examples/
❱ kix deploy how-to-adoption --dry-run

Deployment and StatefulSet selectors are immutable. A mismatch therefore fails the dry run, either as an immutable-field error or as a field-ownership conflict when another manager owns the selector.