Deploying operator resource mapping (ORM)
To optimize the performance of your containerized workloads, Turbonomic for Government Standard can recommend actions such as resizing container specs vertically and scaling replicas horizontally. The Kubeturbo agent executes these actions by updating workload specifications programmatically through workload controllers.
If an operator manages the lifecycle of microservice-based applications and workloads in your environment to maintain their intended configurations, it is possible for the operator to revert any Kubeturbo updates because the updates were not applied through the operator's Custom Resource (CR). To prevent this issue, deploy operator resource mapping (ORM) that defines how to update specifications through the CR. The operator then rolls out the updates.
When you deploy ORM, you define the operand for managing resources and maintaining their intended configurations. Specifically, you configure parameters that control how other assets can make changes to the CR programmatically.
ORM schema
For ORM samples, see this GitHub page.
apiVersion: devops.turbonomic.io/v1alpha1 # version of the api that manifest is using
kind: OperatorResourceMapping # type of kubernetes resource
metadata:
name: orm # name of the resource
namespace: # namespace where this resource is located
...
spec:
mappings:
patterns:
- owned:
apiVersion: # api version for owned resource
kind: # type of owned resource
path: # The JSON path to the resource property to be mapped, targeting specific containers within an owned resource.
selector: # reference to the selector
ownerPath: #JSON path to the resource location in the owner object, where the values should be reflected
selectors: # Defines label selectors for identifying resources.
xyz: # A named selector.
matchLabels: # Label selectors used to identify resources
...
owner:
apiVersion: # The API version of the owner resource
kind: # The kind of the owner resource
name: # The name of the owner resource
status:
lastTransitionTime: # The timestamp of the last status change
owner:
apiVersion: # Details of owner resource specified in 'spec.owner'
kind:
name:
namespace:
ownerValues: # The values from the owner resource that correspond to the mappings.
- owned: # Details of the owned resource specified in 'spec.mappings.patterns.owned'
apiVersion:
kind:
name:
namespace:
path: # The JSON path to the resource property to be mapped, targeting specific containers within an owned resource.
ownerPath: #JSON path to the resource location in the owner object, where the values should be reflected
value:
resources: {}
state: # The status of the resource mapping indicates whether it is 'ok' or if there have been any errors with a reason during the discovery of ORM's and building the ORM mapping registry .
The schema includes the following properties:
| Property | Description |
|---|---|
owner |
An operator resource that manages owned (see the next item). Any
change to owner triggers the operator to update owned.Note:
An |
owned |
A resource deployed by an operator. This resource responds to changes in
owner (see the previous item). |
mappings |
A pair of paths in owner and owned |
patterns |
A pair of paths in owner and ownedYou can
define parameters to generate multiple
|
selectors |
Predefined label selectors that are used in patterns |
Use case 1: One ORM for one owned resource controlled by one
owner
For file samples in support of this use case, see this GitHub page.
-
ownerkind: Deployment metadata: name: ormowner-solo -
ownedkind: Deployment metadata: name: ormowned-solo -
ORM
kind: OperatorResourceMapping metadata: name: solo owner: kind: Deployment name: ormowner-solo mappings: patterns: owned: kind: Deployment name: ormowned-solo
Use case 2: One ORM for two owned resources controlled by one
owner
For file samples in support of this use case, see this GitHub page.
-
ownerkind: Deployment metadata: name: ormowner-patterns -
owned-1kind: Deployment metadata: name: ormowned-0001 labels: app: ormowned-patterns id: "00001" -
owned-2kind: Deployment metadata: name: ormowned-0002 labels: app: ormowned-patterns id: "00002" -
ORM
kind: OperatorResourceMapping metadata: name: patterns owner: kind: Deployment name: ormowner-patterns owned: kind: Deployment matchLabels: app: ormowned-patterns id: "00001" owned: kind: Deployment matchLabels: app: ormowned-patterns id: "00002"
Use case 3: Multiple ORMs for one owned resource with a hierarchy of
owners
For file samples in support of this use case, see this GitHub page.
-
owner-1kind: Deployment metadata: name: ormowner-1 -
owner-2kind: Deployment metadata: name: ormowner-2 -
ownedkind: Deployment metadata: name: ormowned -
ORM 1
kind: OperatorResourceMapping metadata: name: hierarchy-1 owner: kind: Deployment name: ormowner-1 owned: kind: Deployment name: ormowned -
ORM 2
kind: OperatorResourceMapping metadata: name: hierarchy-2 owner: kind: Deployment name: ormowner-2 owned: kind: Deployment name: ormowner-1
Testing your ORM CR
-
Clone the
turbonomic-container-platformrepository.mkdir turbonomiccd turbonomicgit clone https://github.com/IBM/turbonomic-container-platform.gitcd orm -
Create the CRD for the ORM in the cluster where you deployed Kubeturbo.
kubectl apply -f install/devops.turbonomic.io_operatorresourcemappings.yamlNote:The CRD supports Kubernetes 1.16 and later.
-
Deploy the ORM CR to the namespace of the application where actions for containerized workloads are executed.
For sample CRs, see this GitHub page.
In the following example, the CR deploys to the namespace where Turbonomic for Government Standard runs to enable resizing of Turbonomic for Government Standard services.
kubectl -n turbonomic apply -f examples/ibm/turbo_operator_resource_mapping_sample_cr.yaml -
In the Turbonomic for Government Standard user interface, navigate to Settings > Target configuration, find and select the Kubeturbo target, and then click Rediscover.
You do not need to restart the corresponding Kubeturbo pod in the cluster. Kubeturbo automatically discovers the ORM CR when you see a message similar to the following example.
I0118 22:34:08.013144 1 k8s_discovery_client.go:327] Discovered 1 v2 ORM Resources.Note:For Kubeturbo to access the operator-managed CRs from the CRD and map the resources using ORM, Kubeturbo should run with the
cluster-adminrole. For more information about roles, see this topic. -
Try the Redis Standalone example to see the relationship between the operator and the resource it manages.
-
Create Redis Standalone by following the instructions in this GitHub page.
-
Run the following command:
helm list -AThe command returns results similar to the following example.
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION redis ot-operators 1 2023-05-04 12:27:31.051399 -0400 EDT deployed redis-0.14.2 0.14.0 redis-operator ot-operators 1 2023-03-13 12:31:40.264923 -0400 EDT deployed redis-operator-0.14.3 0.14.0 -
Get the Redis Standalone controller resource.
kubectl get statefulset -n ot-operators -oyamlapiVersion: v1 items: - apiVersion: apps/v1 kind: StatefulSet metadata: annotations: redis.opstreelabs.in: "true" redis.opstreelabs.instance: redis-standalone creationTimestamp: "2024-01-25T21:48:58Z" generation: 1 labels: app: redis-standalone redis_setup_type: standalone role: standalone name: redis-standalone namespace: ot-operators ownerReferences: - apiVersion: redis.redis.opstreelabs.in/v1beta1 controller: true kind: Redis name: redis-standalone uid: 6dd0759d-0c67-48e7-903b-bf74b9c8e4a1 resourceVersion: "41508623" uid: 256b404c-1961-471e-9d1c-5085d44e2de2 spec: podManagementPolicy: OrderedReady replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: redis-standalone redis_setup_type: standalone role: standalone serviceName: redis-standalone-headless template: metadata: annotations: redis.opstreelabs.in: "true" redis.opstreelabs.instance: redis-standalone creationTimestamp: null labels: app: redis-standalone redis_setup_type: standalone role: standalone spec: containers: - env: - name: REDIS_ADDR value: redis://localhost:6379 - name: SERVER_MODE value: standalone - name: SETUP_MODE value: standalone image: quay.io/opstree/redis:v7.0.5 imagePullPolicy: IfNotPresent livenessProbe: exec: command: - bash - /usr/bin/healthcheck.sh failureThreshold: 3 initialDelaySeconds: 1 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 name: redis-standalone readinessProbe: exec: command: - bash - /usr/bin/healthcheck.sh failureThreshold: 3 initialDelaySeconds: 1 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 resources: limits: cpu: 100m memory: 128Mi requests: cpu: 20m memory: 24Mi terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 updateStrategy: rollingUpdate: partition: 0 type: RollingUpdate status: availableReplicas: 1 collisionCount: 0 currentReplicas: 1 currentRevision: redis-standalone-799b86b4b5 observedGeneration: 1 readyReplicas: 1 replicas: 1 updateRevision: redis-standalone-799b86b4b5 updatedReplicas: 1 kind: List metadata: resourceVersion: "" -
Get the Redis operator CR.
kubectl get redis redis-standalone -n ot-operators -oyamlapiVersion: redis.redis.opstreelabs.in/v1beta1 kind: Redis metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: creationTimestamp: "2024-01-25T21:48:58Z" finalizers: - redisFinalizer generation: 2 name: redis-standalone namespace: ot-operators resourceVersion: "41508397" uid: 6dd0759d-0c67-48e7-903b-bf74b9c8e4a1 spec: kubernetesConfig: image: quay.io/opstree/redis:v7.0.5 imagePullPolicy: IfNotPresent resources: limits: cpu: 100m memory: 128Mi requests: cpu: 20m memory: 24Mi livenessProbe: failureThreshold: 3 initialDelaySeconds: 1 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 readinessProbe: failureThreshold: 3 initialDelaySeconds: 1 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 redisExporter: image: quay.io/opstree/redis-exporter:v1.44.0 securityContext: {} -
Apply the redis standalone orm from library.
kubectl get orm -n ot-operators redis-orm -o yamlThe patterns defined in
specare found in the cluster. Details are shown in thestatussection.apiVersion: devops.turbonomic.io/v1alpha1 kind: OperatorResourceMapping metadata: name: redis-orm namespace: ot-operators ... spec: mappings: patterns: - owned: apiVersion: apps/v1 kind: StatefulSet path: .spec.template.spec.containers[?(@.name=="redis")].resources selector: my_redis_sts ownerPath: .spec.kubernetesConfig.resources selectors: my_redis_sts: matchLabels: app: redis owner: apiVersion: redis.redis.opstreelabs.in/v1beta1 kind: Redis name: redis status: lastTransitionTime: "2023-05-04T17:27:05Z" owner: apiVersion: redis.redis.opstreelabs.in/v1beta1 kind: Redis name: redis namespace: ot-operators ownerValues: - owned: apiVersion: apps/v1 kind: StatefulSet name: redis namespace: ot-operators path: .spec.template.spec.containers[?(@.name=="redis")].resources ownerPath: .spec.kubernetesConfig.resources value: resources: {} state: ok
-