/kubectl-cost

CLI for determining the cost of Kubernetes workloads

Primary LanguageGoApache License 2.0Apache-2.0

kubectl-cost

kubectl-cost is a kubectl plugin that provides easy CLI access to Kubernetes cost information, like historical cost and predicted future cost, via Kubecost's APIs. It allows developers, devops, and others to quickly determine the cost & efficiency of any Kubernetes workload.

Note: If you use OpenCost, most of kubectl cost works! See the OpenCost documentation for examples. Let us know how it goes, and open an issue if you encounter any problems!

‼️ New! Starting with Kubecost v1.100, kubectl cost can estimate the cost of undeployed changes! Try it now with kubectl cost predict -f your-deployment.yaml:

 OBJECT                        Δ QTY  RESOURCE UNIT   COST PER UNIT     Δ COST/MO  % CHANGE 
────────────────────────────────────────────────────────────────────────────────────────────
 kubecost1 deployment            -92  CPU millicores      0.023 USD     -2.14 USD   -92.00% 
 kubecost1-cost-analyzer                                                                    
                             -172.65  RAM MiB            0.0030 USD     -0.53 USD   -43.38% 

Standard CLI Usage

TUI Usage

Installation

  1. Install Kubecost

    This software requires that you have a running deployment of Kubecost in your cluster. The recommend path is to use Helm but there are alternative install options.

    Helm 3

    helm repo add kubecost https://kubecost.github.io/cost-analyzer/
    helm upgrade -i --create-namespace kubecost kubecost/cost-analyzer --namespace kubecost --set kubecostToken="a3ViZWN0bEBrdWJlY29zdC5jb20=xm343yadf98"
    
  2. Install kubectl cost

    Krew

    If you have Krew, the kubectl plugin manager, installed:

    kubectl krew install cost

    The Krew manifest can be found here.

    Linux/MacOS

    os=$(uname | tr '[:upper:]' '[:lower:]') && \
    arch=$(uname -m | tr '[:upper:]' '[:lower:]' | sed -e s/x86_64/amd64/) && \
    curl -s -L https://github.com/kubecost/kubectl-cost/releases/latest/download/kubectl-cost-$os-$arch.tar.gz | tar xz -C /tmp && \
    chmod +x /tmp/kubectl-cost && \
    sudo mv /tmp/kubectl-cost /usr/local/bin/kubectl-cost

    Latest Release

    If you prefer to download from GitHub, or are on Windows, go to the releases page and download the appropriate binary for your system. Rename it to kubectl-cost and put it in your PATH.

    As long as the binary is still named kubectl-cost and is somewhere in your PATH, it will be usable. This is because kubectl automatically finds plugins by looking for executables prefixed with kubectl- in your PATH.

    Alternatively, you can view DEVELOPMENT.md if you would like to build from source.

Usage

There are several subcommands that focused on aggregation-based cost monitoring: namespace, deployment, controller, label, pod, and node. They display cost information aggregated by the name of the subcommand (see Examples). Each aggregation subcommand has two modes: rate and non-rate. Rate (the default) displays the projected monthly cost based on the activity during the window. Non-rate (--historical) displays the total cost for the duration of the window.

Starting with v1.100 installations of Kubecost, kubectl cost predict is available. It uses historical resource cost information in your cluster to predict the cost implications of undeployed changes. It currently supports Pod, Deployment, and StatefulSet workloads, with more support on the way. It accepts YAML-formatted data either in a file (-f your-file.yaml) or from STDIN (-f -).

There is also kubectl cost tui, which displays a TUI and is currently limited to monthly rate projections. It supports most of the above subcommands while in an experimental status.

See the built-in usage info with --help to learn more about specific flags available for each subcommand.

Examples

Show the projected monthly rate for each namespace with all cost components displayed.

kubectl cost namespace --show-all-resources

Example output:

