Skip to main content

Overview

ClusterAIScaleTemplate watches for Deployments, StatefulSets, and Argo Rollouts that match a label selector, and automatically creates corresponding AIScaleTargets with a predefined configuration. When workloads are added, updated, or removed, Thoras automatically manages the lifecycle of the associated AIScaleTargets.

Use Cases

  • Apply AI-powered scaling to all workloads with a specific label (e.g., thoras.ai/enabled: "true")
  • Standardize scaling policies across multiple microservices
  • Automatically enable AI scaling for new workloads as they’re deployed
  • Manage scaling configuration for entire application tiers or environments

Basic Example

This template will automatically create AIScaleTargets for all Deployments, StatefulSets, and Argo Rollouts in any namespace that have the labels env: production and thoras.ai/enabled: "true".

Specification

ClusterAIScaleTemplateSpec

AIScaleTemplateSpec

The template spec contains the same fields as AIScaleTarget spec, minus the scaleTargetRef (which is automatically populated based on the matched workload):

TemplatePolicy

Behavior

Automatic AIScaleTarget Creation

When a workload (Deployment, StatefulSet, or Argo Rollout) matches the template’s selector:
  1. Thoras creates an AIScaleTarget with the name <workload-name>-ast
  2. The AIScaleTarget is labeled with thoras.ai/managed-by-template: <template-name>
  3. The AIScaleTarget has an owner reference to the workload (so it’s deleted when the workload is deleted)
  4. The scaleTargetRef is automatically populated with the workload’s details

Lifecycle Management

  • Workload Created: AIScaleTarget is automatically created
  • Workload Updated: If labels change and no longer match, the AIScaleTarget is deleted
  • Workload Opted Out: If the workload is annotated with thoras.ai/skip-template: "true", the template stops managing it. Any existing AIScaleTarget is retained, not deleted; see Opting a Workload Out
  • Workload Deleted: AIScaleTarget is automatically deleted via owner reference
  • Template Updated: All managed AIScaleTargets are updated to match the new template
  • Template Deleted: All managed AIScaleTargets are automatically deleted

Conflict Resolution

When reconciling a controller (e.g. Deployment, Rollout, etc.), Thoras checks whether an AIScaleTarget already exists that targets the controller via scaleTargetRef and applies the following conflictResolution policies:
  • skip (default): The existing AIScaleTarget is left unchanged. Changes made to the template will not be reflected in the conflicting AIScaleTarget.
  • override: The template takes ownership of the conflicting AIScaleTarget. The template’s configuration is applied to the AIScaleTarget.
Note: Thoras checks the thoras.ai/managed-by-template label to determine ownership. Only AIScaleTargets created by that specific template will be updated or deleted by it.

Opting a Workload Out

A workload that matches a template’s selector can still opt out of template management by setting an annotation on the workload itself (Deployment, StatefulSet, or Argo Rollout) — not on its pods:
The behavior depends on whether an AIScaleTarget already exists for the workload:
  • No AIScaleTarget exists yet: none is created while the annotation is present.
  • An AIScaleTarget already exists: it is left in place. The template stops updating it, but its history, model state, and suggestions are retained.
A retained AIScaleTarget is not paused — it keeps scaling using its last template-applied configuration. Opting out of a template stops the template from managing the AIScaleTarget; it does not stop autoscaling. See Stopping Autonomous Scaling if your goal is to halt scaling actions.
Removing the annotation (or setting it to "false") resumes template management on the next reconcile, updating any retained AIScaleTarget in place. The annotation value is parsed as a boolean: "true", "True", "TRUE", and "1" opt the workload out. "false", "0", an absent annotation, and empty or unparseable values are all treated as not opted out.

Namespace Filtering

Use policy.includedNamespaces or policy.excludedNamespaces to control which namespaces the template targets. The two fields are mutually exclusive, set one or the other, not both.
  • includedNamespaces (allowlist): only the listed namespaces are in scope. All other namespaces are ignored.
  • excludedNamespaces (denylist): all namespaces are in scope except those listed.
No namespaces are excluded by default. If you want to protect system namespaces, add them explicitly:

Advanced Examples

Using matchExpressions

Restricting to Specific Namespaces

Use includedNamespaces to target only the namespaces you want:

Multiple Templates

You can create multiple templates with different selectors for different workload categories:

Status and Monitoring

ClusterAIScaleTemplate includes a status subresource with conditions to track reconciliation state:

Condition Types

Check template status:
View all managed AIScaleTargets:

Best Practices

  1. Use Specific Selectors: Use precise label selectors to avoid unintended matches. Consider using a dedicated label like thoras.ai/enabled: "true" on workloads you want to scale.
  2. Test in Non-Production First: Create a template in a development environment first to verify the selector matches the intended workloads.
  3. Monitor Template Status: Regularly check the template’s status conditions to ensure successful reconciliation.
  4. Namespace Filtering: No namespaces are excluded by default. Use policy.excludedNamespaces to block system namespaces (e.g., kube-system, kube-public, kube-node-lease) and any namespaces where automated scaling could cause issues. Use policy.includedNamespaces when you want to restrict the template to a known set of namespaces.
  5. Template Naming: Use descriptive names that indicate the purpose or scope (e.g., production-frontend, staging-all-services).
  6. Label Workloads Explicitly: Rather than relying on existing labels, add a specific label to workloads you want managed by templates (e.g., thoras.ai/template: "production-workloads").
  7. Avoid Overlapping Templates: Ensure template selectors don’t overlap in ways that would cause multiple templates to match the same workloads.

Troubleshooting

Template Not Creating AIScaleTargets

  1. Check the template status:
  2. Verify workloads match the selector:
  3. Check namespace filtering configuration:
  4. View operator logs:

Workload Matches the Selector But Has No AIScaleTarget

If a workload matches the template’s selector and namespace filtering, but no AIScaleTarget is created (or an existing one stops being updated), check for the opt-out annotation:
If this returns true, the workload has opted out of template management. See Opting a Workload Out. Remove the annotation to resume management.

AIScaleTarget Not Updating When Template Changes

Ensure the AIScaleTarget has the thoras.ai/managed-by-template label:
If the label is missing or points to a different template, the AIScaleTarget was not created by this template and won’t be updated by it.

Deleting Template But AIScaleTargets Remain

Check if the finalizer is stuck:
View operator logs for errors during cleanup:

Migration from Manual AIScaleTargets

To migrate existing manually created AIScaleTargets to template management:
  1. Create a ClusterAIScaleTemplate with the desired configuration
  2. Add matching labels to your workloads
  3. The template will skip existing AIScaleTargets (due to default skip conflict resolution)
  4. Manually delete existing AIScaleTargets - they will be automatically recreated by the template
  5. Verify new AIScaleTargets have the thoras.ai/managed-by-template label
Alternatively, manually add the label to existing AIScaleTargets:
Warning: Only do this if you’re certain the template configuration matches your existing AIScaleTarget configuration, as the template will overwrite the spec on the next reconciliation.