```{image} ../_static/kup6s-icon-howto.svg :align: center :class: section-icon-large ``` # Deploy with Cloud-Vinyl Cache

Type: How-To (Task-oriented)

Difficulty: Intermediate

Time: 15 minutes

## Prerequisites - The **cloud-vinyl operator** must be installed in your cluster - A working Plone deployment using `cdk8s-plone` - `@bluedynamics/cdk8s-plone` version with VinylCache support ## Steps ### 1. Add PloneVinylCache to Your Deployment ```typescript import { Plone, PloneVinylCache } 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' }, }); const cache = new PloneVinylCache(chart, 'cache', { plone: plone, replicas: 2, }); ``` ### 2. Use the Cache Service in Your IngressRoute The cache exposes a service that should be used as the upstream in your IngressRoute: ```typescript // Use cache.vinylCacheServiceName as the service target // instead of plone.frontendServiceName ``` ### 3. Build and Deploy ```bash npm run build # Review generated manifests # Deploy via ArgoCD or kubectl apply ``` ### 4. Verify ```bash # Check VinylCache status kubectl get vinylcache -n # Check Varnish pods kubectl get pods -n -l app.kubernetes.io/managed-by=cloud-vinyl ``` ## Customization ### Sizing the Cache Storage Without an explicit `storage` entry, the operator ships varnishd with its stock default (~100 MB malloc) — almost always too small. Set a malloc size below the pod's memory limit, leaving headroom for varnishd overhead: ```typescript new PloneVinylCache(chart, 'cache', { plone: plone, requestMemory: '512Mi', limitMemory: '2Gi', storage: [ { name: 's0', type: 'malloc', size: '1500M' }, ], }); ``` For larger working sets you can combine an in-memory tier with a file-backed tier (requires a writable volume mount at the given path): ```typescript storage: [ { name: 'mem', type: 'malloc', size: '500M' }, { name: 'disk', type: 'file', path: '/var/lib/varnish/disk.bin', size: '10Gi' }, ] ``` ### Custom VCL Override the default Plone VCL snippets for custom caching logic: ```typescript new PloneVinylCache(chart, 'cache', { plone: plone, vclRecvSnippet: fs.readFileSync('./config/custom-recv.vcl', 'utf8'), vclBackendResponseSnippet: fs.readFileSync('./config/custom-beresp.vcl', 'utf8'), }); ``` ### Cache Invalidation Invalidation is enabled by default (PURGE, BAN, xkey). Configure `plone.cachepurging` to point to the VinylCache invalidation proxy endpoint. :::{note} BAN-based invalidation requires **cloud-vinyl operator ≥ 0.4.2**. Earlier versions accept the spec but do not emit the BAN ACL / handler. Starting with 0.4.2 the operator's own pod IP is automatically added to the PURGE ACL, so purges from the operator itself work without additional configuration. ::: To disable invalidation: ```typescript new PloneVinylCache(chart, 'cache', { plone: plone, invalidation: false, }); ``` ### Shard Director Tuning For shard-based load distribution (the default), you can fine-tune the consistent-hash behavior. These options require **cloud-vinyl ≥ 0.4.2** to be honored by the generated VCL. ```typescript new PloneVinylCache(chart, 'cache', { plone: plone, director: 'shard', shardBy: 'URL', // hash the request URL instead of Varnish's hash shardHealthy: 'ALL', // require all backends healthy (vs. only "CHOSEN") shardRampup: '45s', // warm-up window for newly added backends shardReplicas: 128, // Ketama replicas per backend }); ``` Shard options are ignored for non-shard directors (`round_robin`, `random`, `hash`). ## Migrating from PloneHttpcache Replace `PloneHttpcache` with `PloneVinylCache`: ```typescript // Before (mittwald) // import { PloneHttpcache } from '@bluedynamics/cdk8s-plone'; // const cache = new PloneHttpcache(chart, 'cache', { // plone, varnishVcl: '...', existingSecret: 'secret', // }); // const serviceName = cache.httpcacheServiceName; // After (cloud-vinyl) import { PloneVinylCache } from '@bluedynamics/cdk8s-plone'; const cache = new PloneVinylCache(chart, 'cache', { plone }); const serviceName = cache.vinylCacheServiceName; ``` Key differences: - No VCL template needed (operator generates VCL from structured config) - No `existingSecret` needed (operator manages agent authentication) - Service name property is `vinylCacheServiceName` (not `httpcacheServiceName`)