+-------------------+-----------+----------+----------+-------------+----------+----------+----------+-------------+--------------------+
| NAMESPACE         | CPU       | CPU EFF. | MEMORY   | MEMORY EFF. | GPU      | PV       | NETWORK  | SHARED COST | MONTHLY RATE (ALL) |
+-------------------+-----------+----------+----------+-------------+----------+----------+----------+-------------+--------------------+
| kube-system       | 29.366083 | 0.066780 | 5.226317 | 0.928257    | 0.000000 | 0.000000 | 0.000000 | 137.142857  |         171.735257 |
| kubecost-stage    | 6.602761  | 0.158069 | 1.824703 | 1.594699    | 0.000000 | 2.569600 | 0.000000 | 137.142857  |         148.139922 |
| kubecost          | 6.499445  | 0.116629 | 1.442334 | 1.461370    | 0.000000 | 2.569600 | 0.000000 | 137.142857  |         147.654236 |
| default           | 3.929377  | 0.000457 | 0.237937 | 0.283941    | 0.000000 | 0.000000 | 0.000000 | 137.142857  |         141.310171 |
| logging           | 0.770976  | 0.003419 | 0.645843 | 0.260154    | 0.000000 | 0.000000 | 0.000000 | 137.142857  |         138.559676 |
| frontend-services | 0.710425  | 0.003660 | 0.595008 | 0.244802    | 0.000000 | 0.000000 | 0.000000 | 137.142857  |         138.448290 |
| data-science      | 0.000284  | 2.000000 | 0.009500 | 2.000000    | 0.000000 | 0.000000 | 0.000000 | 137.142857  |         137.152641 |
+-------------------+-----------+----------+----------+-------------+----------+----------+----------+-------------+--------------------+
| SUMMED            | 47.879350 |          | 9.981644 |             | 0.000000 | 5.139200 | 0.000000 | 960.000000  |        1023.000194 |
+-------------------+-----------+----------+----------+-------------+----------+----------+----------+-------------+--------------------+

Predict the cost impact of a YAML spec based on its requests:

read -r -d '' DEF << EndOfMessage
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: default
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        resources:
          requests:
            cpu: "3"
            memory: "2Gi"
EndOfMessage
echo "$DEF" | kubectl cost predict -f -

Example output:

 OBJECT                      Δ QTY  RESOURCE UNIT  COST PER UNIT    Δ COST/MO  % CHANGE 
────────────────────────────────────────────────────────────────────────────────────────
 default deployment             +9  CPU cores          23.27 USD  +209.47 USD           
 nginx-deployment                                                                       
                                +6  RAM GiB             3.12 USD   +18.72 USD           
                                                                                        
────────────────────────────────────────────────────────────────────────────────────────
 TOTAL MONTHLY COST CHANGE                                        +228.18 USD           

Show how much each namespace cost over the past 5 days with additional CPU and memory cost and without efficiency.

kubectl cost namespace \
  --historical \
  --window 5d \
  --show-cpu \
  --show-memory \
  --show-efficiency=false

Predict the cost of the Deployment defined in k8s-deployment.yaml.

kubectl cost predict -f 'k8s-deployment.yaml' \
  --show-cost-per-resource-hr

Show the projected monthly rate for each controller based on the last 5 days of activity with PV (persistent volume) cost breakdown.

kubectl cost controller --window 5d --show-pv

Show costs over the past 5 days broken down by the value of the app label:

kubectl cost label --historical -l app

Show the projected monthly rate for each deployment based on the last month of activity with CPU, memory, GPU, PV, and network cost breakdown.

kubectl cost deployment --window month -A

Show the projected monthly rate for each deployment in the kubecost namespace based on the last 3 days of activity with CPU cost breakdown.

kubectl cost deployment \
  --window 3d \
  --show-cpu \
  -n kubecost

The same, but with a non-standard Kubecost deployment in the namespace kubecost-staging with the cost analyzer service called kubecost-staging-cost-analyzer.

kubectl cost deployment \
  --window 3d \
  --show-cpu \
  -n kubecost \
  -N kubecost-staging \
  --service-name kubecost-staging-cost-analyzer

Show how much each pod in the "kube-system" namespace cost yesterday, including CPU-specific cost.

kubectl cost pod \
  --historical \
  --window yesterday \
  --show-cpu \
  -n kube-system

Alternatively, kubectl cost can show cost by the asset type. To view node cost with breakdowns of RAM and CPU cost for a window of 7 days.

kubectl cost node \
  --historical \
  --window 7d \
  --show-cpu \
  --show-memory

Which yields an output with this format:

+-------------+---------------------------------------------+---------------+--------------+---------------+
| CLUSTER     | NAME                                        | CPU COST      | RAM COST     | TOTAL COST    |
+-------------+---------------------------------------------+---------------+--------------+---------------+
| cluster-one | gke-test-cluster-default-pool-d6266c7c-dqms |      4.128570 |     2.128920 |      6.257491 |
|             | gke-test-cluster-pool-1-9bb98ef8-3w6g       |      4.128570 |     2.128920 |      6.257491 |
|             | gke-test-cluster-pool-1-9bb98ef8-cf3j       |      4.128570 |     2.128924 |      6.257495 |
|             | gke-test-cluster-pool-1-9bb98ef8-kdsf       |      4.128570 |     2.128924 |      6.257495 |
+-------------+---------------------------------------------+---------------+--------------+---------------+
| SUMMED      |                                             | USD 16.514280 | USD 8.515688 | USD 25.029972 |
+-------------+---------------------------------------------+---------------+--------------+---------------+

