home-operations
gatus-sidecar
Go

Generate Gatus endpoint configs from Kubernetes HTTPRoute, Ingress, and Service resources

Last updated Jul 9, 2026
77
Stars
11
Forks
2
Issues
+1
Stars/day
Attention Score
58
Language breakdown
Go 51.3%
YAML 19.0%
JSON 17.3%
Go Template 10.2%
TOML 1.9%
Dockerfile 0.2%
โ–ธ Files click to expand
README

gatus-sidecar

A Kubernetes sidecar for Gatus โ€” turns Ingress, Service, Gateway API HTTPRoute, and Traefik IngressRoute resources into Gatus endpoint configuration, automatically.

CI E2E Lint Release License


Why

Maintaining a Gatus config by hand stops scaling once you have more than a handful of services. This sidecar watches the cluster, derives an endpoint per resource, and writes a YAML file Gatus hot-reloads โ€” no restarts, no template hell, no drift.

  • ๐Ÿชถ Single binary, scratch image โ€” minimal footprint, no runtime deps.
  • ๐Ÿ”„ Hot reload โ€” atomic file writes; Gatus picks up changes automatically.
  • ๐ŸŽฏ Auto or opt-in โ€” discover every resource, or only ones annotated explicitly.
  • ๐Ÿงฌ Annotation inheritance โ€” Gateway โ†’ HTTPRoute, IngressClass โ†’ Ingress.
  • ๐Ÿ›ฃ๏ธ Path-aware URLs โ€” extracts paths from Ingress rules and HTTPRoute matches.
  • ๐Ÿท๏ธ Per-kind name prefixes โ€” keep an Ingress and a Service with the same name from colliding.

Resource support

| Resource | Group / Version | Parent (annotation inheritance) | URL shape | | ---------------- | ------------------------------ | ------------------------------- | ----------------------------------------- | | Ingress | networking.k8s.io/v1 | IngressClass | http(s)://<host><path> | | Service | v1 | โ€” | <proto>://<name>.<namespace>.svc:<port> | | HTTPRoute | gateway.networking.k8s.io/v1 | Gateway | https://<host><path> | | IngressRoute | traefik.io/v1alpha1 | โ€” | http(s)://<host><path> |

Quick start

docker pull ghcr.io/home-operations/gatus-sidecar:latest

Minimum-viable local run against your current kubeconfig:

gatus-sidecar \
  --auto-ingress \
  --auto-service \
  --output=./gatus-sidecar.yaml

โ€ฆthen point Gatus at the generated file.

Deployment

Run alongside Gatus, sharing a config volume. The sidecar writes /config/gatus-sidecar.yaml; configure Gatus to include it as a watched sub-config.

apiVersion: apps/v1
kind: Deployment
metadata:
    name: gatus
spec:
    template:
        spec:
            serviceAccountName: gatus-sidecar
            containers:
                - name: gatus
                  image: ghcr.io/twin/gatus:latest
                  volumeMounts:
                      - { name: gatus-config, mountPath: /config }
                - name: gatus-sidecar
                  image: ghcr.io/home-operations/gatus-sidecar:latest
                  args:
                      - --auto-ingress
                      - --auto-service
                      - --auto-httproute
                      - --gateway-name=production
                  volumeMounts:
                      - { name: gatus-config, mountPath: /config }
            volumes:
                - { name: gatus-config, emptyDir: {} }

Minimum RBAC for the controllers you enable:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata: { name: gatus-sidecar }
rules:
    - apiGroups: [""]
      resources: ["services"]
      verbs: ["get", "list", "watch"]
    - apiGroups: ["networking.k8s.io"]
      resources: ["ingresses", "ingressclasses"]
      verbs: ["get", "list", "watch"]
    - apiGroups: ["gateway.networking.k8s.io"]
      resources: ["httproutes", "gateways"]
      verbs: ["get", "list", "watch"]
    - apiGroups: ["traefik.io"]
      resources: ["ingressroutes"]
      verbs: ["get", "list", "watch"]

Configuration

Flag reference

Discovery modes

