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

Caching Kubernetes? Introducing the Varnish Gat...

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

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