Flags

See kubectl cost [subcommand] --help for the full set of flags. Each subcommand has its own set of flags for adjusting query behavior and output.

There are several flags that modify the behavior of queries to the backing Kubecost/OpenCost APIs:

    -r, --release-name string         The name of the Helm release, used to template service names if they are unset. For example, if Kubecost is installed with 'helm install kubecost2 kubecost/cost-analyzer', then this should be set to 'kubecost2'. (default "kubecost")
    --service-name string             The name of the Kubecost cost analyzer service. By default, it is derived from the Helm release name and should not need to be overridden.
    --service-port int                The port of the service at which the APIs are running. If using OpenCost, you may want to set this to 9003. (default 9090)
    -N, --kubecost-namespace string   The namespace that Kubecost is deployed in. Requests to the API will be directed to this namespace. Defaults to the Helm release name.

    --use-proxy                       Instead of temporarily port-forwarding, proxy a request to Kubecost through the Kubernetes API server.

    --allocation-path string          URL path at which Allocation queries can be served from the configured service. If using OpenCost, you may want to set this to '/allocation/compute' (default "/model/allocation")

    --predict-speccost-path string    URL path at which Prediction queries can be served from the configured service. (default "/model/prediction/speccost")
    --no-usage                        Set true ignore historical usage data (if any exists) when performing cost prediction.
    --only-after                      Set true to only show the overall predicted cost of the workload.
    --only-diff                       Set true to only show the cost difference (cost "impact") instead of the overall cost plus diff. (default true)

kubectl cost has to interact with the Kubernetes API server. It tries to use your existing kubeconfig. These flags are common to kubectl and allow you to customize this behavior:

      --as string                      Username to impersonate for the operation
      --as-group stringArray           Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
      --cache-dir string               Default cache directory (default "/home/delta/.kube/cache")
      --certificate-authority string   Path to a cert file for the certificate authority
      --client-certificate string      Path to a client certificate file for TLS
      --client-key string              Path to a client key file for TLS
      --cluster string                 The name of the kubeconfig cluster to use
      --context string                 The name of the kubeconfig context to use
  -h, --help                           help for cost
      --insecure-skip-tls-verify       If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
      --kubeconfig string              Path to the kubeconfig file to use for CLI requests.
      --request-timeout string         The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
  -s, --server string                  The address and port of the Kubernetes API server
      --tls-server-name string         Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used
      --token string                   Bearer token for authentication to the API server
      --user string                    The name of the kubeconfig user to use

If something breaks

kubectl cost logs some of its behavior at the debug log level. If something isn't working as you'd expect, try setting --log-level debug before opening a bug report.

Implementation Quirks

In order to provide a seamless experience for standard Kubernetes configurations, kubectl-cost temporarily forwards a port on your system to a Kubecost pod and uses that port to proxy requests. The port will only be bound to localhost and will only be open for the duration of the kubectl cost run. Due to Linux default conventions, the port may appear as held for a little while after the run (see TCP's TIME_WAIT).

If you don't want a port to be temporarily forwarded, there is legacy behavior exposed with the flag --use-proxy or using environment KUBECTL_COST_USE_PROXY that will instead use the Kubernetes API server to proxy requests to Kubecost. This behavior has its own pitfalls, especially with security policies that would prevent the API server from communicating with services. If you'd like to test this behavior, to make sure it will work with your cluster:

kubectl proxy --port 8080
curl -G 'http://localhost:8080/api/v1/namespaces/kubecost/services/kubecost-cost-analyzer:tcp-model/proxy/getConfigs'

If you are running an old version of Kubecost, you may have to replace tcp-model with model

If that curl succeeds, --use-proxy flag in CLI or setting up environment variable KUBECTL_COST_USE_PROXY should work for you.

Otherwise:

  • There may be an underlying problem with your Kubecost install, try kubectl port-forwarding the kubecost-cost-analyzer service, port 9090, and querying one of our APIs.
  • Your problem could be a security configuration that is preventing the API server communicating with certain namespaces or proxying requests in general.
  • If you're still having problems, hit us up on Slack (see below) or open an issue on this repo.

Requirements

A cluster running Kubernetes version 1.8 or higher

Have questions? Join our Slack community or contact us via email at team@kubecost.com!