> ## Documentation Index
> Fetch the complete documentation index at: https://backstage.spotify.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Kubernetes

> Collect facts from Kubernetes clusters including pods, deployments, services, HPAs, stateful sets, and ingresses via the Kubernetes API.

Kubernetes integration for [Soundcheck](https://backstage.spotify.com/plugins/soundcheck/).

This integration collects facts from your kubernetes clusters through its API.
How it collects these facts is similar to the [backstage kubernetes plugin](https://backstage.io/docs/features/kubernetes/).

The kubernetes integration currently supports the following facts:

* [services](https://kubernetes.io/docs/concepts/services-networking/service/)
* [pods](https://kubernetes.io/docs/concepts/workloads/pods/)
* [deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)
* [horizontal pod autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)
* [stateful sets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)
* [pod disruption budgets](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/)
* [ingresses](https://kubernetes.io/docs/concepts/services-networking/ingress/)

See the [facts section](#defining-kubernetes-fact-collector) for more details.

## Prerequisites

### Configure Kubernetes Integration in Backstage

Configure kubernetes according to the backstage kubernetes plugin [docs](https://backstage.io/docs/features/kubernetes/configuration).

**Note: the Kubernetes plugin has the following limitations:**

1. We only support the [catalog](https://backstage.io/docs/features/kubernetes/configuration#catalog) and [config](https://backstage.io/docs/features/kubernetes/configuration#config) `clusterLocatorMethods`.
2. [apiVersionOverrides](https://backstage.io/docs/features/kubernetes/configuration#apiversionoverrides-optional) are currently not supported.
3. We only support certain server-side authentication strategies. See [authentication section](#authentication) for details.

Example:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
kubernetes:
  serviceLocatorMethod:
    type: 'singleTenant'
  clusterLocatorMethods:
    - type: catalog
    - type: 'config'
    clusters:
      - url: https://127.0.0.1:59974
        name: minikube
        authProvider: 'serviceAccount'
        skipTLSVerify: true
        skipMetricsLookup: true
        serviceAccountToken: ${K8S_MINIKUBE_TOKEN}
```

Ensure your components are [annotated correctly](https://backstage.io/docs/features/kubernetes/configuration#surfacing-your-kubernetes-components-as-part-of-an-entity).
The fact collector will only collect facts from entities that have the `backstage.io/kubernetes-id` annotation.

#### Labels in Kubernetes

By default, the label selector used to query the kubernetes cluster is `app={backstage.io/kubernetes-id}`.

You can use a custom label selector by using the `backstage.io/kubernetes-label-selector` annotation.

#### Authentication

Configure your authentication according to the [kubernetes plugin](https://backstage.io/docs/features/kubernetes/authentication).

The fact collector only supports the following server side auth strategies:

* aws
* azure
* googleServiceAccount
* serviceAccount

**Note: google and aks client side strategies will be mapped to googleServiceAccount and azure respectively.**

### Add the Kubernetes Fact Collector to Soundcheck

First, add the `@spotify/backstage-plugin-soundcheck-backend-module-kubernetes` package:

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
yarn workspace backend add @spotify/backstage-plugin-soundcheck-backend-module-kubernetes
```

Then add the following to your `packages/backend/src/index.ts` file:

```ts packages/backend/src/index.ts highlight={4} theme={"theme":{"light":"github-light","dark":"dracula"}}
const backend = createBackend();

backend.add(import('@spotify/backstage-plugin-soundcheck-backend'));
backend.add(
  import('@spotify/backstage-plugin-soundcheck-backend-module-kubernetes'),
);
// ...

backend.start();
```

Consult the [Soundcheck Backend documentation](../../../setup-and-installation#backend-setup) for additional details on setting up the Soundcheck backend.

## Plugin Configuration

Kubernetes Fact Collector can be configured via YAML or No-Code UI. If you configure it via both YAML and No-Code UI, the configurations will be merged.
It's preferable to choose a single source for the Fact Collectors configuration (either No-Code UI or YAML) to avoid confusing merge results.

### No-Code UI Configuration Option

1. Make sure the prerequisite [Configure Kubernetes integration in Backstage](#configure-kubernetes-integration-in-backstage) is completed and Kubernetes instance details are configured.

2. To enable the Kubernetes Integration, go to `Soundcheck > Integrations > Kubernetes` and click the `Configure` button. To learn more about the No-Code UI config, see the [Configuring a fact collector (integration) via the no-code UI](../index#configuring-a-fact-collector-integration-via-the-no-code-ui).

<Frame>
  <img
    src="https://mintcdn.com/spotify-89f50c35/ulmNVnZzSFL3BsWR/plugins/soundcheck/images/collectors/kubernetes-collector-ncui.png?fit=max&auto=format&n=ulmNVnZzSFL3BsWR&q=85&s=766d079ec576e5cbf09ac141b4d14a9e"
    alt="Kubernetes
Integration"
    width="3432"
    height="1912"
    data-path="plugins/soundcheck/images/collectors/kubernetes-collector-ncui.png"
  />
</Frame>

### YAML Configuration Option

1. Create a `kubernetes-facts-collectors.yaml` file in the root of your Backstage repository to use for configuration.

The following example will collect services, pods, deployment facts at the top of every hour:

```yaml kubernetes-facts-collectors.yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
---
frequency:
  cron: '0 * * * *'
collects:
  - type: k8s_services
  - type: k8s_pods
  - type: k8s_deployments
```

**Note:** this file will be loaded at runtime along with the rest of your Backstage configuration files. Therefore, make sure that it's available in deployed environments in the same way as your `app-config.yaml` files are.

2. Add a soundcheck collectors field to `app-config.yaml` and reference the newly created `kubernetes-facts-collectors.yaml`

   ```yaml app-config.yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
   soundcheck:
     collectors:
       kubernetes:
         $include: ./kubernetes-facts-collectors.yaml
   ```

### Rate Limiting (Optional)

This fact collector can be rate limited in Soundcheck using the following configuration:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
soundcheck:
  job:
    workers:
      kubernetes:
        limiter:
          max: 1000
          duration: 60000
```

The following configuration would limit the colection rate to 1000 requests per minute. The above is an example, adjut the numbers as needed for your setup.\_createMdxContent

Soundcheck will automatically pause and retry the fact collector if it encounters rate limit errors.

**Note: Scheduled checks do NOT respect rate limits set here. Checks that utilize fact collectors do NOT need to be scheduled. Instead schedule the fact collector: see [frequency](#frequency-optional).**

## Defining Kubernetes Fact Collector

This section describes the data shape and semantics of **Kubernetes Fact Collector**.

### Overall Shape Of A Kubernetes Fact Collector

The following is an example of a descriptor file for a **Kubernetes Fact Collector**:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
---
frequency:
  cron: '0 * * * *'
initialDelay:
  seconds: 30
filter:
  kind: 'Component'
cache:
  duration:
    hours: 2
collects:
  - type: k8s_services
  - type: k8s_pods
    filter:
      - spec.lifecycle: 'production'
        spec.type: 'service'
    frequency:
      cron: '0 1/2 * * *'
  - type: k8s_deployments
  - type: k8s_hpas
  - type: k8s_stateful_sets
  - type: k8s_pod_disruption_budgets
  - type: k8s_ingresses
```

Below are the details for each field.

#### `frequency` \[optional]

The frequency at which the collector should be executed. Possible values are either a cron expression `{ cron: ... }` or [HumanDuration](https://backstage.io/docs/reference/types.humanduration).
This is the default frequency for each fact type.
Example:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
frequency:
  cron: '0 * * * *'

frequency:
  hours: 3
```

If using a long HumanDuration we recommened you also add an initialDelay to ensure timely fact collection in the case of a deployment or restart.

#### `initialDelay` \[optional]

The amount of time that should pass before the first invocation happens. Possible values are either a cron expression `{ cron: ... }` or [HumanDuration](https://backstage.io/docs/reference/types.humanduration).
This is the default initial delay for each fact type.
Example:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
initialDelay:
  seconds: 30
```

#### `batchSize` \[optional]

The number of entities to collect facts for at once. Optional, the default value is 1.

**Note**: Fact collection for a batch of entities is still considered as one hit towards the rate limits
by the Soundcheck [Rate Limiting](#rate-limiting-optional) engine, while the actual number of hits
will be equal to the `batchSize`.

Example:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
batchSize: 100
```

#### `filter` \[optional]

A filter specifying which entities to collect the specified facts for. Matches the [filter format](https://backstage.io/docs/reference/catalog-client.entityfilterquery) used by the Catalog API.
This is the default filter for each fact type.
Example:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
filter:
  - spec.lifecycle: 'production'
```

See [filters](/plugins/soundcheck/core-concepts/filters) for more details.

#### `exclude` \[optional]

Entities matching this filter will be skipped during the fact collection process. Can be used in combination with filter. Matches the [filter format](https://backstage.io/docs/reference/catalog-client.entityfilterquery) used by the Catalog API.

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
filter:
  - kind: component
exclude:
  - spec.type: documentation
```

#### `cache` \[optional]

If the collected facts should be cached, and if so for how long. Possible values are either `true` or `false` or a nested `{ duration:` [HumanDuration](https://backstage.io/docs/reference/types.humanduration) `}` field.
This is the default cache config for each fact type.
Example:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
cache:
  duration:
    hours: 24
```

#### `google` \[optional]

This is used for GKE authentication. By default that auth strategy uses the application default credentials. However, you can pass in a [JSON key](https://cloud.google.com/iam/docs/keys-create-delete) to use instead.

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
google:
  jsonKey: ${GOOGLE_JSON_KEY}
```

#### `collects` \[required]

An array describing which facts to collect and how to collect them. See below for details about the configuration of fact collection for each fact type.

* #### `type` \[required]

  The type of the collector. The following types are available:

  ```
  k8s_services
  k8s_pods
  k8s_deployments
  k8s_hpas
  k8s_stateful_sets
  k8s_pod_disruption_budgets
  k8s_ingresses
  ```

* #### `frequency` \[optional]

  The frequency at which the fact collection should be executed. Possible values are either a cron expression `{ cron: ... }` or [HumanDuration](https://backstage.io/docs/reference/types.humanduration).
  If provided, it overrides the default frequency provided at the top level. If not provided, it defaults to the frequency provided at the top level. If neither collector's frequency, nor default frequency is provided, the fact will only be collected on demand.

* #### `initialDelay` \[optional]

  The amount of time that should pass before the first invocation happens. Possible values are either a cron expression `{ cron: ... }` or [HumanDuration](https://backstage.io/docs/reference/types.humanduration).
  If provided, it overrides the default initial delay provided at the top level. If not provided, it defaults to the initial delay provided at the top level. If neither collector's initial delay, nor default initial delay is provided, the fact will be collected with no initial delay.

* #### `batchSize` \[optional]

  The number of entities to collect facts for at once. Optional, the default value is 1.
  If provided it overrides the default batchSize provided at the top level. If not provided it defaults to the batchSize provided at the top level. If neither collector's batchSize nor default batchSize is provided the fact will be collected for one entity at a time.

  **Note**: Fact collection for a batch of entities is still considered as one hit towards the rate limits
  by the Soundcheck [Rate Limiting](#rate-limiting-optional) engine, while the actual number of hits
  will be equal to the `batchSize`.

  Example:

  ```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
  batchSize: 100
  ```

* #### `filter` \[optional]

  A filter specifying which entities to collect the specified facts for. Matches the [filter format](https://backstage.io/docs/reference/catalog-client.entityfilterquery) used by the Catalog API.
  If provided, it overrides the default filter provided at the top level. If not provided, it defaults to the filter provided at the top level. If neither collector's filter, nor default filter is provided, the fact will be collected for all entities.

* #### `exclude` \[optional]

  Entities matching this filter will be skipped during the fact collection process. Can be used in combination with filter. Matches the [filter format](https://backstage.io/docs/reference/catalog-client.entityfilterquery) used by the Catalog API.

  ```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
  filter:
    - kind: component
  exclude:
    - spec.type: documentation
  ```

* #### `cache` \[optional]

  If the collected facts should be cached, and if so for how long. Possible values are either `true` or `false` or a nested `{ duration:` [HumanDuration](https://backstage.io/docs/reference/types.humanduration) `}` field.
  If provided, it overrides the default cache config provided at the top level. If not provided, it defaults to the cache config provided at the top level. If neither collector's cache nor default cache config is provided, the fact will not be cached.

### Custom Resources

Custom resources for kubernetes are supported. Each custom resource need to be defined with a unique fact name.

The `customResouce` property needs to be defined and is similar to the kubernetes plugin's [customResources](https://backstage.io/docs/features/kubernetes/configuration#customresources-optional).

Example:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
soundcheck:
  collectors:
    kubernetes:
      frequency:
        cron: '* 0 * * *'
      collects:
        - type: k8s_custom_resource
          factName: k8s_crontabs
          customResource:
            group: customresources
            apiVersion: v1
            plural: crontabs
        - type: k8s_custom_resource
          factName: k8s_buildtools
          customResource:
            group: customresources
            apiVersion: v1
            plural: buildtools
```

If a custom resource api is not present on a cluster, the fact will return a `resourceMissing` property.

Example:

```JSON theme={"theme":{"light":"github-light","dark":"dracula"}}
{
  "clusters": ["cluster-1"],
  "items": [
    {
      "clusterName": "cluster-1",
      "resourceMissing": true
    }
  ]
}
```

## Collecting Facts

All kubernetes fact collections fetch data from the [kubernetes api](https://kubernetes.io/docs/reference/kubernetes-api/).

### Schema

The general type of each fact type is as follows:

```typescript theme={"theme":{"light":"github-light","dark":"dracula"}}
{
  clusters: string[];
  labelSelector: string;
  items: {
    spec: ObjectSpec;
    metadata: V1ObjectMeta;
    clusterName: string;
  }[];
}
```

JSON Schemas are available in the dist package.

#### `clusters`

A list of cluster names where the items were retrieved from.

#### `labelSelector`

The label selector used to query the clusters.

#### `items`

A list of retrieved items. If there are items from multiple clusters, that are combined into this `items` list.

* #### `spec`

  The spec contains data specific to the fact type. See the following table:

  | Fact Type                     | Spec                                                                                                                                                              |
  | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | k8s\_services                 | [V1ServiceSpec](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/#ServiceSpec)                                                    |
  | k8s\_pods                     | [V1PodSpec](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodSpec)                                                               |
  | k8s\_deployments              | [V1DeploymentSpec](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/deployment-v1/#DeploymentSpec)                                          |
  | k8s\_hpas                     | [V2HorizontalPodAutoscalerSpec](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/horizontal-pod-autoscaler-v2/#HorizontalPodAutoscalerSpec) |
  | k8s\_stateful\_sets           | [V1StatefulSetSpec](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/stateful-set-v1/#StatefulSetSpec)                                      |
  | k8s\_pod\_disruption\_budgets | [V1PodDisruptionBudgetSpec](https://kubernetes.io/docs/reference/kubernetes-api/policy-resources/pod-disruption-budget-v1/#PodDisruptionBudgetSpec)               |
  | k8s\_ingresses                | [V1IngressSpec](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/ingress-v1/#IngressSpec)                                                    |

* #### `metadata`

  This is the common kubernetes [ObjectMetadata](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/object-meta/#ObjectMeta) object.

* #### `clusterName`

  The cluster this item comes from.

#### Example Fact

Example for `k8s_deployments` in JSON:

```JSON theme={"theme":{"light":"github-light","dark":"dracula"}}
{
  "factRef": {
      "source": "kubernetes",
      "scope": "default",
      "name": "k8s_deployments"
  },
  "entityRef": "component:default/soundcheck-test-service",
  "data": {
      "clusters": [
          "gke-test-cluster"
      ],
      "labelSelector": "app=soundcheck-test-service",
      "items": [
          {
              "spec": {
                  "replicas": 1,
                  "selector": {
                      "matchLabels": {
                          "app": "soundcheck-test-service"
                      }
                  },
                  "template": {
                      "metadata": {
                          "creationTimestamp": null,
                          "labels": {
                              "app": "soundcheck-test-service"
                          }
                      },
                      "spec": {
                          "containers": [
                              {
                                  "name": "echo-server",
                                  "image": "kicbase/echo-server:1.0",
                                  "resources": {
                                      "limits": {
                                          "cpu": "500m",
                                          "ephemeral-storage": "1Gi",
                                          "memory": "2Gi"
                                      },
                                      "requests": {
                                          "cpu": "500m",
                                          "ephemeral-storage": "1Gi",
                                          "memory": "2Gi"
                                      }
                                  },
                                  "terminationMessagePath": "/dev/termination-log",
                                  "terminationMessagePolicy": "File",
                                  "imagePullPolicy": "IfNotPresent",
                                  "securityContext": {
                                      "capabilities": {
                                          "drop": [
                                              "NET_RAW"
                                          ]
                                      }
                                  }
                              }
                          ],
                          "restartPolicy": "Always",
                          "terminationGracePeriodSeconds": 30,
                          "dnsPolicy": "ClusterFirst",
                          "securityContext": {
                              "seccompProfile": {
                                  "type": "RuntimeDefault"
                              }
                          },
                          "schedulerName": "default-scheduler",
                          "tolerations": [
                              {
                                  "key": "kubernetes.io/arch",
                                  "operator": "Equal",
                                  "value": "amd64",
                                  "effect": "NoSchedule"
                              }
                          ]
                      }
                  },
                  "strategy": {
                      "type": "RollingUpdate",
                      "rollingUpdate": {
                          "maxUnavailable": "25%",
                          "maxSurge": "25%"
                      }
                  },
                  "revisionHistoryLimit": 10,
                  "progressDeadlineSeconds": 600
              },
              "metadata": {
                  "name": "soundcheck-test-service",
                  "namespace": "default",
                  "uid": "327ee942-db74-4723-8d24-d812676edeaf",
                  "resourceVersion": "15896657",
                  "generation": 1,
                  "creationTimestamp": "2024-06-04T15:12:02Z",
                  "labels": {
                      "app": "soundcheck-test-service"
                  },
                  "annotations": {
                      "autopilot.gke.io/resource-adjustment": "{\"input\":{\"containers\":[{\"name\":\"echo-server\"}]},\"output\":{\"containers\":[{\"limits\":{\"cpu\":\"500m\",\"ephemeral-storage\":\"1Gi\",\"memory\":\"2Gi\"},\"requests\":{\"cpu\":\"500m\",\"ephemeral-storage\":\"1Gi\",\"memory\":\"2Gi\"},\"name\":\"echo-server\"}]},\"modified\":true}",
                      "autopilot.gke.io/warden-version": "2.8.83",
                      "deployment.kubernetes.io/revision": "1"
                  },
                  "managedFields": [
                      {
                          "manager": "kubectl-create",
                          "operation": "Update",
                          "apiVersion": "apps/v1",
                          "time": "2024-06-04T15:12:02Z",
                          "fieldsType": "FieldsV1",
                          "fieldsV1": {
                              "f:metadata": {
                                  "f:labels": {
                                      ".": {},
                                      "f:app": {}
                                  }
                              },
                              "f:spec": {
                                  "f:progressDeadlineSeconds": {},
                                  "f:replicas": {},
                                  "f:revisionHistoryLimit": {},
                                  "f:selector": {},
                                  "f:strategy": {
                                      "f:rollingUpdate": {
                                          ".": {},
                                          "f:maxSurge": {},
                                          "f:maxUnavailable": {}
                                      },
                                      "f:type": {}
                                  },
                                  "f:template": {
                                      "f:metadata": {
                                          "f:labels": {
                                              ".": {},
                                              "f:app": {}
                                          }
                                      },
                                      "f:spec": {
                                          "f:containers": {
                                              "k:{\"name\":\"echo-server\"}": {
                                                  ".": {},
                                                  "f:image": {},
                                                  "f:imagePullPolicy": {},
                                                  "f:name": {},
                                                  "f:resources": {},
                                                  "f:terminationMessagePath": {},
                                                  "f:terminationMessagePolicy": {}
                                              }
                                          },
                                          "f:dnsPolicy": {},
                                          "f:restartPolicy": {},
                                          "f:schedulerName": {},
                                          "f:securityContext": {},
                                          "f:terminationGracePeriodSeconds": {}
                                      }
                                  }
                              }
                          }
                      },
                      {
                          "manager": "kube-controller-manager",
                          "operation": "Update",
                          "apiVersion": "apps/v1",
                          "time": "2024-06-18T17:58:40Z",
                          "fieldsType": "FieldsV1",
                          "fieldsV1": {
                              "f:metadata": {
                                  "f:annotations": {
                                      "f:deployment.kubernetes.io/revision": {}
                                  }
                              },
                              "f:status": {
                                  "f:availableReplicas": {},
                                  "f:conditions": {
                                      ".": {},
                                      "k:{\"type\":\"Available\"}": {
                                          ".": {},
                                          "f:lastTransitionTime": {},
                                          "f:lastUpdateTime": {},
                                          "f:message": {},
                                          "f:reason": {},
                                          "f:status": {},
                                          "f:type": {}
                                      },
                                      "k:{\"type\":\"Progressing\"}": {
                                          ".": {},
                                          "f:lastTransitionTime": {},
                                          "f:lastUpdateTime": {},
                                          "f:message": {},
                                          "f:reason": {},
                                          "f:status": {},
                                          "f:type": {}
                                      }
                                  },
                                  "f:observedGeneration": {},
                                  "f:readyReplicas": {},
                                  "f:replicas": {},
                                  "f:updatedReplicas": {}
                              }
                          },
                          "subresource": "status"
                      }
                  ]
              },
              "clusterName": "gke-test-cluster"
          }
      ]
  },
  "timestamp": "2024-06-21T15:04:15.214Z"
}
```
