@bluedynamics/cdk8s-plone 0.1.43 → 0.1.44

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 (73) hide show
  1. package/.jsii +24 -23
  2. package/API.md +6 -2
  3. package/README.md +3 -3
  4. package/documentation/sources/conf.py +55 -29
  5. package/documentation/sources/explanation/architecture.md +14 -16
  6. package/documentation/sources/explanation/cdk8s-workflow.md +66 -0
  7. package/documentation/sources/explanation/index.md +1 -27
  8. package/documentation/sources/how-to/backup-and-restore.md +107 -0
  9. package/documentation/sources/how-to/configure-env-and-secrets.md +184 -0
  10. package/documentation/sources/how-to/configure-ingress-tls.md +108 -0
  11. package/documentation/sources/how-to/configure-security-context.md +0 -5
  12. package/documentation/sources/how-to/deploy-blicca.md +8 -8
  13. package/documentation/sources/how-to/{deploy-production-volto.md → deploy-volto.md} +20 -25
  14. package/documentation/sources/how-to/deploy-with-httpcache.md +224 -0
  15. package/documentation/sources/how-to/deploy-with-vinyl-cache.md +0 -5
  16. package/documentation/sources/how-to/enable-prometheus-monitoring.md +4 -5
  17. package/documentation/sources/how-to/index.md +15 -8
  18. package/documentation/sources/how-to/scale-and-high-availability.md +122 -0
  19. package/documentation/sources/how-to/schedule-pods.md +0 -5
  20. package/documentation/sources/how-to/troubleshooting.md +113 -0
  21. package/documentation/sources/how-to/upgrade-and-rollout.md +89 -0
  22. package/documentation/sources/index.md +3 -11
  23. package/documentation/sources/reference/api/index.md +6 -4
  24. package/documentation/sources/reference/configuration-options.md +85 -516
  25. package/documentation/sources/reference/index.md +16 -43
  26. package/documentation/sources/tutorials/01-quick-start.md +1 -1
  27. package/documentation/sources/tutorials/index.md +7 -11
  28. package/examples/blicca/.env.example +3 -2
  29. package/examples/blicca/README.md +21 -24
  30. package/examples/blicca/__snapshots__/main.test.ts.snap +138 -345
  31. package/examples/blicca/main.test.ts +7 -0
  32. package/examples/blicca/main.ts +8 -7
  33. package/examples/blicca/postgres.plain.ts +115 -0
  34. package/examples/blicca/tsconfig.json +33 -0
  35. package/examples/{production-volto → volto}/.env.example +3 -2
  36. package/examples/{production-volto → volto}/README.md +20 -23
  37. package/examples/{production-volto → volto}/__snapshots__/main.test.ts.snap +139 -345
  38. package/examples/{production-volto → volto}/main.test.ts +7 -0
  39. package/examples/{production-volto → volto}/main.ts +8 -7
  40. package/examples/{production-volto → volto}/package.json +1 -1
  41. package/examples/volto/postgres.plain.ts +115 -0
  42. package/examples/volto/tsconfig.json +33 -0
  43. package/lib/httpcache.js +1 -1
  44. package/lib/imports/vinyl.bluedynamics.eu.d.ts +4011 -53
  45. package/lib/imports/vinyl.bluedynamics.eu.js +1786 -157
  46. package/lib/plone.js +1 -1
  47. package/lib/vinylcache.d.ts +3 -1
  48. package/lib/vinylcache.js +3 -2
  49. package/package.json +1 -1
  50. package/documentation/sources/_static/brand-theme.css +0 -685
  51. package/documentation/sources/_static/custom-icons.css +0 -123
  52. package/documentation/sources/_static/fonts/hack/Hack-Regular.woff2 +0 -0
  53. package/documentation/sources/_static/fonts/orbitron/Orbitron-Black.woff2 +0 -11
  54. package/documentation/sources/_static/fonts/orbitron/Orbitron-Bold.woff2 +0 -11
  55. package/documentation/sources/_static/fonts/orbitron/Orbitron-Regular.woff2 +0 -0
  56. package/documentation/sources/_static/fonts/rajdhani/Rajdhani-Bold.woff2 +0 -11
  57. package/documentation/sources/_static/fonts/rajdhani/Rajdhani-Medium.woff2 +0 -11
  58. package/documentation/sources/_static/fonts/rajdhani/Rajdhani-Regular.woff2 +0 -11
  59. package/documentation/sources/_static/fonts/rajdhani/Rajdhani-SemiBold.woff2 +0 -11
  60. package/documentation/sources/_static/kup6s-icon-explanation.svg +0 -32
  61. package/documentation/sources/_static/kup6s-icon-howto.svg +0 -34
  62. package/documentation/sources/_static/kup6s-icon-reference.svg +0 -34
  63. package/documentation/sources/_static/kup6s-icon-tutorials.svg +0 -30
  64. package/documentation/sources/_static/logo-fix.js +0 -12
  65. package/documentation/sources/reference/api/.gitkeep +0 -1
  66. package/examples/blicca/postgres.bitnami.ts +0 -49
  67. package/examples/production-volto/postgres.bitnami.ts +0 -49
  68. /package/documentation/sources/_static/{kup6s-icon-plone.svg → logo.svg} +0 -0
  69. /package/examples/{production-volto → volto}/cdk8s.yaml +0 -0
  70. /package/examples/{production-volto → volto}/config/varnish.tpl.vcl +0 -0
  71. /package/examples/{production-volto → volto}/ingress.ts +0 -0
  72. /package/examples/{production-volto → volto}/jest.config.js +0 -0
  73. /package/examples/{production-volto → volto}/postgres.cloudnativepg.ts +0 -0