One per resource type. With no --enable-/--auto- flag set, every kind runs in annotation-only mode (resources must opt in).

| Flag | Effect | | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | --auto-ingress | Emit an endpoint for every in-scope Ingress. | | --auto-service | Emit an endpoint for every in-scope Service. | | --auto-httproute | Emit an endpoint for every in-scope HTTPRoute. | | --auto-ingressroute | Emit an endpoint for every Traefik IngressRoute. | | --enable-ingress --enable-service --enable-httproute --enable-ingressroute | Watch the kind, but only emit for resources annotated gatus.home-operations.com/enabled: "true". |

Filtering

| Flag | Repeatable? | Effect | | ----------------- | ----------- | ------------------------------------------------------------- | | --namespace | no | Watch a single namespace (empty = all). | | --ingress-class | yes | Only Ingresses whose class is in the set are emitted. | | --gateway-name | yes | Only HTTPRoutes referencing a Gateway in the set are emitted. |

Repeatable flags can be passed multiple times: --ingress-class=nginx --ingress-class=traefik matches either.

Naming

Use these to disambiguate endpoints across resource kinds โ€” Gatus rejects duplicate names, so prefix per-kind whenever an Ingress and a Service might share a name.

| Flag | Prepended to endpoint name | | ----------------------- | -------------------------- | | --prefix-ingress | Ingress endpoints | | --prefix-service | Service endpoints | | --prefix-httproute | HTTPRoute endpoints | | --prefix-ingressroute | IngressRoute endpoints |

Output & runtime

| Flag | Default | Description | | ---------------------- | ------------------------------------ | ---------------------------------------------------- | | --output | /config/gatus-sidecar.yaml | Destination YAML file (written atomically). | | --default-interval | 1m | Probe interval when not overridden by an annotation. | | --annotation-config | gatus.home-operations.com/endpoint | Annotation key for YAML template overrides. | | --annotation-enabled | gatus.home-operations.com/enabled | Annotation key for the on/off gate. | | --log-level | info | debug \| info \| warn \| error. |

Annotations

| Annotation | Value | Effect | | ------------------------------------ | ---------------- | ----------------------------------------------------------------------------------- | | gatus.home-operations.com/enabled | "true" / "1" | Force-include this resource in annotation-only mode, or keep it in --auto-* mode. | | gatus.home-operations.com/enabled | anything else | Exclude this resource even when --auto-* is set. | | gatus.home-operations.com/endpoint | YAML fragment | Merged into the generated endpoint (see below). |

Template merging

The endpoint annotation accepts any subset of a Gatus endpoint. Known keys are merged into typed fields; unknown keys are inlined verbatim โ€” so alerts:, headers:, body:, etc., all work out of the box.

| Template key | Behavior | | ---------------------------------- | --------------------------------------------------------------- | | name, group, url, interval | Override the field. | | conditions | Replace the default conditions. Accepts string or list. | | dns, client, ui | Deep-merged into the field's map. | | guarded | If present, switches the endpoint to a DNS probe. | | path | Replace the auto-extracted path. Empty string forces bare host. | | anything else | Inlined into the YAML output as-is. |

For resources with a parent (HTTPRoute โ†’ Gateway, Ingress โ†’ IngressClass) the parent's annotation is merged first; the child wins on conflicts for scalars, deep-merges for nested maps. Use the parent for common alerting and the child for per-route conditions.

URL derivation

