Skip to content

Target Cookbook

Recipes for the most common spec.target shapes. Pick the row that matches your workload's wire protocol and edge style, then copy the YAML and adjust names / ports.

At a glance

Protocol ClusterIP (Service) Gateway (Envoy) Ingress (classic, legacy)
HTTP/1.1 #http1-clusterip #http1-gateway #http1-ingress
HTTP/2 #http2-clusterip #http2-gateway n/a
gRPC #grpc-clusterip #grpc-gateway n/a

Working copies of every Gateway-path recipe ship in config/e2e/ along with the target Deployments, Envoy Gateway resources, and a README that walks through install + run + teardown.

HTTP/1.1

ClusterIP

The default. spec.target.host is left unset; the controller resolves to <targetRef.name>.<namespace>.svc.cluster.local.

spec:
  target:
    mode: ServiceDefault
    port: 80
    networkPath: ClusterIP
    protocol: HTTP1

Gateway (Envoy)

Point host at the Envoy Gateway listener Service. The HTTPRoute attached to that listener handles the upstream lookup.

spec:
  target:
    mode: ServiceDefault
    port: 80
    networkPath: Gateway
    protocol: HTTP1
    host: envoy-<gateway-ns>-<gateway-name>-<hash>.envoy-gateway-system.svc.cluster.local

The Envoy Gateway controller names the listener Service envoy-<gw-ns>-<gw-name>-<hash> by default; look it up with:

kubectl -n envoy-gateway-system get svc -l gateway.envoyproxy.io/owning-gateway-name=<gw-name>

Classic Ingress

Legacy path. Prefer Gateway for new workloads; classic kubernetes/ingress-nginx is sunset.

spec:
  target:
    mode: ServiceDefault
    port: 80
    networkPath: Ingress
    protocol: HTTP1
    host: my-app.example.com   # the Ingress rule's host

HTTP/2

ClusterIP

Cleartext HTTP/2 (h2c). The loadgen dials http:// and switches into h2c prior-knowledge framing because protocol: HTTP2.

spec:
  target:
    mode: ServiceDefault
    port: 80
    networkPath: ClusterIP
    protocol: HTTP2

The backend must accept h2c. Servers that speak it include nginx (http2 on on a cleartext listener), Caddy (servers { protocols h1 h2c }), and Envoy upstreams with h2 framing. Go net/http servers (including traefik/whoami) only speak h2 over TLS; the repo's h2c fixture uses Caddy for exactly that reason (config/e2e/targets/h2c-echo.yaml).

Gateway (Envoy)

Same as the HTTP/1 Gateway recipe but with protocol: HTTP2. The upstream Service should mark appProtocol: kubernetes.io/h2c so Envoy keeps h2 framing end-to-end rather than downgrading to HTTP/1 upstream.

spec:
  target:
    mode: ServiceDefault
    port: 8080
    networkPath: Gateway
    protocol: HTTP2
    host: envoy-<gateway-ns>-<gateway-name>-<hash>.envoy-gateway-system.svc.cluster.local

gRPC

The loadgen drives the standard grpc.health.v1.Health/Check probe. The target must register the Health server. URL path is ignored by gRPC; the loadgen extracts host:port and discards the rest.

ClusterIP

spec:
  target:
    mode: ServiceDefault
    port: 50051
    networkPath: ClusterIP
    protocol: GRPC
    grpc:
      service: orders.v1.Orders   # optional, scopes the probe to a per-service entry

Gateway (Envoy)

Attach a GRPCRoute to the Gateway listener, then point the validation at the listener Service:

spec:
  target:
    mode: ServiceDefault
    port: 50051
    networkPath: Gateway
    protocol: GRPC
    host: envoy-<gateway-ns>-<gateway-name>-<hash>.envoy-gateway-system.svc.cluster.local
    grpc:
      service: orders.v1.Orders

Envoy's GRPCRoute keeps h2 framing end-to-end. The upstream Service should mark appProtocol: grpc to make that explicit.

TLS

All recipes above default to cleartext. Add TLS verification by setting https:// indirectly through the resolved scheme (currently only via mode: AutoDiscoverProbe reading the backend's readiness httpGet.scheme), or by trusting a private CA via a ConfigMap reference:

spec:
  target:
    # ...
    tls:
      caBundle:
        configMapRef:
          name: my-cluster-ca
          key: ca.crt

tls.insecureSkipVerify: true exists for dev clusters but is loud about masking TLS errors; do not enable it on production runs.

Workload kinds other than Deployment

spec.targetRef is a cross-version reference, and its apiVersion and kind are honoured. The workload is resolved through its scale subresource, the same one the HorizontalPodAutoscaler reads, so anything scalable can be a target:

spec:
  targetRef:
    apiVersion: apps/v1
    kind: StatefulSet
    name: cart-store

Deployment, StatefulSet and ReplicaSet work out of the box. Anything else needs two things:

  1. The kind must serve a scale subresource whose status.selector identifies its pods. Argo Rollouts and most scalable CRDs do.
  2. The manager and observer need RBAC for that resource and its scale subresource. The chart exposes an extension point:
rbac:
  extraRules:
    - apiGroups: [argoproj.io]
      resources: [rollouts, rollouts/scale]
      verbs: [get, list, watch]

If the kind cannot be resolved, the run fails immediately with a TargetUnsupported diagnostic naming it, rather than waiting out the readiness window.

AutoDiscoverProbe additionally needs the workload to carry a pod template at spec.template.spec.containers, which every built-in workload kind does.

CRDs the cookbook does not cover

  • Custom path matching for upstream-rewritten routes (mode: CustomPath + a non-/ customPath).
  • AutoDiscoverProbe mode that reads the target workload's readiness probe to pick port + path + scheme automatically.

See the Configuration reference for both.