Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Caching Kubernetes? Introducing the Varnish Gat...

Caching Kubernetes? Introducing the Varnish Gateway Controller for Kubernetes

Slides for my SREDay Munich 2026 presentation about the Varnish Gateway Controller.

This Gateway Controller is a Gateway API implementation for Kubernetes that uses Varnish underneath. This allows requests to be cached inside the Varnish Gateway Controller without relying on service-specific caching implementations.

See https://feryn.eu/presentations/caching-kubernetes-introducing-the-varnish-gateway-controller-for-kubernetes-sreday-munich-2026 for more information.

Avatar for Thijs Feryn

Thijs Feryn PRO

May 21, 2026

More Decks by Thijs Feryn

Other Decks in Technology

Transcript

  1. vcl 4.1; backend default { .host = "127.0.0.1"; .port =

    "8080"; } sub vcl_recv { if(req.url ~ "^/admin(/.*|$)") { return(pass); } unset req.http.Cookie; }
  2. vcl 4.1; backend default { .host = "127.0.0.1"; .port =

    "8080"; } sub vcl_backend_response { if (beresp.http.Content-Type ~ "^image/") { set beresp.ttl = 1y; } else { set beresp.ttl = 1h; } }
  3. $ helm install varnish \ oci://docker.io/varnish/varnish-cache \ --set server.extraEnvs.VARNISH_BACKEND_HOST=example.default.svc.cluster.local \

    --set server.extraEnvs.VARNISH_BACKEND_PORT=80 Pulled: docker.io/varnish/varnish-cache:1.1.1 Digest: sha256:48c0f1beaa3f8ea26a618f842ae413233c48c748484bf0b5863ca439d26025d7 NAME: varnish LAST DEPLOYED: Mon May 18 13:40:43 2026 NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: __ __ _ _ \ \ / /_ _ _ __ _ __ (_)___| |__ \ \ / / _` | '__| '_ \| / __| '_ \ \ V / (_| | | | | | | \__ \ | | | \_/ \__,_|_| |_| |_|_|___/_| |_| varnish-cache.org
  4. ✓ ✓ Native TLS Dynamic backends Structured JSON logging OpenTelemetry

    support GeoIP Accept header cleanup Rate limiting & throttling Tag-based cached invalidation JSON parsing & JQ support LUA & ECMAScript support ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ HMAC, message digest & Base64 Local file server Redis interface Response body manipulation Request body capturing Query string manipulation Header manipulation String functions HTTP client g or h. is ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ rn va VARNISH 9
  5. Watches Gateway API resources Operator - Gateway - HTTPRoute -

    GatewayClass - GatewayClassParameters Creates/updates gateway, routing.json file & main.vcl to ConfigMap ROUTING IN MEMORY, NO VCL RECOMPILE Varnish pod Varnish + ghost module Logs varnishlog-json Reloads Watches Chaperone Watches EndpointSlices ConfigMaps - main.vcl - routing.json
  6. $ kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/ download/v1.5.0/standard-install.yaml $ helm install varnish-gateway

    oci://ghcr.io/varnish/charts/varnish-gateway \ --namespace varnish-gateway-system \ --create-namespace
  7. $ kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/ download/v1.5.0/standard-install.yaml $ helm install varnish-gateway

    oci://ghcr.io/varnish/charts/varnish-gateway \ --namespace varnish-gateway-system \ --create-namespace
  8. Watches Gateway API resources Operator - Gateway - HTTPRoute -

    GatewayClass - GatewayClassParameters CREATED BY HELM INSTALL, RUNS CLUSTER WIDE Varnish + ghost module Logs - varnishlog-json Varnish pod Reloads Watches Chaperone Watches EndpointSlices ConfigMaps - main.vcl - routing.json
  9. $ kubectl get all -n varnish-gateway-system NAME pod/varnish-gateway-operator-5b9c4c9dd-gfs7v READY 1/1

    NAME service/varnish-gateway-operator-metrics TYPE ClusterIP NAME deployment.apps/varnish-gateway-operator READY 1/1 NAME replicaset.apps/varnish-gateway-operator-5b9c4c9dd STATUS Running RESTARTS 0 CLUSTER-IP 10.43.121.125 UP-TO-DATE 1 DESIRED 1 EXTERNAL-IP <none> AVAILABLE 1 CURRENT 1 AGE 19m AGE 19m READY 1 AGE 19m PORT(S) 8080/TCP AGE 19m
  10. --apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: varnish-gateway namespace: default annotations:

    cert-manager.io/issuer: letsencrypt spec: gatewayClassName: varnish listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: All - name: https-todo port: 443 protocol: HTTPS hostname: "todo.demo.artifactcache.com" tls: mode: Terminate certificateRefs: - name: demo-artifactcache-com-tls allowedRoutes: namespaces: from: All
  11. $ kubectl apply -f varnish-gateway.yaml gateway.gateway.networking.k8s.io/varnish-gateway created $ kubectl get

    gateways NAME varnish-gateway CLASS varnish ADDRESS 172.31.44.22 PROGRAMMED True AGE 58m
  12. Watches Gateway API resources Operator - Gateway - HTTPRoute -

    GatewayClass - GatewayClassParameters Creates/updates routing.json file & main.vcl to ConfigMap Varnish pod Varnish + ghost module Logs varnishlog-json Reloads Watches Chaperone Watches EndpointSlices ConfigMaps - main.vcl - routing.json
  13. --apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: todo-http-route namespace: default spec:

    parentRefs: - name: varnish-gateway hostnames: - todo.demo.artifactcache.com rules: - backendRefs: - name: todo port: 80
  14. $ kubectl get svc --field-selector metadata.name=todo NAME todo TYPE NodePort

    CLUSTER-IP 10.43.78.51 EXTERNAL-IP <none> PORT(S) 80:31666/TCP $ kubectl apply -f todo-gateway-routes.yaml httproute.gateway.networking.k8s.io/todo-http-route created $ kubectl get httproutes NAME todo-http-route HOSTNAMES ["todo.demo.artifactcache.com"] AGE 12s AGE 49m
  15. --apiVersion: gateway.varnish-software.com/v1alpha1 kind: VarnishCachePolicy metadata: name: cache-todo namespace: default spec:

    targetRef: group: gateway.networking.k8s.io kind: HTTPRoute name: todo-http-route defaultTTL: 1h
  16. $ kubectl apply -f varnish-cache-policy-todo.yaml varnishcachepolicy.gateway.varnish-software.com/cache-todo created $ kubectl get

    varnishcachepolicy NAME cache-todo TARGET KIND HTTPRoute TARGET NAME todo-http-route AGE 28s
  17. apiVersion: gateway.varnish-software.com/v1alpha1 kind: VarnishCachePolicy metadata: name: my-cache-policy namespace: default spec:

    targetRef: group: gateway.networking.k8s.io kind: HTTPRoute # or Gateway name: my-route # sectionName: my-rule # optional: target a specific named rule defaultTTL: 5m # forcedTTL: 1h grace: 30s # serve stale while revalidating (default: 0) keep: 24h # serve stale when backend is down (default: 0) cacheKey: headers: - Accept-Language queryParameters: include: # allowlist (mutually exclusive with exclude) - page - filter # exclude: # denylist # - utm_source bypass: headers: - name: Authorization - name: Cookie valueRegex: "session_id|admin_token"
  18. sub vcl_recv { if(req.http.host == "todo.demo.artifactcache.com") { unset req.http.cookie; unset

    req.http.authorization; if(req.url ~ "^/[0-9a-f]{32}/?$" || (req.method != "GET" && req.method != "HEAD")) { return(pass); } return(hash); } } sub vcl_backend_response { set beresp.ttl = 1h; if(beresp.http.content-type ~ "^text/css") { set beresp.ttl = 1y; } } sub vcl_deliver { if(req.http.host == "todo.demo.artifactcache.com") { if(req.url ~ "^/[0-9a-f]{32}/?$" && resp.status == 404) { set resp.status = 302; set resp.reason = "Found"; set resp.http.Location = "https://todo.demo.artifactcache.com/"; return(deliver); } } }
  19. $ kubectl create configmap user-vcl \ -n varnish-gateway-system \ --from-file=../conf/user.vcl

    gatewayClass: defaultParams: userVCL: enabled: true configMap: name: user-vcl key: user.vcl VARNISH GATEWAY VALUES.YAML - - $ helm install -f ../conf/varnish-gateway-values.yaml varnish-gateway \ oci://ghcr.io/varnish/charts/varnish-gateway \ --namespace varnish-gateway-system \ --create-namespace