| Resource | Host | Scheme | Path | | ---------------- | ---------------------------------------- | ------------------------------------------------------ | -------------------------------------------------------------- | | Ingress | First rule with host | https if TLS covers that host, else http | First non-/ path under the first rule's HTTP block | | HTTPRoute | spec.hostnames[0] | https (always) | First Exact/PathPrefix match value (regex matches skipped) | | Service | <name>.<namespace>.svc | First port's protocol, lowercased (tcp://, udp://) | โ€” | | IngressRoute | First Host(\...\)in a route'smatch | https if spec.tls is set, else http | First Path(\...\)/PathPrefix(\...\)in the samematch |

Trivial paths (empty, /, non-rooted) are dropped so the URL stays bare.
>
If the host already starts with http:// or https:// the scheme is preserved verbatim (useful for explicit override).

To opt out of path extraction:

  • path: "" in the endpoint annotation forces a bare-host probe; path: /custom picks a specific path while keeping the auto-detected host.
  • --probe-paths=false strips paths cluster-wide; per-resource path: still applies.
  • A full url: annotation overrides both.

Guarded probes

Set guarded: true in a template to replace the HTTP probe with a DNS query against 1.1.1.1 for the resource's hostname. Useful when the sidecar pod can't actually reach the service (split-horizon DNS, external-only ingress) but you still want to know DNS is resolving.

metadata:
    annotations:
        gatus.home-operations.com/endpoint: |
            guarded: true

Examples

Inherit alerts from a Gateway, override per route

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
    name: prod
    annotations:
        gatus.home-operations.com/endpoint: |
            alerts:
              - type: slack
                webhook-url: https://hooks.slack.com/...

apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: api annotations: gatus.home-operations.com/endpoint: | interval: 30s conditions: - "[STATUS] == 200" - "[RESPONSE_TIME] < 500" spec: parentRefs: [{ name: prod }] hostnames: ["api.example.com"] rules: - matches: [{ path: { type: PathPrefix, value: "/v1" } }]

Generated endpoint URL: https://api.example.com/v1 โ€” inherits the Gateway's alerts, uses the route's own interval/conditions.

Disambiguate same-named resources

gatus-sidecar --auto-ingress --auto-service \
  --prefix-ingress=ing/ --prefix-service=svc/

An Ingress and a Service both named web-app produce ing/web-app and svc/web-app instead of a Gatus startup error.

Watch multiple gateway classes at once

gatus-sidecar --auto-httproute \
  --gateway-name=public --gateway-name=internal

Development

go build -o gatus-sidecar ./cmd/gatus-sidecar
go test ./...                              # unit tests
mise run lint                              # golangci-lint
go test -tags e2e ./test/e2e/...           # Kind-based E2E (needs KUBECONFIG)

The project pins tool versions via mise. Running mise install resolves Go, golangci-lint, lefthook, yamlfmt, and zizmor.

Architecture

cmd/gatus-sidecar/       Entry point
internal/config/         CLI flag parsing & validation
internal/gatus/          Endpoint type, template merge, atomic YAML writer
internal/k8s/            Dynamic-informer controller, Resource interface
internal/resources/      Ingress / Service / HTTPRoute / IngressRoute
test/e2e/                Kind-driven end-to-end suite (build tag: e2e)

One Controller runs per enabled resource kind. Each uses a dynamicinformer to watch its GVR and feeds a shared gatus.Writer with the merged endpoint set; the writer renders YAML to disk via tempfile + rename, so Gatus never reads a partial file.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚  Kubernetes API  โ”‚ โ”€โ”€โ”€โ”€ informers/watches โ”€โ”€โ–ถโ”‚  gatus-sidecar  โ”‚
   โ”‚                  โ”‚                           โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
   โ”‚  Ingress         โ”‚                           โ”‚  โ”‚ Controller โ”‚ โ”‚โ”€โ”€ reconcile โ”€โ”€โ”
   โ”‚  Service         โ”‚                           โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚               โ”‚
   โ”‚  HTTPRoute       โ”‚                           โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚               โ–ผ
   โ”‚  IngressRoute    โ”‚                           โ”‚  โ”‚  Writer    โ”‚ โ”€โ”€ atomic โ”€โ”€โ–ถ /config/gatus-sidecar.yaml
   โ”‚  IngressClass    โ”‚                           โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚               โ”‚
   โ”‚  Gateway         โ”‚                           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                                              โ–ผ
                                                                            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                                                            โ”‚    Gatus     โ”‚ โ—€โ”€โ”€ hot-reload
                                                                            โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

License

MIT โ€” see LICENSE.

๐Ÿ”— More in this category

ยฉ 2026 GitRepoTrend ยท home-operations/gatus-sidecar ยท Updated daily from GitHub