diff --git a/content/master/guides/disabling-unused-managed-resources.md b/content/master/guides/disabling-unused-managed-resources.md new file mode 100644 index 000000000..3beb04a28 --- /dev/null +++ b/content/master/guides/disabling-unused-managed-resources.md @@ -0,0 +1,214 @@ +--- +title: Disabling Unused Managed Resources +weight: 85 +state: alpha +alphaVersion: 2.0 +description: Reduce CRD overhead by disabling unused managed resources +--- + +{{}} +This guide uses +[managed resource definitions]({{}}) +and +[managed resource activation policies]({{}}), +which Crossplane v2.0+ enables by default. To disable this behavior, set +`--enable-custom-to-managed-resource-conversion=false` when installing +Crossplane. +{{}} + +Large Crossplane providers can install 100+ managed resource CRDs, consuming +significant cluster resources even when you only need one or two resource +types. This guide shows how to use +[ManagedResourceDefinitions]({{}}) +and +[ManagedResourceActivationPolicies]({{}}) +to install only the provider resources you actually need. + +## Before you begin + +This guide requires: + +- Crossplane v2.0+ installed in your cluster +- A provider with `safe-start` capability (this guide uses + `provider-aws-ec2:v2.0.0`) +- Basic familiarity with Kubernetes and Crossplane concepts + +{{}} +ManagedResourceDefinitions and ManagedResourceActivationPolicies are alpha +features in Crossplane v2.0+. +{{}} + +## The problem: Resource overhead + +Installing a large cloud provider in Crossplane creates hundreds of CRDs: + +```shell +# Before selective activation - provider-aws-ec2 installs ~200 CRDs +kubectl get crds | grep aws.crossplane.io | wc -l +# Output: 200 + +# Each CRD consumes ~3 MiB of API server memory +# 200 CRDs × 3 MiB = 600 MiB of memory usage +``` + +Most users only need a small subset of these resources. Selective activation +lets you install just what you need. + +## Step 1: Disable automatic activation + +By default, the Crossplane Helm chart creates an activation policy that +enables all provider resources. To use selective activation, disable this +default behavior. + + +### Option A: Helm installation + + +```shell +helm install crossplane crossplane-stable/crossplane \ + --namespace crossplane-system \ + --create-namespace \ + --set provider.defaultActivations={} +``` + + +### Option B: Existing installation + + +Delete the default activation policy: + +```shell +kubectl delete managedresourceactivationpolicy default +``` + +## Step 2: Install your provider + +Install your provider as normal. Crossplane automatically converts the +provider's CRDs to ManagedResourceDefinitions: + +```yaml +apiVersion: pkg.crossplane.io/v1 +kind: Provider +metadata: + name: provider-aws-ec2 +spec: + package: xpkg.crossplane.io/provider-aws-ec2:v2.0.0 +``` + +Save this as `provider.yaml` and apply it: + +```shell +kubectl apply -f provider.yaml + +# Wait for provider to be ready +kubectl wait --for=condition=Healthy provider/provider-aws-ec2 --timeout=5m +``` + +## Step 3: Verify Crossplane created MRDs + + +After the provider installs, check ManagedResourceDefinitions that Crossplane +created in inactive state: + + +```shell +# List ManagedResourceDefinitions +kubectl get managedresourcedefinitions + +# Check their states (should be "Inactive") +kubectl get mrds -o jsonpath='{.items[*].spec.state}' \ + | tr ' ' '\n' | sort | uniq -c +# 200 Inactive +``` + +Notice that Crossplane didn't create any CRDs yet: + +```shell +kubectl get crds | grep ec2.aws.m.crossplane.io +# No output - CRDs don't exist until MRDs are activated +``` + +## Step 4: Create an activation policy + +Create a ManagedResourceActivationPolicy to selectively activate only the +resources you need: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceActivationPolicy +metadata: + name: my-app-resources +spec: + activate: + - instances.ec2.aws.m.crossplane.io # EC2 instances for compute + - securitygroups.ec2.aws.m.crossplane.io # Security groups for networking + - vpcs.ec2.aws.m.crossplane.io # VPCs for isolation +``` + +Save this as `activation-policy.yaml` and apply it: + +```shell +kubectl apply -f activation-policy.yaml +``` + +## Step 5: Verify selective activation + + +Check that Crossplane activated only the specified resources: + + +```shell +# Check MRD states - only some should be Active now +kubectl get mrds \ + -o jsonpath='{range .items[*]}{.metadata.name}: {.spec.state}{"\n"}{end}' \ + | grep Active +# instances.ec2.aws.m.crossplane.io: Active +# securitygroups.ec2.aws.m.crossplane.io: Active +# vpcs.ec2.aws.m.crossplane.io: Active + +# Verify Crossplane created corresponding CRDs +kubectl get crds | grep ec2.aws.m.crossplane.io +# instances.ec2.aws.m.crossplane.io +# securitygroups.ec2.aws.m.crossplane.io +# vpcs.ec2.aws.m.crossplane.io + +# Count CRDs from EC2 provider - should match activated MRDs +kubectl get crds | grep ec2.aws.m.crossplane.io | wc -l +# 3 (only the activated resources) +``` + +## Step 6: Measure the impact + +Check the significant reduction in resource overhead: + +```shell +# Count CRDs from EC2 provider - should be much lower than 200 +kubectl get crds | grep aws.crossplane.io | wc -l +# 3 CRDs (99% reduction from 200) + +# Calculate memory savings +echo "197 CRDs saved × 3 MiB = 591 MiB saved (99% reduction)" + +# Verify inactive MRDs still exist but consume minimal resources +kubectl get mrds \ + -o jsonpath='{.items[?(@.spec.state=="Inactive")]..metadata.name}' | wc -w +# 197 inactive MRDs (~20 MiB total overhead vs 600 MiB for active CRDs) + +# Check total MRDs (active + inactive) +kubectl get mrds | wc -l +# 200 total MRDs (3 active, 197 inactive) +``` + +The selective activation provides massive resource savings while maintaining +full capability for the resources you actually use. + +## Next steps + +- Learn more about + [ManagedResourceDefinitions]({{}}) + for detailed concepts and troubleshooting +- Explore + [ManagedResourceActivationPolicies]({{}}) + for advanced activation strategies and best practices +- Check the [API reference]({{}}) for complete schema + documentation diff --git a/content/master/guides/implementing-safe-start.md b/content/master/guides/implementing-safe-start.md new file mode 100644 index 000000000..b8c36a21b --- /dev/null +++ b/content/master/guides/implementing-safe-start.md @@ -0,0 +1,247 @@ +--- +title: Implementing safe-start in Providers +weight: 90 +state: alpha +alphaVersion: 2.0 +description: Guide for provider developers to add safe-start capability for + selective resource activation +--- + +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. + +{{}} +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: + +- Provider built with crossplane-runtime v2.0+ +- Understanding of + [ManagedResourceDefinitions]({{}}) +- Test environment with Crossplane v2.0+ + +## Implementation steps + +### Step 1: Declare safe-start capability + +Add safe-start to your provider package metadata: + +```yaml +# package/crossplane.yaml +apiVersion: meta.pkg.crossplane.io/v1 +kind: Provider +metadata: + name: provider-example +spec: + capabilities: + - safe-start +``` + +### Step 2: Add required imports + +Update your main.go imports (see +[crossplane-runtime godoc](https://pkg.go.dev/github.com/crossplane/crossplane-runtime/v2) +for full API reference): + +```go +import ( + // existing imports... + + "k8s.io/apimachinery/pkg/runtime/schema" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + + "github.com/crossplane/crossplane-runtime/v2/pkg/controller" + "github.com/crossplane/crossplane-runtime/v2/pkg/gate" + "github.com/crossplane/crossplane-runtime/v2/pkg/reconciler/customresourcesgate" +) +``` + +### Step 3: Initialize the gate + +Add gate initialization in your main function: + +```go +func main() { + // existing setup code... + + o := controller.Options{ + // existing options... + Gate: new(gate.Gate[schema.GroupVersionKind]), + } + + // Add CustomResourceDefinition to scheme for gate controller + if err := apiextensionsv1.AddToScheme(mgr.GetScheme()); err != nil { + panic(err) + } + + // Setup controllers + if err := yourprovider.Setup(mgr, o); err != nil { + panic(err) + } + + // Setup the CRD gate controller + if err := customresourcesgate.Setup(mgr, o); err != nil { + panic(err) + } + + // start manager... +} +``` + +### Step 4: Use gated controller setup + +Create a gated setup function for each managed resource controller: + +```go +// SetupGated registers controller setup with the gate, waiting for the +// required CRD +func SetupGated(mgr ctrl.Manager, o controller.Options) error { + o.Gate.Register(func() { + if err := Setup(mgr, o); err != nil { + panic(err) + } + }, v1alpha1.MyResourceGroupVersionKind) + return nil +} + +// Setup is your existing controller setup function (unchanged) +func Setup(mgr ctrl.Manager, o controller.Options) error { + // existing controller setup code... +} +``` + +### Step 5: Update controller registration + +Change your controller setup to use the gated versions: + +```go +// internal/controller/controller.go +func Setup(mgr ctrl.Manager, o controller.Options) error { + for _, setup := range []func(ctrl.Manager, controller.Options) error{ + myresource.SetupGated, // Changed from myresource.Setup + // other gated setups... + } { + if err := setup(mgr, o); err != nil { + return err + } + } + return nil +} +``` + +## 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: + +```shell +# Install Crossplane v2.0+ +helm install crossplane crossplane-stable/crossplane \ + --namespace crossplane-system \ + --set provider.defaultActivations={} + +# Install your provider +kubectl apply -f provider.yaml + +# Check that MRDs are created but inactive +kubectl get mrds +# All should show STATE: Inactive + +# No CRDs should exist yet +kubectl get crds | grep yourprovider.m.crossplane.io +# Should return no results + +# Create activation policy +kubectl apply -f - < +**Solution**: check that Crossplane activated MRDs and created CRDs: + +```shell +kubectl get mrds -o wide +kubectl describe mrap +``` + + +### CRDs don't appear + + +**Cause**: MRDs might not activate or activation policy doesn't match. + + +**Solution**: verify activation policy patterns match MRD names: +```shell +kubectl get mrds +kubectl 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]({{}}). diff --git a/content/master/managed-resources/_index.md b/content/master/managed-resources/_index.md index 335700301..b96343c7a 100644 --- a/content/master/managed-resources/_index.md +++ b/content/master/managed-resources/_index.md @@ -1,5 +1,5 @@ --- title: Managed Resources weight: 52 -description: Understand Crossplane's core components +description: Understand Crossplane's managed resources and selective activation --- diff --git a/content/master/managed-resources/managed-resource-activation-policies.md b/content/master/managed-resources/managed-resource-activation-policies.md new file mode 100644 index 000000000..0d15583b2 --- /dev/null +++ b/content/master/managed-resources/managed-resource-activation-policies.md @@ -0,0 +1,472 @@ +--- +title: Managed Resource Activation Policies +weight: 20 +state: alpha +alphaVersion: 2.0 +description: ManagedResourceActivationPolicies control which + ManagedResourceDefinitions activate for selective provider resource + installation +--- + +{{}} +Managed resource activation policies work with +[managed resource definitions]({{}}), +which Crossplane v2.0+ enables by default. To disable this behavior, set +`--enable-custom-to-managed-resource-conversion=false` when installing +Crossplane. +{{}} + +A `ManagedResourceActivationPolicy` (MRAP) controls which +[ManagedResourceDefinitions]({{}}) +become active in your cluster. MRAPs enable selective installation of provider +resources, allowing you to activate only the 10 managed resources you need +instead of the 100+ that a provider ships. + +## The selective activation problem + +Modern Crossplane providers can ship dozens or hundreds of managed resources, +but most users only need a small subset. Before MRAPs, you got "all or +nothing" - installing a provider meant getting every managed resource it +supported, consuming unnecessary cluster resources. + +MRAPs solve this by providing pattern-based activation of +ManagedResourceDefinitions, letting you choose which provider resources to +enable. + + + +## How MRAPs work + + + +MRAPs contain activation patterns that match ManagedResourceDefinition names. +When you create or update an MRAP, Crossplane: + +1. **Lists all MRDs** in the cluster +2. **Matches MRD names** against the activation patterns +3. **Activates matching MRDs** by setting their `state` to `Active` +4. **Updates the MRAP status** with the list of activated resources + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceActivationPolicy +metadata: + name: aws-core-resources +spec: + activate: + - buckets.s3.aws.m.crossplane.io # Modern v2 style S3 buckets + - instances.rds.aws.m.crossplane.io # Modern v2 style RDS instances + - "*.ec2.aws.m.crossplane.io" # All modern v2 style EC2 resources +``` + +When you apply this MRAP, Crossplane activates the specified S3 Bucket, RDS +Instance, and all EC2 resources, leaving other AWS resources inactive. + +## Key features + +- **Pattern-based matching**: Use wildcards to activate groups of resources +- **Multiple policy support**: Different MRAPs can activate different resource + sets +- **Status tracking**: See which resources each policy activated +- **Automatic activation**: New MRDs matching existing patterns activate + automatically + +## Pattern matching + +### Exact matching + +Specify complete MRD names for precise control: + +```yaml +spec: + activate: + - buckets.s3.aws.m.crossplane.io + - databases.rds.aws.m.crossplane.io + - clusters.eks.aws.m.crossplane.io +``` + +### Wildcard patterns + +Use `*` wildcards to match multiple resources: + +```yaml +spec: + activate: + - "*.s3.aws.m.crossplane.io" # All S3 resources + - "*.ec2.aws.m.crossplane.io" # All EC2 resources + - "*.rds.aws.m.crossplane.io" # All RDS databases +``` + +{{}} +MRAPs use prefix-only wildcards, not full regular expressions. Only `*` at +the beginning of a pattern works (for example, `*.s3.aws.m.crossplane.io`). +Patterns like `s3.*.aws.m.crossplane.io` or `*.s3.*` aren't valid. +{{}} + +{{}} +You can mix exact names and wildcards for flexible activation: +```yaml +spec: + activate: + - buckets.s3.aws.m.crossplane.io # Exact S3 buckets + - "*.ec2.aws.m.crossplane.io" # All EC2 resources + - clusters.eks.aws.m.crossplane.io # Exact EKS clusters +``` +{{}} + +## Legacy and modern resource versions + +Crossplane v2 supports two styles of managed resources: + +- **Modern v2 style** (recommended): Use `*.m.crossplane.io` domains for + namespaced managed resources with better isolation and security +- **Legacy v1 style**: Use `*.crossplane.io` domains for cluster-scoped + managed resources (maintained for backward compatibility) + +### Activating modern resources + +Most examples in this guide use modern v2 style resources: + +```yaml +spec: + activate: + - buckets.s3.aws.m.crossplane.io # Modern v2 S3 bucket + - "*.ec2.aws.m.crossplane.io" # All modern v2 EC2 resources +``` + +### Activating legacy resources + +To activate legacy v1 style resources, use patterns without `.m`: + +```yaml +spec: + activate: + - buckets.s3.aws.crossplane.io # Legacy v1 S3 bucket + - "*.ec2.aws.crossplane.io" # All legacy v1 EC2 resources +``` + +### Mixed activation + +You can activate both modern and legacy resources in the same MRAP: + +```yaml +spec: + activate: + - "*.aws.m.crossplane.io" # All modern AWS resources + - "*.aws.crossplane.io" # All legacy AWS resources +``` + +## Common activation strategies + +### Activate everything (default behavior) + +The Crossplane Helm chart creates a default MRAP that activates all resources: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceActivationPolicy +metadata: + name: default +spec: + activate: + - "*" # Activate all MRDs +``` + +You can customize this during installation: + +```shell +# Disable default activations entirely +helm install crossplane crossplane-stable/crossplane \ + --set provider.defaultActivations={} + +# Or provide custom default activations +helm install crossplane crossplane-stable/crossplane \ + --set provider.defaultActivations={\ + "*.s3.aws.m.crossplane.io","*.ec2.aws.m.crossplane.io"} +``` + +### Provider-specific activation + +Activate all resources from specific providers: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceActivationPolicy +metadata: + name: aws-provider-resources +spec: + activate: + - "*.aws.crossplane.io" # All AWS resources + - "*.aws.m.crossplane.io" # All AWS managed resources (v2 style) +``` + +### Service-specific activation + +Activate resources for specific cloud services: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceActivationPolicy +metadata: + name: storage-and-compute +spec: + activate: + - "*.s3.aws.m.crossplane.io" # AWS S3 resources + - "*.ec2.aws.m.crossplane.io" # AWS EC2 resources + - "*.storage.gcp.m.crossplane.io" # GCP Storage resources + - "*.compute.gcp.m.crossplane.io" # GCP Compute resources +``` + +### Minimal activation + +Activate only the resources you know you need: + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceActivationPolicy +metadata: + name: minimal-footprint +spec: + activate: + - buckets.s3.aws.m.crossplane.io # Just S3 buckets + - instances.ec2.aws.m.crossplane.io # Just EC2 instances + - databases.rds.aws.m.crossplane.io # Just RDS databases +``` + + + +## Multiple MRAPs + + + +You can have multiple MRAPs in your cluster. Crossplane processes all MRAPs +together and activates any MRD that matches at least one pattern. + +### Team-based activation + +Different teams can manage their own activation policies: + +```yaml +# Storage team MRAP +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceActivationPolicy +metadata: + name: storage-team +spec: + activate: + - "*.s3.aws.m.crossplane.io" + - "*.storage.gcp.m.crossplane.io" +--- +# Database team MRAP +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceActivationPolicy +metadata: + name: database-team +spec: + activate: + - "*.rds.aws.m.crossplane.io" + - "*.sql.gcp.m.crossplane.io" +``` + +### Configuration package activation + +Configuration packages can include MRAPs to declare their resource dependencies: + +```yaml +# In your Configuration package +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceActivationPolicy +metadata: + name: web-platform-dependencies +spec: + activate: + - buckets.s3.aws.m.crossplane.io # For static assets + - instances.ec2.aws.m.crossplane.io # For web servers + - databases.rds.aws.m.crossplane.io # For application data + - certificates.acm.aws.m.crossplane.io # For HTTPS +``` + + + +## Working with MRAPs + + + + + +### Creating MRAPs + + + +Apply an MRAP like any Kubernetes resource: + +```shell +kubectl apply -f my-activation-policy.yaml +``` + + + +### Viewing MRAPs + + + +List all MRAPs: + +```shell +kubectl get managedresourceactivationpolicies +``` + +View MRAP details and status: + +```shell +kubectl describe mrap aws-core-resources +``` + +### Checking activation status + +MRAPs track which resources they've activated: + +```yaml +status: + conditions: + - type: Healthy + status: "True" + reason: Running + activated: + - buckets.s3.aws.m.crossplane.io + - instances.ec2.aws.m.crossplane.io + - instances.rds.aws.m.crossplane.io + - securitygroups.ec2.aws.m.crossplane.io + - subnets.ec2.aws.m.crossplane.io + - vpcs.ec2.aws.m.crossplane.io +``` + + + +## MRAP status conditions + + + +### Healthy condition + +- **`Healthy: True, Reason: Running`**: MRAP works +- **`Healthy: Unknown, Reason: EncounteredErrors`**: Some MRDs failed to + activate + + + +## Troubleshooting MRAPs + + + + + +### MRAP exists but resources aren't activated + + + + +**Symptoms**: MRAP shows `activated: []` or missing expected resources + + +**Causes and solutions:** + +1. **Pattern doesn't match MRD names** + ```shell + # List available MRDs + kubectl get mrds + + # Check your pattern matches + kubectl get mrds -o name | grep "your-pattern" + ``` + +2. **MRDs don't exist yet** + - Install the required provider first + - Providers create MRDs when they start + +3. **Provider doesn't support activation** + ```shell + # Check provider capabilities + kubectl get providerrevision \ + -o jsonpath='{.status.capabilities}' + # Look for "safe-start" + ``` + + + +### MRAP shows activation errors + + + + +**Symptoms**: MRAP has `Healthy: Unknown` status with errors + + +**Status condition example:** + +```yaml +conditions: +- type: Healthy + status: "Unknown" + reason: EncounteredErrors + message: "failed to activate 2 of 5 ManagedResourceDefinitions" +``` + +**Solution**: select MRAP events for specific failure details: + +```shell +kubectl describe mrap +# Look at the Events section for activation errors +``` + +### Resources activate when you don't expect them to + +**Symptoms**: more resources are active than expected + +**Cause**: multiple MRAPs with overlapping patterns (this is normal behavior) + +**Solution**: review all MRAP patterns to understand which policies are +activating which resources + +```shell +# List all MRAP activation patterns +kubectl get mrap \ + -o jsonpath='{range .items[*]}{.metadata.name}: {.spec.activate}{"\n"}{end}' + +# Check which MRAPs activated each resource +kubectl get mrap \ + -o jsonpath='{range .items[*]}{.metadata.name}: {.status.activated}{"\n"}{end}' +``` + +## Best practices + +MRAPs are additive - multiple MRAPs can activate the same resource without +conflicts. This enables team-based activation strategies and Configuration +package dependencies. + + +1. **Start specific, broaden as needed** - Begin with exact resource names, + add wildcards only when beneficial for maintainability +2. **Plan for provider evolution** - Design wildcard patterns that + accommodate new resources as providers add them (for example, + `*.s3.aws.m.crossplane.io` works for future S3 resources) +3. **Group related resources logically** - Create MRAPs that activate + resources teams actually use together +4. **Include activation dependencies in Configuration packages** - + Configuration packages should declare what MRDs they need rather than + assuming resources are available +5. **Use conservative patterns in shared environments** - Avoid overly broad + wildcards that activate unnecessary resources when multiple teams share + providers + + +## Next steps + +- Learn about + [ManagedResourceDefinitions]({{}}) + to understand what MRAPs activate +- See the + [disabling unused managed resources guide]({{}}) + for step-by-step implementation +- Check the [API reference]({{}}) for complete MRAP schema + documentation diff --git a/content/master/managed-resources/managed-resource-definitions.md b/content/master/managed-resources/managed-resource-definitions.md new file mode 100644 index 000000000..248a9b521 --- /dev/null +++ b/content/master/managed-resources/managed-resource-definitions.md @@ -0,0 +1,377 @@ +--- +title: Managed Resource Definitions +weight: 15 +state: alpha +alphaVersion: 2.0 +description: ManagedResourceDefinitions enable selective activation of provider + resources and reduce CRD overhead +--- + +{{}} +Crossplane v2.0+ enables managed resource definitions by default. This +automatically converts provider CRDs to MRDs during installation. To disable +this +behavior, set `--enable-custom-to-managed-resource-conversion=false` when +installing Crossplane. +{{}} + +A `ManagedResourceDefinition` (MRD) is a lightweight abstraction over +Kubernetes CustomResourceDefinitions (CRDs) that enables selective activation of +managed resources. MRDs solve the problem of providers installing hundreds of +CRDs when you only need one or two, reducing API server overhead and improving +cluster performance. + + + +## The CRD scaling problem + + + +Large Crossplane providers can install 100+ managed resource CRDs. Each CRD +consumes about 3 MiB of API server memory and creates API endpoints that affect +cluster performance: + +- **Memory pressure**: Large providers can consume 300+ MiB of API server + memory +- **Slower kubectl operations**: Commands like `kubectl get managed` must query + all custom resource endpoints +- **Increased API server load**: More CRDs mean more API endpoints to serve +- **Unnecessary resource overhead**: Most users only need a subset of provider + resources + +MRDs address this by allowing providers to ship resource definitions that only +become active CRDs when explicitly needed. + + + +## How MRDs work + + + +An MRD contains the same schema as a CRD but adds two key fields: + +- **`connectionDetails`**: Documents what connection secrets the resource + provides +- **`state`**: Controls whether the underlying CRD exists (`Active` or + `Inactive`) + +When an MRD's state is `Inactive`, no CRD exists in the cluster. When +activated, Crossplane creates the corresponding CRD and the provider can start +managing instances of that resource. + +```yaml +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceDefinition +metadata: + name: buckets.s3.aws.m.crossplane.io +spec: + group: s3.aws.m.crossplane.io + names: + kind: Bucket + plural: buckets + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + forProvider: + type: object + properties: + region: + type: string + versioning: + type: boolean + connectionDetails: + - name: bucket-name + description: The name of the created S3 bucket + - name: region + description: The AWS region where the bucket was created + state: Inactive # Default state - no CRD created yet +``` + +## Key characteristics + +- **Selective activation**: Only create CRDs for resources you actually need +- **Performance benefits**: Inactive MRDs consume minimal cluster resources +- **Connection details documentation**: Schema for documenting available + connection secrets +- **One-way state transition**: MRDs can go from `Inactive` to `Active` but not + back + + + +## MRD states + + + +### Inactive state + +When `state: Inactive` (the default): + +- No CRD exists in the cluster +- No API endpoints exist +- The provider doesn't start a controller for this resource +- Minimal memory and CPU overhead + +```yaml +spec: + state: Inactive # Default for all MRDs +``` + +### Active state + +When `state: Active`: + +- Crossplane creates the corresponding CRD +- API endpoints become available for the resource +- The provider starts a controller to manage instances +- Full capability like traditional managed resources + +```yaml +spec: + state: Active # CRD will be created +``` + +{{}} +MRD state transitions are one-way only. Once an MRD becomes `Active`, it can't +return to `Inactive`. This prevents accidental deletion of CRDs that may have +existing resources. +{{}} + +## Connection details documentation + +MRDs can document what connection details a managed resource provides. This +helps users understand what data is available in connection secrets without +having to create test resources. + +```yaml +spec: + connectionDetails: + - name: endpoint + description: The RDS instance endpoint for database connections + - name: port + description: The port number for database connections + - name: username + description: The master username for database access + - name: password + description: The auto-generated master password +``` + +{{}} + + + +Connection details are currently a schema-only feature. Most providers +don't yet populate the `connectionDetails` field in their MRDs, but the structure +is available for future implementation. + + + +{{}} + + + +## Working with MRDs + + + + + +### Viewing MRDs + + + +List all MRDs in your cluster: + +```shell +kubectl get managedresourcedefinitions +``` + +View MRD details: + +```shell +kubectl describe mrd buckets.s3.aws.m.crossplane.io +``` + + + +### Checking MRD status + + + +MRDs provide status information about their lifecycle: + +```yaml +status: + conditions: + - type: Established + status: "False" + reason: InactiveManagedResource + message: "ManagedResourceDefinition is inactive" +``` + +**Status conditions:** + +- **`Established: False, Reason: InactiveManagedResource`**: MRD is inactive, + no CRD created +- **`Established: Unknown, Reason: PendingManagedResource`**: Crossplane is + creating the CRD +- **`Established: True, Reason: EstablishedManagedResource`**: CRD exists and + is ready +- **`Healthy: True, Reason: Running`**: MRD controller operating +- **`Healthy: Unknown, Reason: EncounteredErrors`**: MRD controller + experiencing issues + + + +### Manually activating MRDs + + + +You can manually activate an MRD by changing its state: + +```shell +kubectl patch mrd buckets.s3.aws.m.crossplane.io --type='merge' \ + -p='{"spec":{"state":"Active"}}' +``` + +The recommended approach is to use +[ManagedResourceActivationPolicies]({{}}) +for systematic activation. + +## How providers work with MRDs + +Crossplane v2.0+ automatically converts all provider CRDs to MRDs during +package installation, regardless of the provider's age or original format. The +provider's `safe-start` capability determines the default MRD state: + +### Providers with `safe-start` capability +- MRDs start with `state: Inactive` by default +- Support selective activation via + [ManagedResourceActivationPolicies]({{}}) +- Reduced resource overhead for unused resources +- Provider can start without all CRDs being active + +```yaml +# Provider package metadata +apiVersion: meta.pkg.crossplane.io/v1 +kind: Provider +spec: + capabilities: + - safe-start +``` + +{{}} +Crossplane uses fuzzy matching for capabilities, so `safe-start`, +`safe_start`, `safestart`, and `SafeStart` all match the `safe-start` +capability. +{{}} + +### Providers without `safe-start` capability +- MRDs start with `state: Active` by default (legacy behavior) +- All CRDs become available for backward compatibility +- Full resource overhead like traditional providers + + + + +## Troubleshooting MRDs + + + + + +### MRD exists but no CRD appears + + + + +**Symptoms**: MRD is present but `kubectl get ` shows "no +resources found" + +**Cause**: MRD is in `Inactive` state + +**Solution**: Activate the MRD using an +[ManagedResourceActivationPolicy]({{}}) +or manually patch the state + + +```shell +# Check MRD state +kubectl get mrd -o jsonpath='{.spec.state}' + +# Activate if needed +kubectl patch mrd --type='merge' -p='{"spec":{"state":"Active"}}' +``` + + + +### MRD activation fails + + + + +**Symptoms**: MRD state is `Active` but `Established` condition remains `False` + +**Cause**: CRD creation failed due to schema issues or conflicts + +**Solution**: Check MRD events and status for error details + + +```shell +kubectl describe mrd +``` + +**Other status conditions for troubleshooting:** +- **`Established: False, Reason: BlockedManagedResourceActivationPolicy`**: + Blocked by activation policy issues +- **`Established: False, Reason: TerminatingManagedResource`**: Crossplane is + deleting the MRD + +**Common events you might see:** +- `Normal CreateCustomResourceDefinition` - CRD successfully created +- `Normal UpdateCustomResourceDefinition` - CRD successfully updated +- `Warning CreateCustomResourceDefinition` - CRD creation failed +- `Warning UpdateCustomResourceDefinition` - CRD update failed +- `Warning Reconcile` - General reconciliation errors + +Common issues: +- Malformed OpenAPI schema in the MRD +- CRD name conflicts with existing resources +- Insufficient RBAC permissions for Crossplane + +### Provider doesn't support activation + + +**Symptoms**: Provider starts all controllers regardless of MRD states + +**Cause**: Provider doesn't implement late activation support + +**Solution**: Check provider capabilities and use a compatible provider version + + +```shell +# Check if provider supports late activation +kubectl get providerrevision \ + -o jsonpath='{.status.capabilities}' +``` + +Look for the `safe-start` capability. + +## Next steps + +- Learn about + [ManagedResourceActivationPolicies]({{}}) + for systematic resource activation +- See the + [disabling unused managed resources guide]({{}}) + for practical implementation +- Check the [API reference]({{}}) for complete MRD schema + documentation \ No newline at end of file diff --git a/content/master/managed-resources/managed-resources.md b/content/master/managed-resources/managed-resources.md index 6b57ce9b2..a6d8d5200 100644 --- a/content/master/managed-resources/managed-resources.md +++ b/content/master/managed-resources/managed-resources.md @@ -454,6 +454,8 @@ password: 27 bytes {{}} The Provider determines the data written to the Secret object. Refer to the specific Provider documentation for the generated Secret data. + +[ManagedResourceDefinitions]({{}}) can document what connection details a managed resource provides, though most providers don't yet populate this information. {{< /hint >}} ## Annotations diff --git a/content/master/operations/cronoperation.md b/content/master/operations/cronoperation.md index fbfe08b5f..45327cf28 100644 --- a/content/master/operations/cronoperation.md +++ b/content/master/operations/cronoperation.md @@ -1,5 +1,5 @@ --- -title: CronOperation +title: Cron Operations weight: 120 state: alpha alphaVersion: 2.0 diff --git a/content/master/operations/operation.md b/content/master/operations/operation.md index 051a180ab..bdd69c02d 100644 --- a/content/master/operations/operation.md +++ b/content/master/operations/operation.md @@ -1,5 +1,5 @@ --- -title: Operation +title: Operations weight: 110 state: alpha alphaVersion: 2.0 diff --git a/content/master/operations/watchoperation.md b/content/master/operations/watchoperation.md index 71db90640..539530c15 100644 --- a/content/master/operations/watchoperation.md +++ b/content/master/operations/watchoperation.md @@ -1,5 +1,5 @@ --- -title: WatchOperation +title: Watch Operations weight: 130 state: alpha alphaVersion: 2.0 diff --git a/content/master/whats-new/_index.md b/content/master/whats-new/_index.md index fb29fdb7f..1267d601c 100644 --- a/content/master/whats-new/_index.md +++ b/content/master/whats-new/_index.md @@ -171,6 +171,11 @@ deprecate and remove cluster scoped MRs at a future date. Read more about Crossplane v2's [backward compatibility](#backward-compatibility). {{}} +Crossplane v2 also introduces +[managed resource definitions]({{}}) +for selective activation of provider resources, reducing cluster overhead by +installing only the managed resources you actually need. + ## Compose any resource Crossplane v2 isn't opinionated about using composition together with managed diff --git a/utils/vale/styles/Crossplane/allowed-jargon.txt b/utils/vale/styles/Crossplane/allowed-jargon.txt index b1ee0f02c..12ed111a9 100644 --- a/utils/vale/styles/Crossplane/allowed-jargon.txt +++ b/utils/vale/styles/Crossplane/allowed-jargon.txt @@ -27,6 +27,7 @@ CronJobs crt CSS CUE +CustomResourceDefinitions CVEs DatabaseInstance DevOps @@ -41,6 +42,7 @@ ESS float64 GitOps Go +godoc gRPC hostname IAM @@ -56,7 +58,9 @@ kube-controller-manager kubectl kv KV +main.go metrics-server +MiB minikube multi-platform namespace diff --git a/utils/vale/styles/Crossplane/crossplane-words.txt b/utils/vale/styles/Crossplane/crossplane-words.txt index 50a59d285..17e5a3909 100644 --- a/utils/vale/styles/Crossplane/crossplane-words.txt +++ b/utils/vale/styles/Crossplane/crossplane-words.txt @@ -28,6 +28,7 @@ Crossplane crossplane-admin crossplane-browse crossplane-edit +crossplane-runtime Crossplane's crossplane-view crossplane.yaml @@ -60,8 +61,17 @@ InactivePackageRevision initProvider KCL LateInitialize +ManagedResourceActivationPolicies +ManagedResourceActivationPolicy +ManagedResourceDefinition +ManagedResourceDefinitions managementPolicies MR +MRAP +MRAPs +MRD +MRD's +MRDs MRs Operation-specific PatchSet diff --git a/utils/vale/styles/Crossplane/spelling-exceptions.txt b/utils/vale/styles/Crossplane/spelling-exceptions.txt index a86c03206..ae35534f6 100644 --- a/utils/vale/styles/Crossplane/spelling-exceptions.txt +++ b/utils/vale/styles/Crossplane/spelling-exceptions.txt @@ -45,16 +45,22 @@ non-Kubernetes non-production one-time One-time +one-way +One-way Operation-level +pattern-based +Pattern-based per-element performant per-object per-resource poll-interval pre-existing +prefix-only preload pre-provisioned pre-release +Provider-specific race-conditions read-only ready-made @@ -62,8 +68,11 @@ resource-intensive resource-specific right-hand run-time +safe-start +schema-only self-service self-signed +Service-specific space-delimited status-checking step-by-step @@ -71,6 +80,8 @@ subresources System-level /tab /tabs +team-based +Team-based third-party Time-sensitive top-level