@bluedynamics/cdk8s-plone 0.1.9 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.claude/claude.md +39 -0
  2. package/.claude/settings.local.json +31 -0
  3. package/.jsii +4 -4
  4. package/README.md +15 -2
  5. package/documentation/sources/how-to/deploy-classic-ui.md +322 -0
  6. package/documentation/sources/how-to/deploy-production-volto.md +319 -0
  7. package/documentation/sources/how-to/index.md +13 -0
  8. package/documentation/sources/reference/api/index.md +29 -0
  9. package/examples/classic-ui/.env.example +19 -0
  10. package/examples/classic-ui/README.md +343 -0
  11. package/examples/classic-ui/__snapshots__/main.test.ts.snap +1242 -0
  12. package/examples/classic-ui/cdk8s.yaml +6 -0
  13. package/examples/classic-ui/config/varnish.tpl.vcl +217 -0
  14. package/examples/classic-ui/ingress.ts +217 -0
  15. package/examples/classic-ui/jest.config.js +11 -0
  16. package/examples/classic-ui/main.test.ts +11 -0
  17. package/examples/classic-ui/main.ts +100 -0
  18. package/examples/classic-ui/package-lock.json +5719 -0
  19. package/examples/classic-ui/package.json +36 -0
  20. package/examples/classic-ui/postgres.bitnami.ts +49 -0
  21. package/examples/classic-ui/postgres.cloudnativepg.ts +63 -0
  22. package/examples/production-volto/.env.example +20 -0
  23. package/examples/production-volto/README.md +295 -0
  24. package/examples/production-volto/__snapshots__/main.test.ts.snap +1412 -0
  25. package/examples/production-volto/cdk8s.yaml +6 -0
  26. package/examples/production-volto/config/varnish.tpl.vcl +297 -0
  27. package/examples/production-volto/ingress.ts +229 -0
  28. package/examples/production-volto/jest.config.js +11 -0
  29. package/examples/production-volto/main.test.ts +11 -0
  30. package/examples/production-volto/main.ts +104 -0
  31. package/examples/production-volto/package-lock.json +5714 -0
  32. package/examples/production-volto/package.json +36 -0
  33. package/examples/production-volto/postgres.bitnami.ts +49 -0
  34. package/examples/production-volto/postgres.cloudnativepg.ts +63 -0
  35. package/lib/httpcache.js +1 -1
  36. package/lib/plone.js +1 -1
  37. package/package.json +3 -3
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "cdk8s-plone-example-classic-ui",
3
+ "version": "1.0.0",
4
+ "description": "Classic UI Plone deployment example using cdk8s-plone",
5
+ "main": "main.js",
6
+ "types": "main.ts",
7
+ "license": "Apache-2.0",
8
+ "private": true,
9
+ "scripts": {
10
+ "import": "cdk8s import",
11
+ "synth": "cdk8s synth",
12
+ "compile": "tsc --build",
13
+ "watch": "tsc --build -w",
14
+ "test": "jest",
15
+ "test-update": "jest --updateSnapshot",
16
+ "build": "npm run compile && npm run test && npm run synth",
17
+ "upgrade": "npm i cdk8s@latest cdk8s-cli@latest",
18
+ "upgrade:next": "npm i cdk8s@next cdk8s-cli@next"
19
+ },
20
+ "dependencies": {
21
+ "@bluedynamics/cdk8s-plone": "../../",
22
+ "cdk8s": "^2.70.27",
23
+ "cdk8s-plus-30": "^2.4.10",
24
+ "constructs": "^10.4.2",
25
+ "dotenv": "^16.4.5"
26
+ },
27
+ "devDependencies": {
28
+ "@types/jest": "^29.5.14",
29
+ "@types/node": "^18.19.64",
30
+ "cdk8s-cli": "^2.198.268",
31
+ "jest": "^29.7.0",
32
+ "ts-jest": "^29.2.5",
33
+ "ts-node": "^10.9.2",
34
+ "typescript": "^5.9.3"
35
+ }
36
+ }
@@ -0,0 +1,49 @@
1
+ import { Construct } from 'constructs';
2
+ import { Helm } from 'cdk8s';
3
+
4
+ export class PGBitnamiChart extends Construct {
5
+ public readonly dbServiceName: string;
6
+
7
+ constructor(scope: Construct, id: string) {
8
+ super(scope, id);
9
+
10
+ const dbname = 'plone';
11
+ const dbuser = 'plone';
12
+ const dbpass = 'admin@plone';
13
+
14
+ const db = new Helm(this, 'db', {
15
+ chart: 'postgresql',
16
+ repo: 'https://charts.bitnami.com/bitnami',
17
+ // XXX: in fact I do not want a namespace here.
18
+ // I want to use the passed in with kubectl apply.
19
+ // need to figure out how to achieve this. Could be bitnami specific.
20
+ namespace: 'plone',
21
+ values: {
22
+ 'commonLabels': { 'app.kubernetes.io/part-of': 'plone' },
23
+ 'global': {
24
+ 'postgresql': {
25
+ 'postgresPassword': 'admin@postgres',
26
+ 'username': dbuser,
27
+ 'password': dbpass,
28
+ 'database': dbname,
29
+ },
30
+ },
31
+ 'auth': {
32
+ 'username': dbuser,
33
+ 'password': dbpass,
34
+ 'database': dbname,
35
+ }
36
+ }
37
+ });
38
+ const dbService = db.apiObjects.find(construct => {
39
+ if ((construct.kind === 'Service') && (construct.metadata.name?.endsWith('postgresql'))) {
40
+ return construct.name;
41
+ }
42
+ return undefined;
43
+ });
44
+ if (dbService === undefined) {
45
+ throw new Error('Could not find postgresql service');
46
+ }
47
+ this.dbServiceName = dbService.name;
48
+ }
49
+ };
@@ -0,0 +1,63 @@
1
+ import { Construct } from 'constructs';
2
+ import * as cnpg from './imports/postgresql.cnpg.io'
3
+
4
+ export class PGCloudNativePGChart extends Construct {
5
+ // uses the CloudNativePG operator
6
+ // https://cloudnative-pg.io/
7
+
8
+ public readonly dbServiceName: string;
9
+ public readonly clusterName: string;
10
+
11
+ constructor(scope: Construct, id: string) {
12
+ super(scope, id);
13
+
14
+ const db = new cnpg.Cluster(
15
+ this,
16
+ 'db',
17
+ {
18
+ metadata: {
19
+ labels: {
20
+ 'app.kubernetes.io/name': 'plone-postgresql',
21
+ 'app.kubernetes.io/instance': 'postgresql',
22
+ 'app.kubernetes.io/component': 'database',
23
+ 'app.kubernetes.io/part-of': 'plone',
24
+ }
25
+ },
26
+ spec: {
27
+ instances: 2,
28
+ postgresql: {
29
+ parameters: {
30
+ 'max_connections': '200',
31
+ 'shared_buffers': '256MB',
32
+ 'effective_cache_size': '1GB',
33
+ 'maintenance_work_mem': '64MB',
34
+ 'checkpoint_completion_target': '0.9',
35
+ 'wal_buffers': '16MB',
36
+ 'default_statistics_target': '100',
37
+ 'random_page_cost': '1.1',
38
+ 'effective_io_concurrency': '200',
39
+ 'work_mem': '4MB',
40
+ 'min_wal_size': '1GB',
41
+ 'max_wal_size': '4GB',
42
+ }
43
+ },
44
+ bootstrap: {
45
+ initdb: {
46
+ database: 'plone',
47
+ owner: 'plone',
48
+ }
49
+ },
50
+ storage: {
51
+ size: '10Gi',
52
+ },
53
+ }
54
+ }
55
+ );
56
+
57
+ // CloudNativePG creates a service named {cluster-name}-rw for read-write access
58
+ // CloudNativePG creates a secret named {cluster-name}-app with username/password
59
+ // Use the CDK8S-generated name, never hard-code metadata.name
60
+ this.clusterName = db.name;
61
+ this.dbServiceName = `${db.name}-rw`;
62
+ }
63
+ }
@@ -0,0 +1,20 @@
1
+ # This file contains the environment variables for the project.
2
+ # Copy this file to .env and adjust the values as needed.
3
+ # The variables are loaded when "cdk8s synth" is called.
4
+
5
+ # Configure domain names
6
+ DOMAIN_CACHED=plone.example.com
7
+ DOMAIN_UNCACHED=plone-test.example.com
8
+ DOMAIN_MAINTENANCE=plone-admin.example.com
9
+
10
+ # Cluster issuer to use (cert-manager ClusterIssuer for TLS certificates)
11
+ CLUSTER_ISSUER=letsencrypt-prod
12
+
13
+ # Configure the Plone images to use
14
+ # Leave commented to use defaults (official Plone images)
15
+ #PLONE_FRONTEND_IMAGE=plone/plone-frontend:latest
16
+ #PLONE_BACKEND_IMAGE=plone/plone-backend:6.1.3
17
+
18
+ # Configure database backend
19
+ # Options: 'bitnami' (default, simple) or 'cloudnativepg' (production-ready)
20
+ DATABASE=cloudnativepg
@@ -0,0 +1,295 @@
1
+ # Production Volto Example
2
+
3
+ This example demonstrates a **production-ready Plone deployment** using the [@bluedynamics/cdk8s-plone](https://www.npmjs.com/package/@bluedynamics/cdk8s-plone) TypeScript package.
4
+
5
+ ## Features
6
+
7
+ This example includes:
8
+
9
+ - **Plone 6.1 with Volto** (React frontend + REST API backend)
10
+ - **PostgreSQL with RelStorage** - Choose between:
11
+ - [CloudNativePG](https://cloudnative-pg.io/) (CNCF project, production-ready with HA)
12
+ - [Bitnami PostgreSQL](https://github.com/bitnami/charts/tree/main/bitnami/postgresql) Helm chart (simple, for dev/testing)
13
+ - **HTTP Caching with Varnish** - Using [kube-httpcache](https://github.com/mittwald/kube-httpcache)
14
+ - **Ingress** - Supports both Traefik and Kong with TLS/cert-manager
15
+ - **Three access domains**:
16
+ - Cached (public, via Varnish)
17
+ - Uncached (testing, direct to frontend)
18
+ - Maintenance (backend API access)
19
+
20
+ ## Prerequisites
21
+
22
+ ### Node.js Setup
23
+
24
+ Configure Node.js:
25
+ ```bash
26
+ nvm use lts/*
27
+ ```
28
+
29
+ Install dependencies:
30
+ ```bash
31
+ npm install
32
+ ```
33
+
34
+ ### Kubernetes Cluster Requirements
35
+
36
+ Your cluster needs:
37
+
38
+ 1. **PostgreSQL Operator** (choose one):
39
+ - **CloudNativePG** (recommended for production):
40
+ ```bash
41
+ kubectl apply -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.24/releases/cnpg-1.24.0.yaml
42
+ ```
43
+ - **Bitnami** (no operator needed, uses Helm):
44
+ - Requires namespace `plone` to exist: `kubectl create namespace plone`
45
+
46
+ 2. **Ingress Controller** (choose one):
47
+ - Traefik v3 with CRDs installed
48
+ - Kong Gateway
49
+
50
+ 3. **cert-manager** (for TLS certificates):
51
+ ```bash
52
+ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml
53
+ ```
54
+
55
+ 4. **kube-httpcache Operator** (for Varnish caching):
56
+ ```bash
57
+ kubectl apply -f https://github.com/mittwald/kube-httpcache/releases/latest/download/kube-httpcache.yaml
58
+ ```
59
+
60
+ ## Usage
61
+
62
+ ### 1. Import CRDs
63
+
64
+ Import the required Custom Resource Definitions:
65
+
66
+ ```bash
67
+ npm run import
68
+ ```
69
+
70
+ This will generate TypeScript bindings in `./imports/` for:
71
+ - Kubernetes core API
72
+ - Traefik IngressRoute CRDs
73
+ - CloudNativePG Cluster CRDs
74
+
75
+ ### 2. Configure Environment
76
+
77
+ Create a `.env` file (copy from `.env.example`):
78
+
79
+ ```bash
80
+ # Domain names
81
+ DOMAIN_CACHED=plone.example.com
82
+ DOMAIN_UNCACHED=plone-test.example.com
83
+ DOMAIN_MAINTENANCE=plone-admin.example.com
84
+
85
+ # TLS certificate issuer (cert-manager ClusterIssuer)
86
+ CLUSTER_ISSUER=letsencrypt-prod
87
+
88
+ # Plone images (defaults to official images if not set)
89
+ PLONE_BACKEND_IMAGE=plone/plone-backend:6.1.3
90
+ PLONE_FRONTEND_IMAGE=plone/plone-frontend:latest
91
+
92
+ # Database backend: 'bitnami' (default) or 'cloudnativepg'
93
+ DATABASE=cloudnativepg
94
+ ```
95
+
96
+ ### 3. Generate Kubernetes Manifests
97
+
98
+ ```bash
99
+ npm run synth
100
+ ```
101
+
102
+ This generates `dist/plone-example.k8s.yaml` with all Kubernetes resources.
103
+
104
+ ### 4. Deploy to Kubernetes
105
+
106
+ ```bash
107
+ kubectl apply -f dist/plone-example.k8s.yaml
108
+ ```
109
+
110
+ Or deploy to a specific namespace:
111
+ ```bash
112
+ kubectl apply -f dist/plone-example.k8s.yaml -n plone
113
+ ```
114
+
115
+ ## Database Options
116
+
117
+ ### CloudNativePG (Production)
118
+
119
+ **Pros:**
120
+ - CNCF Sandbox project (Cloud Native Computing Foundation)
121
+ - Built-in high availability (2 instances)
122
+ - Automated backups and point-in-time recovery
123
+ - Monitoring and observability
124
+ - Connection pooling support
125
+ - Modern, actively maintained
126
+
127
+ **Configuration:**
128
+ ```bash
129
+ DATABASE=cloudnativepg
130
+ ```
131
+
132
+ **Secrets:** CloudNativePG automatically creates a secret `plone-postgresql-app` with:
133
+ - `username` - Database user
134
+ - `password` - Database password
135
+
136
+ ### Bitnami PostgreSQL (Development/Testing)
137
+
138
+ **Pros:**
139
+ - No operator required
140
+ - Simple setup
141
+ - Good for development and testing
142
+ - Helm-based deployment
143
+
144
+ **Cons:**
145
+ - Requires namespace `plone` to be pre-created
146
+ - No built-in HA features
147
+ - Less suitable for production
148
+
149
+ **Configuration:**
150
+ ```bash
151
+ DATABASE=bitnami
152
+ ```
153
+
154
+ ## Architecture
155
+
156
+ ```
157
+ ┌─────────────────┐
158
+ │ cert-manager │
159
+ │ (TLS Certs) │
160
+ └────────┬────────┘
161
+
162
+ ┌──────────────────┐ ┌────▼────────────┐
163
+ │ External │───▶│ Ingress │
164
+ │ Traffic │ │ (Traefik/Kong) │
165
+ └──────────────────┘ └────┬─────┬──────┘
166
+ │ │
167
+ ┌──────────────┘ └──────────────┐
168
+ │ │
169
+ ┌─────────▼─────────┐ ┌─────────▼─────────┐
170
+ │ HTTP Cache │ │ Plone Frontend │
171
+ │ (Varnish) │ │ (Volto/React) │
172
+ └─────────┬─────────┘ └─────────┬─────────┘
173
+ │ │
174
+ └──────────────┬─────────────────────┘
175
+
176
+ ┌─────────▼─────────┐
177
+ │ Plone Backend │
178
+ │ (Python/Zope) │
179
+ └─────────┬─────────┘
180
+
181
+ ┌─────────▼─────────┐
182
+ │ PostgreSQL │
183
+ │ (RelStorage) │
184
+ └───────────────────┘
185
+ ```
186
+
187
+ ## Development
188
+
189
+ ### Build and Test
190
+
191
+ ```bash
192
+ # Compile TypeScript
193
+ npm run compile
194
+
195
+ # Run tests
196
+ npm test
197
+
198
+ # Update test snapshots
199
+ npm run test-update
200
+
201
+ # Full build (compile + test + synth)
202
+ npm run build
203
+ ```
204
+
205
+ ### Watch Mode
206
+
207
+ ```bash
208
+ npm run watch
209
+ ```
210
+
211
+ ## Customization
212
+
213
+ ### Changing Plone Configuration
214
+
215
+ Edit [main.ts](main.ts) to customize:
216
+ - RelStorage settings (cache sizes, blob mode)
217
+ - Resource limits
218
+ - Environment variables
219
+ - Number of replicas
220
+
221
+ ### Modifying Varnish Caching
222
+
223
+ Edit [config/varnish.tpl.vcl](config/varnish.tpl.vcl) to customize:
224
+ - Cache rules
225
+ - Request routing logic
226
+ - Authentication handling
227
+ - PURGE/BAN configurations
228
+
229
+ ### Ingress Configuration
230
+
231
+ Edit [ingress.ts](ingress.ts) to:
232
+ - Add/modify domain routes
233
+ - Change TLS settings
234
+ - Customize path rewrites
235
+ - Add middleware
236
+
237
+ ## Troubleshooting
238
+
239
+ ### Check Pod Status
240
+
241
+ ```bash
242
+ kubectl get pods -l app.kubernetes.io/part-of=plone
243
+ ```
244
+
245
+ ### View Logs
246
+
247
+ ```bash
248
+ # Backend logs
249
+ kubectl logs -l app.kubernetes.io/name=plone-backend -f
250
+
251
+ # Frontend logs
252
+ kubectl logs -l app.kubernetes.io/name=plone-frontend -f
253
+
254
+ # Varnish cache logs
255
+ kubectl logs -l app.kubernetes.io/name=plone-httpcache -f
256
+ ```
257
+
258
+ ### Database Connection Issues
259
+
260
+ **CloudNativePG:**
261
+ ```bash
262
+ # Check cluster status
263
+ kubectl get cluster plone-postgresql
264
+
265
+ # Check secret
266
+ kubectl get secret plone-postgresql-app -o yaml
267
+ ```
268
+
269
+ **Bitnami:**
270
+ ```bash
271
+ # Check service
272
+ kubectl get svc -l app.kubernetes.io/part-of=plone
273
+
274
+ # Check secret
275
+ kubectl get secret <service-name> -o yaml
276
+ ```
277
+
278
+ ### Access Logs
279
+
280
+ ```bash
281
+ # Get all Plone-related resources
282
+ kubectl get all -l app.kubernetes.io/part-of=plone
283
+ ```
284
+
285
+ ## References
286
+
287
+ - [cdk8s-plone Documentation](https://bluedynamics.github.io/cdk8s-plone/)
288
+ - [Plone 6 Documentation](https://6.docs.plone.org/)
289
+ - [CloudNativePG Documentation](https://cloudnative-pg.io/documentation/)
290
+ - [CDK8S Documentation](https://cdk8s.io/)
291
+ - [Varnish Documentation](https://varnish-cache.org/docs/)
292
+
293
+ ## License
294
+
295
+ Apache-2.0