Skip to main content
Version: Preview

Kubernetes

Experimental
Creates:
AssetsLineageRun History

Configure in the UI

This plugin can be configured directly in the Marmot UI with a step-by-step wizard.

View Guide

The Kubernetes plugin discovers namespaces, services, deployments, stateful sets, cron jobs, and pods from Kubernetes clusters. Each resource kind can be toggled on or off, and discovery can be scoped to specific namespaces or a label selector.

Discovered resources are linked together: namespaces contain their resources, services link to the deployments and stateful sets they expose (matched by selector), and workloads link to their pods (matched by owner references). Cron jobs come with run history built from their recent job runs, so the catalog shows whether the nightly pipeline actually succeeded. When cluster_name is set, a Cluster asset is created as the root of the tree.

Pods are not discovered by default because they are short-lived and can flood the catalog; enable discover_pods when pod-level visibility is worth the churn. One-off Jobs are never cataloged for the same reason; only jobs owned by a cron job are used, as run history.

Prerequisites

The plugin needs read access to the resources it discovers. When running inside a cluster, bind a role like this to the service account Marmot runs as:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: marmot-discovery
rules:
- apiGroups: [""]
resources: ["namespaces", "services", "pods"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "replicasets"]
verbs: ["get", "list"]
- apiGroups: ["batch"]
resources: ["cronjobs", "jobs"]
verbs: ["get", "list"]
Managed clusters

This plugin is for self-managed and on-prem clusters. For managed clusters that authenticate with cloud IAM, use the dedicated plugins, which reuse this plugin's discovery engine:

Authentication

The plugin supports three authentication methods:

  • In-cluster: when Marmot runs inside Kubernetes and no connection settings are provided, the pod's service account is used automatically. The projected token is rotated automatically, so there is nothing to refresh.
  • Kubeconfig: $KUBECONFIG or ~/.kube/config is used when Marmot runs somewhere kubectl already works. Set kubeconfig_path and context to pick a specific file and context.
  • Direct token: set host, token, and ca_certificate to connect to any cluster with a service account token.

Connecting with a service account token

Create a service account bound to the read-only role above and mint a token for it:

kubectl create serviceaccount marmot-discovery
kubectl create clusterrolebinding marmot-discovery \
--clusterrole=marmot-discovery --serviceaccount=default:marmot-discovery
kubectl create token marmot-discovery --duration=48h
Tokens expire

kubectl create token mints a time-bounded token, and the API server caps the lifetime (often 48h) regardless of the --duration you request, so a scheduled ingest will start failing once it expires. For unattended discovery, prefer in-cluster auth (its token is rotated automatically), or rotate the token on a schedule. A long-lived token can be created with a kubernetes.io/service-account-token Secret, but that is discouraged upstream and disabled on some clusters.

Then give the plugin the cluster endpoint, the token, and the cluster's CA certificate. The connection fields go in the same config as the discovery options, not a separate file:

host: "https://mycluster.example.com:6443"
token: "${K8S_SA_TOKEN}"
ca_certificate: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
cluster_name: "prod"
namespaces:
- "payments"
- "orders"
discover_pods: false
tags:
- "kubernetes"
- "${labels.team}"

Example Configuration

When Marmot runs inside the cluster or has a working kubeconfig, no connection fields are needed; leave out host/token and the plugin uses the in-cluster service account or your kubeconfig. This example lists every discovery option with its default:


cluster_name: "prod"
namespaces:
- "payments"
- "orders"
discover_namespaces: true
discover_services: true
discover_deployments: true
discover_statefulsets: true
discover_cronjobs: true
discover_pods: false
labels_to_metadata: true
annotations_to_metadata: false
tags:
- "kubernetes"
- "${labels.team}"

Set namespaces to ["*"] (or leave it empty) to discover all namespaces except the ones in exclude_namespaces. Tags interpolate resource labels, so ${labels.team} tags every asset with the value of its team label. Set cluster_name when cataloging more than one cluster; it prefixes asset names (prod/payments/api) so the same namespace in two clusters stays distinct, and it creates a Cluster asset that anchors the lineage tree.

Configuration

The following configuration options are available:

PropertyTypeRequiredDescription
annotations_to_metadataboolfalseInclude resource annotations in asset metadata
ca_certificatestringfalsePEM-encoded CA certificate of the API server
cluster_namestringfalseCluster name to prefix asset names with
contextstringfalseKubeconfig context. Defaults to the current context
hoststringfalseAPI server URL for direct token authentication
discover_cronjobsboolfalseDiscover cron jobs, with their recent job runs as run history
discover_deploymentsboolfalseDiscover deployments
discover_namespacesboolfalseDiscover namespaces
discover_podsboolfalseDiscover pods. Off by default because pods are short-lived and can flood the catalog
discover_servicesboolfalseDiscover services
discover_statefulsetsboolfalseDiscover stateful sets
exclude_namespaces[]stringfalseNamespaces to skip when discovering all namespaces
external_links[]ExternalLinkfalseExternal links to show on all assets
filterFilterfalseFilter discovered assets by name (regex)
kubeconfig_pathstringfalseKubeconfig path. Defaults to in-cluster, then $KUBECONFIG
label_selectorstringfalseOnly discover namespaced resources matching this label selector (e.g. team=data)
labels_to_metadataboolfalseInclude resource labels in asset metadata
namespaces[]stringfalseNamespaces to discover. Empty or ["*"] means all namespaces
tagsTagsConfigfalseTags to apply to discovered assets
tokenstringfalseBearer token, typically a service account token

Available Metadata

The following metadata fields are available:

FieldTypeDescription
annotationsmap[string]stringResource annotations
available_replicasint32Number of available replicas
clusterstringConfigured cluster name
cluster_ipstringCluster IP address (None for headless services)
concurrency_policystringCron job concurrency policy (Allow, Forbid, Replace)
container_countintNumber of containers in the pod template
created_atstringResource creation timestamp
external_namestringExternal DNS name for ExternalName services
headless_servicestringHeadless service governing the stateful set
imagesstringContainer images (comma-separated)
kubernetes_versionstringKubernetes server version
labelsmap[string]stringResource labels
last_schedule_timestringWhen the cron job last fired
last_successful_timestringWhen the cron job last completed successfully
load_balancer_hostsstringLoad balancer ingress hostnames and IPs
namespacestringNamespace name
nodestringNode the pod is scheduled on
owner_kindstringKind of the controlling owner (ReplicaSet, StatefulSet, DaemonSet, Job)
owner_namestringName of the controlling owner
pausedboolWhether rollouts are paused
phasestringLifecycle phase (Active, Running, Pending, Failed)
platformstringServer platform (e.g. linux/amd64)
portsstringExposed ports (name:port/protocol, comma-separated)
qos_classstringQuality of service class (Guaranteed, Burstable, BestEffort)
ready_replicasint32Number of ready replicas
replicasint32Desired replica count
restart_countint32Total container restarts
schedulestringCron schedule expression
selectorstringPod selector labels (key=value, comma-separated)
service_accountstringService account the resource runs as
service_typestringService type (ClusterIP, NodePort, LoadBalancer, ExternalName)
strategystringRollout/update strategy (RollingUpdate, Recreate, OnDelete)
suspendedboolWhether the cron job is suspended
timezonestringTime zone the cron schedule is evaluated in
updated_replicasint32Number of replicas updated to the latest pod template
volume_claimsstringVolume claim templates (name:size/storageClass, comma-separated)