kadet-hub logokadet-hub

Blackbox exporter on Kubernetes without Helm, with Kapitan

The Prometheus blackbox exporter 0.29.1 with the module http_2xx, rendered by the kadet-hub kubernetes generator 1.14.0 from the prometheus-community Helm chart prometheus-blackbox-exporter 11.20.2 with its default values and the pod’s seccomp profile RuntimeDefault.

What it deploys

Required parameters

No parameter has to be set.

Include

A target includes the recipe and its options as classes and can override anything the recipe sets:

classes:
  - recipes.blackbox-exporter
parameters:
  namespace: blackbox-exporter
  kapitan:
    vars:
      target: blackbox-exporter

Fetching it

The quickstart goes through these steps on a kind cluster with the uptime-kuma recipe, from installing Kapitan to the running app.

A separate fetch inventory pins the recipe by version and digest. This is fetch/targets/recipes.yml for version 1.0.1:

parameters:
  kapitan:
    dependencies:
      - type: oci
        source: ghcr.io/kadet-hub/recipes/blackbox-exporter:1.0.1@sha256:46692ba7208a46a1c780f098c1c176c2eee6630988c3f07c2b2920a81a051bb4
        output_path: inventory/classes/recipes/blackbox-exporter

The first command fetches the recipe into inventory/classes/recipes/blackbox-exporter, the second the generators and compiles:

kapitan compile --inventory-path fetch --fetch --output-path .
kapitan compile --fetch

The first command exits with status 1 because the fetch target compiles nothing. Kapitan's --fetch checks neither the digest nor the attestation. This verifies the attestation of the recipe:

gh attestation verify \
  oci://ghcr.io/kadet-hub/recipes/blackbox-exporter@sha256:46692ba7208a46a1c780f098c1c176c2eee6630988c3f07c2b2920a81a051bb4 \
  --owner kadet-hub \
  --cert-identity https://github.com/kadet-hub/registry/.github/workflows/release.yml@refs/heads/main

The attested index must also list each digest under its recipe with the pinned version, and not as yanked. Verifying by hand shows how to read it.

Settings

<c> stands for components.blackbox-exporter-prometheus-blackbox-exporter.

Chart value Inventory
config <c>.config_maps.config.data["blackbox.yaml"].value, the whole file as text
image.tag <c>.image, tag and digest
replicas <c>.replicas
extraArgs <c>.args.<key>, such as log-level: --log.level=debug
resources <c>.resources
service.type <c>.service.type
podAnnotations <c>.pod_annotations
nodeSelector, tolerations, affinity <c>.node_selector, <c>.tolerations, <c>.affinity
podSecurityContext <c>.workload_security_context
securityContext <c>.security_context

The pod annotation checksum/config is the chart’s hash of its ConfigMap for the default config. It does not change with the recipe’s blackbox.yaml, so after changing it restart the exporter with kubectl rollout restart deployment/blackbox-exporter-prometheus-blackbox-exporter. The module configuration is the chart’s, with its license in blackbox-exporter.yml.LICENSE.

The chart’s ServiceMonitor, PodMonitoring, PrometheusRule, Ingress, route, NetworkPolicy, PodDisruptionBudget and config reloader are off by default and not part of the recipe. A ServiceMonitor needs the CRDs of the Prometheus Operator, which check does not install.

Any list set in the target is appended to the recipe’s list. To replace one, set the key to ~ in a class included after the recipe and the new list in the target.

Proof

check blackbox-exporter --level deploys with tests/values.yaml and tests/target.yml, on kind for each Kubernetes minor CI tests. tests/values.yaml sets the chart’s podSecurityContext to the seccomp profile RuntimeDefault, which the chart leaves unset and Pod Security restricted requires. blackbox-exporter 1.0.0 had no seccomp profile, so a namespace that enforces restricted rejected its pod. The four objects differ in three ways. The Deployment and the Service select on name, the chart on app.kubernetes.io/name and instance, and both select the same pods. The container is named after the component, the chart’s blackbox-exporter. The ServiceAccount sets automountServiceAccountToken: true, the API default the chart leaves unset, while the pod opts out as in the chart. The chart binds no role.

tests/smoke calls /probe with the module http_2xx through the Service and the API server’s service proxy. The target is CoreDNS’s metrics endpoint on the Service kube-dns in kube-system: /metrics gives probe_success 1, and a path CoreDNS does not serve gives probe_success 0. A server-side dry run of the label pod-security.kubernetes.io/enforce=restricted on the namespace must return no warning about the running pod.

Versions

The recipe's files are in kadet-hub/recipes. All recipes