Implementing safe-start in Providers

This is an alpha feature. Crossplane may change or drop this feature at any time.

This feature was introduced in v2.

For more information read the Crossplane feature lifecycle.

This guide shows provider developers how to implement safe-start capability in their Crossplane providers. safe-start enables disabling unused managed resources through ManagedResourceDefinitions, improving performance and reducing resource overhead.

Important
safe-start requires Crossplane v2.0+ and crossplane-runtime v2.0+. Implementing safe-start involves code changes that affect provider startup behavior.

What safe-start provides

safe-start changes how your provider handles CRD installation:

Without safe-start:

  • Providers create all managed resource CRDs when installed
  • Users get all resources even if they only need one or two
  • Higher memory usage and API server load

With safe-start:

  • Providers create ManagedResourceDefinitions but CRDs only when activated
  • Users activate only needed resources through ManagedResourceActivationPolicies
  • Significant reduction in cluster resource overhead

Prerequisites

Before implementing safe-start:

Implementation steps

Step 1: Declare safe-start capability

Add safe-start to your provider package metadata:

1# package/crossplane.yaml
2apiVersion: meta.pkg.crossplane.io/v1
3kind: Provider
4metadata:
5  name: provider-example
6spec:
7  capabilities:
8  - safe-start

Step 2: Add required imports

Update your main.go imports (see crossplane-runtime godoc for full API reference):

 1import (
 2    // existing imports...
 3    
 4    "k8s.io/apimachinery/pkg/runtime/schema"
 5    apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 6    
 7    "github.com/crossplane/crossplane-runtime/v2/pkg/controller"
 8    "github.com/crossplane/crossplane-runtime/v2/pkg/gate"
 9    "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/customresourcesgate"
10)

Step 3: Initialize the gate

Add gate initialization in your main function:

 1func main() {
 2    // existing setup code...
 3    
 4    o := controller.Options{
 5        // existing options...
 6        Gate: new(gate.Gate[schema.GroupVersionKind]),
 7    }
 8    
 9    // Add CustomResourceDefinition to scheme for gate controller
10    if err := apiextensionsv1.AddToScheme(mgr.GetScheme()); err != nil {
11        panic(err)
12    }
13    
14    // Setup controllers
15    if err := yourprovider.Setup(mgr, o); err != nil {
16        panic(err)
17    }
18        
19    // Setup the CRD gate controller  
20    if err := customresourcesgate.Setup(mgr, o); err != nil {
21        panic(err)
22    }
23        
24    // start manager...
25}

Step 4: Use gated controller setup

Create a gated setup function for each managed resource controller:

 1// SetupGated registers controller setup with the gate, waiting for the
 2// required CRD
 3func SetupGated(mgr ctrl.Manager, o controller.Options) error {
 4    o.Gate.Register(func() {
 5        if err := Setup(mgr, o); err != nil {
 6            panic(err)
 7        }
 8    }, v1alpha1.MyResourceGroupVersionKind)
 9    return nil
10}
11
12// Setup is your existing controller setup function (unchanged)
13func Setup(mgr ctrl.Manager, o controller.Options) error {
14    // existing controller setup code...
15}

Step 5: Update controller registration

Change your controller setup to use the gated versions:

 1// internal/controller/controller.go
 2func Setup(mgr ctrl.Manager, o controller.Options) error {
 3    for _, setup := range []func(ctrl.Manager, controller.Options) error{
 4        myresource.SetupGated,  // Changed from myresource.Setup
 5        // other gated setups...
 6    } {
 7        if err := setup(mgr, o); err != nil {
 8            return err
 9        }
10    }
11    return nil
12}

Implementation details

The safe-start implementation uses a “gate” pattern:

  1. Gate initialization: Creates a gate that tracks CRD readiness
  2. Controller registration: Controllers register with the gate, specifying which CRDs they need
  3. CRD monitoring: The customresourcesgate controller watches for CRD creation/deletion
  4. Delayed startup: Controllers only start when their required CRDs become active

Testing your implementation

Test safe-start behavior with this basic workflow:

 1# Install Crossplane v2.0+
 2helm install crossplane crossplane-stable/crossplane \
 3  --namespace crossplane-system \
 4  --set provider.defaultActivations={}
 5
 6# Install your provider  
 7kubectl apply -f provider.yaml
 8
 9# Check that MRDs are created but inactive
10kubectl get mrds
11# All should show STATE: Inactive
12
13# No CRDs should exist yet
14kubectl get crds | grep yourprovider.m.crossplane.io
15# Should return no results
16
17# Create activation policy
18kubectl apply -f - <<EOF
19apiVersion: apiextensions.crossplane.io/v1alpha1
20kind: ManagedResourceActivationPolicy
21metadata:
22  name: test-activation
23spec:
24  activate:
25  - "myresource.yourprovider.m.crossplane.io"
26EOF
27
28# Verify activation worked
29kubectl get mrd myresource.yourprovider.m.crossplane.io
30# Should show STATE: Active
31
32# CRD should now exist
33kubectl get crd myresource.yourprovider.m.crossplane.io

Troubleshooting

Controllers never start

Cause: gate waits for CRDs that never become active.

Solution: check that Crossplane activated MRDs and created CRDs:

1kubectl get mrds -o wide
2kubectl describe mrap <activation-policy-name>

CRDs don’t appear

Cause: MRDs might not activate or activation policy doesn’t match.

Solution: verify activation policy patterns match MRD names:

1kubectl get mrds
2kubectl get mrap -o yaml

Migration considerations

When adding safe-start to existing providers:

  • Existing installations: Continue working as expected (no CRD changes)
  • New installations: Start with inactive MRDs, require activation policies

Next steps

  • Test your safe-start implementation with different activation patterns
  • Update provider documentation to explain activation requirements
  • Consider the user experience for providers that now require activation policies

Learn more about the user experience in disabling unused managed resources.