Optimize custom workloads using CRDs
3 minute read
Use this guide if your organization defines workloads with CRDs, for example:
- Custom workloads unique to your organization’s platform.
- Third-party operators such as GitHub’s Actions Runner Controller (ARC) or Apache Spark applications.
By default, StormForge Optimize Live supports standard Kubernetes workload types such as Deployments, StatefulSets, and DaemonSets, as well as common third-party workload types, such as Argo Rollouts.
Optimize Live also supports custom workload types defined by Custom Resource Definitions (CRDs). If your CRD represents the workload itself, you can configure StormForge to recognize and optimize it using the workloadResourceTypes Helm parameter.
How Optimize Live handles custom workloads
- Discovery: The StormForge Agent monitors for resources matching the
GroupandKinddefined by theworkloadResourceTypesHelm parameter. - Recognition: StormForge treats discovered resources as workloads.
- Optimization: StormForge analyzes workload usage metrics and generates recommendations.
- Patching: StormForge generates one or more patches when a recommendation is applied. Different apply methods result in different kinds of patches.
Prerequisites
For StormForge to recognize your CRD as a workload type, ensure it meets the following requirements:
- Pod ownership can be traced to the CRD through owner references
- The CRD implements the scale subresource
Define a custom workload type
Define custom workload types using the Helm parameter workloadResourceTypes in the StormForge Agent’s Helm configuration.
When defining a custom workload type, StormForge needs to know the resource’s API Group and Kind, and—to support patching—the specific CRD fields it might need to update.
Helm parameter: workloadResourceTypes
The workloadResourceTypes parameter is a list of objects with the following fields:
| Field | Description | Required |
|---|---|---|
group |
CRD API group (for example, actions.github.com). |
Yes |
kind |
CRD Kind (for example, AutoscalingRunnerSet). |
Yes |
resource |
API resource name (for example, autoscalingrunnersets). |
Yes |
patchTargetTypeDefaults |
(Map) Default patch paths. Required for patching. | Conditional |
Patch target type defaults
StormForge uses patch paths to determine which workload fields to update when performing optimization operations.
Patch path values are Go templates that StormForge resolves into JSON pointers (with some extensions).
Common keys for patchTargetTypeDefaults:
live.stormforge.io/containers.cpu.requests.patch-pathlive.stormforge.io/containers.cpu.limits.patch-pathlive.stormforge.io/containers.memory.requests.patch-pathlive.stormforge.io/containers.memory.limits.patch-path
Contact StormForge support for information on how to define patch path settings for your workload.
Example: GitHub ARC
Suppose you are hosting your own GitHub Actions runners with ARC, and you want to optimize the AutoscalingRunnerSet resource.
For StormForge to apply recommendations, you need to map ARC’s AutoScalingRunnerSet template and resource fields.
Accessing the memory and CPU requests involves navigating the spec to find the container template.
Your values.yaml may resemble the following:
workloadResourceTypes:
- group: actions.github.com
kind: AutoscalingRunnerSet
resource: autoscalingrunnersets
# Configuration values for patch paths depend on your CRD structure.
# For AutoscalingRunnerSet, the pod template is in the spec.
patchTargetTypeDefaults:
# Allows StormForge to rollout/restart the workload when recommendations are applied.
live.stormforge.io/pod-template.metadata.patch-path: >
/spec/template/metadata
# These paths let StormForge patch the container resources on the workload
# definition itself. Not required if using the webhook to patch pods on admission.
live.stormforge.io/containers.cpu.requests.patch-path: >
/spec/template/spec/containers/[name={{ .ContainerName }}]/resources/requests/cpu
live.stormforge.io/containers.cpu.limits.patch-path: >
/spec/template/spec/containers/[name={{ .ContainerName }}]/resources/limits/cpu
live.stormforge.io/containers.memory.requests.patch-path: >
/spec/template/spec/containers/[name={{ .ContainerName }}]/resources/requests/memory
live.stormforge.io/containers.memory.limits.patch-path: >
/spec/template/spec/containers/[name={{ .ContainerName }}]/resources/limits/memory