All Policies

Kubecost Proactive Cost Control

Kubecost Enterprise allows users to define budgets for Namespaces and clusters as well as predict the cost of new Deployments based on historical cost data. By combining these abilities, users can achieve proactive cost controls for clusters with Kubecost installed by denying Deployments which would exceed the remaining configured monthly budget, if applicable. This policy checks for the creation of Deployments and compares the predicted cost of the Deployment to the remaining amount in the monthly budget, if one is found. If the predicted cost is greater than the remaining budget, the Deployment is denied. This policy requires Kubecost Enterprise at a version of 1.108 or greater.

Policy Definition

/kubecost/kubecost-proactive-cost-control/kubecost-proactive-cost-control.yaml

 1apiVersion: kyverno.io/v1
 2kind: ClusterPolicy
 3metadata:
 4  name: kubecost-proactive-cost-control
 5  annotations:
 6    policies.kyverno.io/title: Kubecost Proactive Cost Control
 7    policies.kyverno.io/category: Kubecost
 8    policies.kyverno.io/severity: medium
 9    policies.kyverno.io/subject: Deployment
10    policies.kyverno.io/minversion: 1.11.0
11    kyverno.io/kyverno-version: 1.11.4
12    kyverno.io/kubernetes-version: "1.26"
13    policies.kyverno.io/description: >-
14      Kubecost Enterprise allows users to define budgets for Namespaces and clusters
15      as well as predict the cost of new Deployments based on historical cost data.
16      By combining these abilities, users can achieve proactive cost controls for
17      clusters with Kubecost installed by denying Deployments which would exceed the
18      remaining configured monthly budget, if applicable. This policy checks for the creation of
19      Deployments and compares the predicted cost of the Deployment to the remaining amount
20      in the monthly budget, if one is found. If the predicted cost is greater than the remaining
21      budget, the Deployment is denied. This policy requires Kubecost Enterprise
22      at a version of 1.108 or greater.      
23spec:
24  validationFailureAction: Audit
25  rules:
26  - name: enforce-monthly-namespace-budget
27    match:
28      any:
29      - resources:
30          kinds:
31          - Deployment
32          operations:
33          - CREATE
34    # First, check if this Namespace is subject to a budget.
35    # If it is not, always allow the Deployment.
36    preconditions:
37      all:
38      - key: "{{ budget }}"
39        operator: NotEquals
40        value: nobudget
41    context:
42    # Get the budget of the destination Namespace. Select the first budget returned which matches the Namespace.
43    # If no budget is found, set budget to "nobudget".
44    - name: budget
45      apiCall:
46        method: GET
47        service:
48          url: http://kubecost-cost-analyzer.kubecost:9090/model/budgets
49        jmesPath: "data[?values.namespace[?contains(@,'{{ request.namespace }}')]] | [0] || 'nobudget'"
50    # Call the prediction API and pass it the Deployment from the admission request. Extract the totalMonthlyRate.
51    - name: predictedMonthlyCost
52      apiCall:
53        method: POST
54        data:
55        - key: apiVersion
56          value: "{{ request.object.apiVersion }}"
57        - key: kind
58          value: "{{ request.object.kind }}"
59        - key: spec
60          value: "{{ request.object.spec }}"
61        service:
62          url: http://kubecost-cost-analyzer.kubecost:9090/model/prediction/speccost?clusterID=cluster-one&defaultNamespace=default
63        jmesPath: "[0].costChange.totalMonthlyRate"
64    # Calculate the budget that remains from the window by subtracting the currentSpend from the spendLimit.
65    - name: remainingBudget
66      variable:
67        jmesPath: subtract(budget.spendLimit,budget.currentSpend)
68    validate:
69      message: >-
70        This Deployment, which costs ${{ round(predictedMonthlyCost, `2`) }} to run for a month,
71        will overrun the remaining budget of ${{ round(remainingBudget,`2`) }}. Please seek approval or request
72        a Policy Exception.        
73      # Deny the request if the predictedMonthlyCost is greater than the remainingBudget.
74      deny:
75        conditions:
76          all:
77          - key: "{{ predictedMonthlyCost }}"
78            operator: GreaterThan
79            value: "{{ remainingBudget }}"