Deploy with PloneHttpcache#

This guide shows you how to deploy the PloneHttpcache Varnish cache and attach it to an existing Plone instance.

PloneHttpcache deploys Varnish through the mittwald kube-httpcache Helm chart. The construct renders that chart at synth time, so the cache is part of your own manifests. For an operator-managed alternative, see Deploy with cloud-vinyl cache.

Prerequisites#

  • A running Plone deployment created with cdk8s-plone (see Quick start).

  • The helm CLI available wherever you run cdk8s synth.

  • A Kubernetes Secret holding the Varnish admin credentials, referenced through existingSecret.

  • amd64 worker nodes.

The construct renders the kube-httpcache Helm chart locally, so you do not pre-install a controller in the cluster. The pod nodeSelector is hard-coded to kubernetes.io/arch=amd64 (a kube-httpcache workaround), so PloneHttpcache pods only schedule on amd64 nodes. There is no nodeSelector option on this construct.

Create the admin credentials Secret before you deploy:

kubectl create secret generic varnish-admin \
  --namespace <namespace> \
  --from-literal=secret="$(head -c32 /dev/urandom | base64)"

Attach a basic PloneHttpcache#

Construct PloneHttpcache with a plone reference, the existingSecret, and a replicas count.

import { Plone, PloneHttpcache } from '@bluedynamics/cdk8s-plone';

const plone = new Plone(chart, 'plone', {
  backend: { image: 'plone/plone-backend:6.1.3' },
  frontend: { image: 'plone/plone-frontend:16.0.0' },
});

new PloneHttpcache(chart, 'cache', {
  plone: plone,
  existingSecret: 'varnish-admin',
  replicas: 2,
});

RBAC for the rendered controller is always enabled; there is nothing to configure.

Set resources#

Tune the CPU and memory requests and limits to match your workload.

new PloneHttpcache(chart, 'cache', {
  plone: plone,
  existingSecret: 'varnish-admin',
  requestCpu: '200m',
  limitCpu: '1',
  requestMemory: '256Mi',
  limitMemory: '1Gi',
});

The defaults are requestCpu: '100m', limitCpu: '500m', requestMemory: '100Mi', and limitMemory: '500Mi'.

Customize the VCL#

Provide an inline VCL through varnishVcl, which takes precedence over varnishVclFile.

new PloneHttpcache(chart, 'cache', {
  plone: plone,
  existingSecret: 'varnish-admin',
  varnishVcl: `
vcl 4.1;
backend default {
  .host = "{{ .Env.BACKEND_SERVICE_NAME }}";
  .port = "{{ .Env.BACKEND_SERVICE_PORT }}";
}
`,
});

Alternatively, point varnishVclFile at a VCL template file on disk; the construct reads it at synth time. When you set neither option, the construct uses the built-in config/varnish.tpl.vcl.

new PloneHttpcache(chart, 'cache', {
  plone: plone,
  existingSecret: 'varnish-admin',
  varnishVclFile: './config/varnish.tpl.vcl',
});

VCL templates use Go template syntax. The construct supplies these environment variables: BACKEND_SERVICE_NAME, BACKEND_SERVICE_PORT, BACKEND_SITE_ID, FRONTEND_SERVICE_NAME, and FRONTEND_SERVICE_PORT. Reference them as {{ .Env.NAME }}.

Add your own variables through extraEnvVars, which are appended to the built-in set.

new PloneHttpcache(chart, 'cache', {
  plone: plone,
  existingSecret: 'varnish-admin',
  extraEnvVars: [
    { name: 'THUMBOR_SERVICE_NAME', value: 'my-thumbor' },
  ],
});

Reference an extra variable in your VCL template as {{ .Env.THUMBOR_SERVICE_NAME }}.

Schedule the cache pods#

Add tolerations so the cache pods can run on tainted nodes.

new PloneHttpcache(chart, 'cache', {
  plone: plone,
  existingSecret: 'varnish-admin',
  tolerations: [
    { key: 'dedicated', operator: 'Equal', value: 'cache', effect: 'NoSchedule' },
  ],
});

Omit effect to tolerate every taint for the given key. operator defaults to 'Equal'.

Enable monitoring#

Set servicemonitor to emit a Prometheus ServiceMonitor, and keep exporterEnabled so the Varnish exporter sidecar is present for it to scrape.

new PloneHttpcache(chart, 'cache', {
  plone: plone,
  existingSecret: 'varnish-admin',
  servicemonitor: true,
  exporterEnabled: true,
});

exporterEnabled defaults to true, and servicemonitor defaults to false. Use servicemonitor here; there is no monitoring option on this construct. For the full monitoring setup, see Enable Prometheus monitoring.

Pin the chart and image versions#

Set chartVersion to pin the kube-httpcache Helm chart, and appVersion to pin the image tag.

new PloneHttpcache(chart, 'cache', {
  plone: plone,
  existingSecret: 'varnish-admin',
  chartVersion: '0.13.1',
  appVersion: '0.13.1',
});

chartVersion defaults to the latest chart, and appVersion defaults to chartVersion.

Point your ingress at the cache#

Route external traffic through the cache by using the read-only httpcacheServiceName output as your Ingress or IngressRoute upstream instead of the Plone frontend service.

const cache = new PloneHttpcache(chart, 'cache', {
  plone: plone,
  existingSecret: 'varnish-admin',
});

const upstream = cache.httpcacheServiceName;

For the routing and TLS details, see Configure ingress and TLS.

Verify the cache#

Generate the manifests and confirm the cache resources are present.

cdk8s synth
grep -l 'kube-httpcache' dist/*.yaml

Apply the manifests and inspect the rollout on the cluster.

kubectl apply -f dist/
kubectl get pods -n <namespace>
kubectl get service -n <namespace>

Send a request through the cache service and check the Varnish response headers.

kubectl run -it --rm curl --image=curlimages/curl --restart=Never -- \
  curl -sI http://<httpcacheServiceName>.<namespace>:80/

A cached response carries an X-Varnish header, and an Age header greater than zero confirms a cache hit.

PloneHttpcache compared with PloneVinylCache#

PloneHttpcache runs Varnish from the mittwald kube-httpcache chart with a Secret and a VCL template that you supply. PloneVinylCache runs Varnish through the cloud-vinyl operator, which generates VCL from structured configuration and manages credentials for you. For the trade-offs between the two, see Architecture overview and Deploy with cloud-vinyl cache.

See also#