Configuration guide#
This guide shows the most common ways to configure cdk8s-plone, grouped by task, with copy-pasteable examples.
Important
For the complete and authoritative list of every construct, option, type, default value, and whether it is required, see the API reference. That reference is generated from the TypeScript source, so it never drifts. This guide is hand-written orientation and deliberately does not repeat the full option tables.
Constructs at a glance#
PloneDeploys the Plone backend and, for the Volto variant, the React frontend, plus their services and (optionally) a
PodDisruptionBudgetandServiceMonitor. This is the entry point.PloneHttpcacheAdds a Varnish caching layer through the mittwald kube-httpcache Helm chart. Self-contained: it needs no operator in the cluster.
PloneVinylCacheAdds a Varnish caching layer through the cloud-vinyl operator. Requires the operator to be installed in the cluster.
To choose between the two cache constructs, read Architecture overview.
Choose a frontend variant#
The Plone construct deploys one of two frontends, selected with variant:
import { Plone, PloneVariant } from '@bluedynamics/cdk8s-plone';
// Volto: React single-page frontend talking to the REST API backend (default).
new Plone(chart, 'plone', {
variant: PloneVariant.VOLTO,
backend: {},
frontend: {},
});
// Blicca: the backend renders the UI server-side, so there is no separate frontend.
new Plone(chart, 'plone', {
variant: PloneVariant.BLICCA,
backend: {},
});
Note
PloneVariant.CLASSICUI is a deprecated alias for PloneVariant.BLICCA, kept for backward compatibility.
It keeps its legacy value ('classicui'), so existing configuration keeps working unchanged.
The alias will be removed in a future major release.
For the conceptual difference between the variants, see Deployment variants.
Configure the backend and frontend#
Both backend and frontend take the same options (PloneBaseOptions).
The examples below cover the common groups.
See the API reference for every field, its type, and its default.
Images and replicas#
backend: {
image: 'plone/plone-backend:6.1.3',
replicas: 3,
imagePullPolicy: 'Always',
}
Resource requests and limits#
backend: {
requestCpu: '500m',
limitCpu: '2',
requestMemory: '512Mi',
limitMemory: '2Gi',
}
High availability#
A PodDisruptionBudget is created automatically when replicas is 2 or more, or when you set minAvailable or maxUnavailable explicitly.
Both accept an absolute number or a percentage string such as "50%".
backend: {
replicas: 5,
minAvailable: 3, // keep at least 3 pods available during voluntary disruptions
}
rollingUpdate controls how a Deployment replaces its pods during an update (spec.strategy.rollingUpdate).
It is independent of the top-level maxUnavailable and minAvailable, which configure the PodDisruptionBudget.
Both fields take an absolute number or a percentage string.
Without the option, Kubernetes uses 25% for both.
backend: {
rollingUpdate: { maxUnavailable: 0, maxSurge: '50%' }, // no capacity dip during rollouts
}
Probes#
Readiness probes are enabled by default; liveness probes are disabled by default.
frontend: {
readinessEnabled: true,
readinessInitialDelaySeconds: 10,
livenessEnabled: true, // opt in; useful for the frontend
livenessInitialDelaySeconds: 30,
}
Graceful shutdown#
Each Plone container waits in a preStop hook before it receives SIGTERM.
During that time kube-proxy, ingress controllers, and caches that address pods directly stop sending it requests.
preStopDelaySecondsdefaults to15.0disables the hook.terminationGracePeriodSecondsdefaults topreStopDelaySecondsplus30, so the shutdown after the delay keeps the 30 seconds that Kubernetes grants by default. Without a hook, the field stays unset.An explicit
terminationGracePeriodSecondsmust be greater thanpreStopDelaySeconds.
backend: {
preStopDelaySeconds: 20,
terminationGracePeriodSeconds: 90, // long-running requests get 70 seconds to finish
}
The hook uses the native sleep action, so the image needs no sleep binary.
It requires Kubernetes 1.30 or later.
Service#
Configure the generated Kubernetes Service through the grouped service option.
Curated fields cover the common cases; service.overrides is an escape hatch for any other ServiceSpec field and has the highest precedence.
Write overrides in their manifest form, for example clusterIP or targetPort: 8080.
Each top-level key replaces the field as a whole.
backend: {
service: {
type: 'LoadBalancer',
trafficDistribution: 'PreferClose',
loadBalancerSourceRanges: ['10.0.0.0/8'],
annotations: {
'external-dns.alpha.kubernetes.io/hostname': 'backend.example.com',
},
overrides: {
ipFamilyPolicy: 'PreferDualStack',
},
},
}
Note
The top-level serviceAnnotations option is deprecated. Use service.annotations instead.
Escape hatch#
For fields without a dedicated option, patch the generated objects with JSON Patch.
Plone exposes backendDeployment, backendService, frontendDeployment, and frontendService.
The frontend properties are undefined for the Blicca variant.
import { JsonPatch } from 'cdk8s';
const plone = new Plone(chart, 'plone');
plone.backendDeployment.addJsonPatch(
JsonPatch.add('/spec/strategy', {
type: 'RollingUpdate',
rollingUpdate: { maxUnavailable: 0, maxSurge: '50%' },
}),
JsonPatch.add('/spec/template/spec/containers/0/args', ['--debug']),
);
Patches apply to the final manifest, so you write values in their manifest form, such as
'50%'orcpu: '2'.The Plone container is always
containers/0.Patches are not validated. Prefer a dedicated option where one exists.
Environment variables#
Pass environment variables with the cdk8s-plus Env API, including values sourced from a Secret.
import { Env } from 'cdk8s-plus-30';
backend: {
environment: {
variables: {
RELSTORAGE_DSN: Env.fromSecret(dbSecret, 'dsn'),
},
},
}
Annotations, scheduling, security, and monitoring#
These groups each have a dedicated how-to guide:
Schedule pods to specific nodes —
nodeSelectorandtolerationsConfigure security context —
securityContexthardeningEnable Prometheus monitoring —
servicemonitor,metricsPort,metricsPath
Add a cache#
import { PloneHttpcache } from '@bluedynamics/cdk8s-plone';
// Self-contained Varnish via the kube-httpcache Helm chart.
new PloneHttpcache(chart, 'cache', {
plone: ploneInstance,
existingSecret: 'varnish-secret',
replicas: 2,
});
import { PloneVinylCache } from '@bluedynamics/cdk8s-plone';
// Operator-managed Varnish via the cloud-vinyl operator.
const cache = new PloneVinylCache(chart, 'cache', {
plone: ploneInstance,
storage: [{ name: 'cache', type: 'malloc', size: '1G' }],
cluster: true,
monitoring: true,
});
Important
PloneVinylCache without an explicit storage entry runs varnishd with its stock default (~100 MB malloc) regardless of the container memory limit.
Size malloc storage below the pod’s memory limit to leave headroom for varnishd overhead.
Never name a storage entry s0; the stock image’s entrypoint already defines it.
Option |
Type |
Default |
Description |
|---|---|---|---|
|
boolean |
not set |
Sets |
|
map of string |
not set |
Sets |
For the full walk-through, including custom VCL snippets and shard-director tuning, see Deploy with cloud-vinyl cache.
Complete example#
import { App, Chart } from 'cdk8s';
import { Plone, PloneVariant, PloneHttpcache } from '@bluedynamics/cdk8s-plone';
import { Env } from 'cdk8s-plus-30';
const app = new App();
const chart = new Chart(app, 'PloneDeployment');
const plone = new Plone(chart, 'my-plone', {
siteId: 'MySite',
variant: PloneVariant.VOLTO,
imagePullSecrets: ['registry-secret'],
backend: {
image: 'plone/plone-backend:6.1.3',
replicas: 3,
requestCpu: '500m',
limitCpu: '2',
requestMemory: '512Mi',
limitMemory: '2Gi',
minAvailable: 2,
environment: {
variables: {
SITE: Env.value('MySite'),
},
},
},
frontend: {
image: 'plone/plone-frontend:16.0.0',
replicas: 2,
livenessEnabled: true,
},
});
new PloneHttpcache(chart, 'cache', {
plone: plone,
existingSecret: 'varnish-secret',
replicas: 2,
servicemonitor: true,
});
app.synth();
See also#
API reference — every option, type, and default (generated)
Quick start — first deployment, step by step
Deploy the Volto example — production-ready Volto deployment
Deploy Blicca example — Blicca deployment
Architecture overview — how the pieces fit together