@@ -5,7 +5,7 @@ import * as kplus from 'cdk8s-plus-30';
5
5
  import * as path from 'path';
6
6
  import { IngressChart } from './ingress';
7
7
  import { config } from 'dotenv';
8
- import { PGBitnamiChart } from './postgres.bitnami';
8
+ import { PGPlainChart } from './postgres.plain';
9
9
  import { PGCloudNativePGChart } from './postgres.cloudnativepg';
10
10
 
11
11
 
@@ -17,10 +17,10 @@ export class BliccaChart extends Chart {
17
17
 
18
18
  // ================================================================================================================
19
19
  // Postgresql
20
- let db: PGBitnamiChart | PGCloudNativePGChart;
20
+ let db: PGPlainChart | PGCloudNativePGChart;
21
21
  let postgresql_username;
22
22
  let postgresql_password;
23
- if ((process.env.DATABASE ?? 'bitnami') == 'cloudnativepg') {
23
+ if ((process.env.DATABASE ?? 'plain') == 'cloudnativepg') {
24
24
  const cloudnativepgDb = new PGCloudNativePGChart(this, 'db');
25
25
  db = cloudnativepgDb;
26
26
  // CloudNativePG creates secrets with format: {cluster-name}-app
@@ -29,10 +29,11 @@ export class BliccaChart extends Chart {
29
29
  postgresql_username = { valueFrom: { secretKeyRef: { name: secretName, key: 'username' }}};
30
30
  postgresql_password = { valueFrom: { secretKeyRef: { name: secretName, key: 'password' }}};
31
31
  } else {
32
- const bitnamiDb = new PGBitnamiChart(this, 'db');
33
- db = bitnamiDb;
34
- postgresql_username = { value: 'plone' };
35
- postgresql_password = { valueFrom: { secretKeyRef: { name: `${bitnamiDb.dbServiceName}`, key: 'password' }}};
32
+ // Operator-free single-instance PostgreSQL using the official image.
33
+ const plainDb = new PGPlainChart(this, 'db');
34
+ db = plainDb;
35
+ postgresql_username = { valueFrom: { secretKeyRef: { name: plainDb.secretName, key: 'username' }}};
36
+ postgresql_password = { valueFrom: { secretKeyRef: { name: plainDb.secretName, key: 'password' }}};
36
37
  }
37
38
 
38
39
  // ================================================================================================================
@@ -0,0 +1,115 @@
1
+ import { Construct } from 'constructs';
2
+ import * as k8s from './imports/k8s';
3
+
4
+ /**
5
+ * Operator-free PostgreSQL for the example.
6
+ *
7
+ * Deploys a single-instance PostgreSQL StatefulSet using the official
8
+ * `postgres` Docker image. No operator and no third-party Helm chart are
9
+ * required, which keeps the dependency surface minimal. It is intended for
10
+ * development and small production setups; for high availability, point-in-time
11
+ * recovery, and automated failover use the CloudNativePG variant instead.
12
+ */
13
+ export class PGPlainChart extends Construct {
14
+ public readonly dbServiceName: string;
15
+ public readonly secretName: string;
16
+
17
+ constructor(scope: Construct, id: string) {
18
+ super(scope, id);
19
+
20
+ const dbname = 'plone';
21
+ const dbuser = 'plone';
22
+ const dbpass = 'admin@plone';
23
+
24
+ const labels = {
25
+ 'app.kubernetes.io/name': 'plone-postgresql',
26
+ 'app.kubernetes.io/instance': 'postgresql',
27
+ 'app.kubernetes.io/component': 'database',
28
+ 'app.kubernetes.io/part-of': 'plone',
29
+ };
30
+
31
+ const secret = new k8s.KubeSecret(this, 'secret', {
32
+ metadata: { labels },
33
+ stringData: { username: dbuser, password: dbpass, database: dbname },
34
+ });
35
+ this.secretName = secret.name;
36
+
37
+ const service = new k8s.KubeService(this, 'service', {
38
+ metadata: { labels },
39
+ spec: {
40
+ selector: labels,
41
+ ports: [
42
+ { port: 5432, targetPort: k8s.IntOrString.fromNumber(5432), name: 'postgresql' },
43
+ ],
44
+ },
45
+ });
46
+ this.dbServiceName = service.name;
47
+
48
+ new k8s.KubeStatefulSet(this, 'db', {
49
+ metadata: { labels },
50
+ spec: {
51
+ serviceName: service.name,
52
+ replicas: 1,
53
+ selector: { matchLabels: labels },
54
+ template: {
55
+ metadata: { labels },
56
+ spec: {
57
+ // The official postgres image runs as uid/gid 999.
58
+ // fsGroup makes the mounted volume group-writable for it.
59
+ securityContext: { fsGroup: 999 },
60
+ containers: [
61
+ {
62
+ name: 'postgresql',
63
+ image: 'postgres:18',
64
+ ports: [{ containerPort: 5432, name: 'postgresql' }],
65
+ env: [
66
+ { name: 'POSTGRES_USER', valueFrom: { secretKeyRef: { name: secret.name, key: 'username' } } },
67
+ { name: 'POSTGRES_PASSWORD', valueFrom: { secretKeyRef: { name: secret.name, key: 'password' } } },
68
+ { name: 'POSTGRES_DB', valueFrom: { secretKeyRef: { name: secret.name, key: 'database' } } },
69
+ // Keep PGDATA in a subdirectory so the volume root can hold lost+found.
70
+ { name: 'PGDATA', value: '/var/lib/postgresql/data/pgdata' },
71
+ ],
72
+ volumeMounts: [
73
+ { name: 'data', mountPath: '/var/lib/postgresql/data' },
74
+ ],
75
+ readinessProbe: {
76
+ exec: { command: ['pg_isready', '-U', dbuser, '-d', dbname] },
77
+ initialDelaySeconds: 10,
78
+ periodSeconds: 10,
79
+ timeoutSeconds: 5,
80
+ },
81
+ livenessProbe: {
82
+ exec: { command: ['pg_isready', '-U', dbuser, '-d', dbname] },
83
+ initialDelaySeconds: 30,
84
+ periodSeconds: 15,
85
+ timeoutSeconds: 5,
86
+ },
87
+ resources: {
88
+ requests: {
89
+ cpu: k8s.Quantity.fromString('100m'),
90
+ memory: k8s.Quantity.fromString('256Mi'),
91
+ },
92
+ limits: {
93
+ cpu: k8s.Quantity.fromString('1'),
94
+ memory: k8s.Quantity.fromString('1Gi'),
95
+ },
96
+ },
97
+ },
98
+ ],
99
+ },
100
+ },
101
+ volumeClaimTemplates: [
102
+ {
103
+ metadata: { name: 'data', labels },
104
+ spec: {
105
+ accessModes: ['ReadWriteOnce'],
106
+ resources: {
107
+ requests: { storage: k8s.Quantity.fromString('10Gi') },
108
+ },
109
+ },
110
+ },
111
+ ],
112
+ },
113
+ });
114
+ }
115
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "compilerOptions": {
3
+ "alwaysStrict": true,
4
+ "declaration": true,
5
+ "experimentalDecorators": true,
6
+ "inlineSourceMap": true,
7
+ "inlineSources": true,
8
+ "lib": [
9
+ "ES2020"
10
+ ],
11
+ "module": "CommonJS",
12
+ "noEmit": false,
13
+ "noEmitOnError": true,
14
+ "noFallthroughCasesInSwitch": true,
15
+ "noImplicitAny": true,
16
+ "noImplicitReturns": true,
17
+ "noImplicitThis": true,
18
+ "noUnusedLocals": true,
19
+ "noUnusedParameters": true,
20
+ "resolveJsonModule": true,
21
+ "strict": true,
22
+ "strictNullChecks": true,
23
+ "strictPropertyInitialization": true,
24
+ "stripInternal": true,
25
+ "target": "ES2020"
26
+ },
27
+ "include": [
28
+ "**/*.ts"
29
+ ],
30
+ "exclude": [
31
+ "node_modules"
32
+ ]
33
+ }
@@ -16,5 +16,6 @@ CLUSTER_ISSUER=letsencrypt-prod
16
16
  #PLONE_BACKEND_IMAGE=plone/plone-backend:6.1.3
17
17
 
18
18
  # Configure database backend
19
- # Options: 'bitnami' (default, simple) or 'cloudnativepg' (production-ready)
20
- DATABASE=cloudnativepg
19
+ # Options: 'plain' (default, operator-free single instance) or
20
+ # 'cloudnativepg' (production HA, requires the CloudNativePG operator)
21
+ DATABASE=plain
@@ -1,4 +1,4 @@
1
- # Production Volto Example
1
+ # Volto Example
2
2
 
3
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
4
 
@@ -8,8 +8,8 @@ This example includes:
8
8
 
9
9
  - **Plone 6.1 with Volto** (React frontend + REST API backend)
10
10
  - **PostgreSQL with RelStorage** - Choose between:
11
+ - Plain single-instance PostgreSQL using the official `postgres` image (default, operator-free, for dev and small setups)
11
12
  - [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
13
  - **HTTP Caching with Varnish** - Using [kube-httpcache](https://github.com/mittwald/kube-httpcache)
14
14
  - **Ingress** - Supports both Traefik and Kong with TLS/cert-manager
15
15
  - **Three access domains**:
@@ -35,13 +35,12 @@ npm install
35
35
 
36
36
  Your cluster needs:
37
37
 
38
- 1. **PostgreSQL Operator** (choose one):
39
- - **CloudNativePG** (recommended for production):
38
+ 1. **PostgreSQL** (choose one):
39
+ - **Plain** (default, no operator needed): the example deploys a single-instance PostgreSQL StatefulSet using the official `postgres` image, so there is nothing to install.
40
+ - **CloudNativePG** (recommended for production HA): install the operator
40
41
  ```bash
41
42
  kubectl apply -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.24/releases/cnpg-1.24.0.yaml
42
43
  ```
43
- - **Bitnami** (no operator needed, uses Helm):
44
- - Requires namespace `plone` to exist: `kubectl create namespace plone`
45
44
 
46
45
  2. **Ingress Controller** (choose one):
47
46
  - Traefik v3 with CRDs installed
@@ -89,8 +88,8 @@ CLUSTER_ISSUER=letsencrypt-prod
89
88
  PLONE_BACKEND_IMAGE=plone/plone-backend:6.1.3
90
89
  PLONE_FRONTEND_IMAGE=plone/plone-frontend:latest
91
90
 
92
- # Database backend: 'bitnami' (default) or 'cloudnativepg'
93
- DATABASE=cloudnativepg
91
+ # Database backend: 'plain' (default) or 'cloudnativepg'
92
+ DATABASE=plain
94
93
  ```
95
94
 
96
95
  ### 3. Generate Kubernetes Manifests
@@ -133,24 +132,24 @@ DATABASE=cloudnativepg
133
132
  - `username` - Database user
134
133
  - `password` - Database password
135
134
 
136
- ### Bitnami PostgreSQL (Development/Testing)
135
+ ### Plain PostgreSQL (default, operator-free)
137
136
 
138
137
  **Pros:**
139
- - No operator required
140
- - Simple setup
141
- - Good for development and testing
142
- - Helm-based deployment
138
+ - No operator and no third-party Helm chart required
139
+ - Uses the official `postgres` image, which is actively maintained
140
+ - Single-instance StatefulSet with a PersistentVolumeClaim
141
+ - Good for development and small production setups
143
142
 
144
143
  **Cons:**
145
- - Requires namespace `plone` to be pre-created
146
- - No built-in HA features
147
- - Less suitable for production
144
+ - No built-in high availability, failover, or automated backups
148
145
 
149
146
  **Configuration:**
150
147
  ```bash
151
- DATABASE=bitnami
148
+ DATABASE=plain
152
149
  ```
153
150
 
151
+ **Secrets:** the example creates a Secret with `username`, `password`, and `database` keys.
152
+
154
153
  ## Architecture
155
154
 
156
155
  ```
@@ -266,13 +265,11 @@ kubectl get cluster plone-postgresql
266
265
  kubectl get secret plone-postgresql-app -o yaml
267
266
  ```
268
267
 
269
- **Bitnami:**
268
+ **Plain PostgreSQL:**
270
269
  ```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
270
+ # Check the StatefulSet and pod
271
+ kubectl get statefulset -l app.kubernetes.io/name=plone-postgresql
272
+ kubectl get pods -l app.kubernetes.io/name=plone-postgresql
276
273
  ```
277
274
 
278
275
  ### Access Logs