From 8dfa231a1d6facf6f8625cb84fef8678aa5fd5ea Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Fri, 8 Aug 2025 16:29:16 -0700 Subject: [PATCH] Add documentation for MRDs, MRAPs, and safe-start Large Crossplane providers install hundreds of CRDs consuming significant API server resources, even when users only need a few resource types. The new alpha ManagedResourceDefinition (MRD) and ManagedResourceActivationPolicy (MRAP) features in Crossplane v2.0+ solve this by enabling selective activation of provider resources, but lack user-facing documentation. This change adds complete documentation covering both concepts and practical implementation. The MRD concepts page explains the CRD scaling problem and selective activation approach. The MRAP concepts page details pattern-based activation strategies and multiple policy coordination. Two how-to guides provide end-to-end workflows: one for users wanting to reduce CRD overhead through selective activation, and another for provider developers implementing safe-start capability. The user guide was tested with simulated MRDs to verify the activation workflow and troubleshooting steps. Signed-off-by: Nic Cope --- .../disabling-unused-managed-resources.md | 214 +++++++++ .../master/guides/implementing-safe-start.md | 247 ++++++++++ content/master/managed-resources/_index.md | 2 +- .../managed-resource-activation-policies.md | 430 ++++++++++++++++++ .../managed-resource-definitions.md | 377 +++++++++++++++ .../managed-resources/managed-resources.md | 2 + content/master/whats-new/_index.md | 5 + .../vale/styles/Crossplane/allowed-jargon.txt | 4 + .../styles/Crossplane/crossplane-words.txt | 10 + .../styles/Crossplane/spelling-exceptions.txt | 11 + 10 files changed, 1301 insertions(+), 1 deletion(-) create mode 100644 content/master/guides/disabling-unused-managed-resources.md create mode 100644 content/master/guides/implementing-safe-start.md create mode 100644 content/master/managed-resources/managed-resource-activation-policies.md create mode 100644 content/master/managed-resources/managed-resource-definitions.md 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 00000000..6693ee6f --- /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.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.crossplane.io # EC2 instances for compute + - securitygroups.ec2.aws.crossplane.io # Security groups for networking + - vpcs.ec2.aws.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.crossplane.io: Active +# securitygroups.ec2.aws.crossplane.io: Active +# vpcs.ec2.aws.crossplane.io: Active + +# Verify Crossplane created corresponding CRDs +kubectl get crds | grep ec2.aws.crossplane.io +# instances.ec2.aws.crossplane.io +# securitygroups.ec2.aws.crossplane.io +# vpcs.ec2.aws.crossplane.io + +# Count CRDs from EC2 provider - should match activated MRDs +kubectl get crds | grep ec2.aws.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 00000000..d3f52c73 --- /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.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 33570030..b96343c7 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 00000000..0069b1bd --- /dev/null +++ b/content/master/managed-resources/managed-resource-activation-policies.md @@ -0,0 +1,430 @@ +--- +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.crossplane.io + - instances.rds.aws.crossplane.io + - *.ec2.aws.crossplane.io # All 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.crossplane.io + - databases.rds.aws.crossplane.io + - clusters.eks.aws.crossplane.io +``` + +### Wildcard patterns + +Use `*` wildcards to match multiple resources: + +```yaml +spec: + activate: + - "*.s3.aws.crossplane.io" # All S3 resources + - "*.ec2.aws.crossplane.io" # All EC2 resources + - "*.rds.aws.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.crossplane.io`). +Patterns like `s3.*.aws.crossplane.io` or `*.s3.*` aren't valid. +{{}} + +{{}} +You can mix exact names and wildcards for flexible activation: +```yaml +spec: + activate: + - buckets.s3.aws.crossplane.io # Exact S3 buckets + - "*.ec2.aws.crossplane.io" # All EC2 resources + - clusters.eks.aws.crossplane.io # Exact EKS clusters +``` +{{}} + +## 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.crossplane.io","*.ec2.aws.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.crossplane.io" # AWS S3 resources + - "*.ec2.aws.crossplane.io" # AWS EC2 resources + - "*.storage.gcp.crossplane.io" # GCP Storage resources + - "*.compute.gcp.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.crossplane.io # Just S3 buckets + - instances.ec2.aws.crossplane.io # Just EC2 instances + - databases.rds.aws.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.crossplane.io" + - "*.storage.gcp.crossplane.io" +--- +# Database team MRAP +apiVersion: apiextensions.crossplane.io/v1alpha1 +kind: ManagedResourceActivationPolicy +metadata: + name: database-team +spec: + activate: + - "*.rds.aws.crossplane.io" + - "*.sql.gcp.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.crossplane.io # For static assets + - instances.ec2.aws.crossplane.io # For web servers + - databases.rds.aws.crossplane.io # For application data + - certificates.acm.aws.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.crossplane.io + - instances.ec2.aws.crossplane.io + - instances.rds.aws.crossplane.io + - securitygroups.ec2.aws.crossplane.io + - subnets.ec2.aws.crossplane.io + - vpcs.ec2.aws.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.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 00000000..7f868fa3 --- /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.crossplane.io +spec: + group: s3.aws.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.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.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 6b57ce9b..a6d8d520 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/whats-new/_index.md b/content/master/whats-new/_index.md index fb29fdb7..1267d601 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 b1ee0f02..12ed111a 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 50a59d28..17e5a390 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 a86c0320..ae35534f 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