@bluedynamics/cdk8s-plone 0.1.43 → 0.1.45
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.
- package/.jsii +25 -24
- package/API.md +6 -2
- package/README.md +3 -3
- package/documentation/sources/conf.py +55 -29
- package/documentation/sources/explanation/architecture.md +14 -16
- package/documentation/sources/explanation/cdk8s-workflow.md +66 -0
- package/documentation/sources/explanation/index.md +1 -27
- package/documentation/sources/how-to/backup-and-restore.md +107 -0
- package/documentation/sources/how-to/configure-env-and-secrets.md +184 -0
- package/documentation/sources/how-to/configure-ingress-tls.md +108 -0
- package/documentation/sources/how-to/configure-security-context.md +0 -5
- package/documentation/sources/how-to/deploy-blicca.md +8 -8
- package/documentation/sources/how-to/{deploy-production-volto.md → deploy-volto.md} +20 -25
- package/documentation/sources/how-to/deploy-with-httpcache.md +224 -0
- package/documentation/sources/how-to/deploy-with-vinyl-cache.md +0 -5
- package/documentation/sources/how-to/enable-prometheus-monitoring.md +4 -5
- package/documentation/sources/how-to/index.md +15 -8
- package/documentation/sources/how-to/scale-and-high-availability.md +122 -0
- package/documentation/sources/how-to/schedule-pods.md +0 -5
- package/documentation/sources/how-to/troubleshooting.md +113 -0
- package/documentation/sources/how-to/upgrade-and-rollout.md +89 -0
- package/documentation/sources/index.md +3 -11
- package/documentation/sources/reference/api/index.md +6 -4
- package/documentation/sources/reference/configuration-options.md +85 -516
- package/documentation/sources/reference/index.md +16 -43
- package/documentation/sources/tutorials/01-quick-start.md +1 -1
- package/documentation/sources/tutorials/index.md +7 -11
- package/examples/blicca/.env.example +3 -2
- package/examples/blicca/README.md +21 -24
- package/examples/blicca/__snapshots__/main.test.ts.snap +138 -345
- package/examples/blicca/main.test.ts +7 -0
- package/examples/blicca/main.ts +8 -7
- package/examples/blicca/postgres.plain.ts +115 -0
- package/examples/blicca/tsconfig.json +33 -0
- package/examples/{production-volto → volto}/.env.example +3 -2
- package/examples/{production-volto → volto}/README.md +20 -23
- package/examples/{production-volto → volto}/__snapshots__/main.test.ts.snap +139 -345
- package/examples/{production-volto → volto}/main.test.ts +7 -0
- package/examples/{production-volto → volto}/main.ts +8 -7
- package/examples/{production-volto → volto}/package.json +1 -1
- package/examples/volto/postgres.plain.ts +115 -0
- package/examples/volto/tsconfig.json +33 -0
- package/lib/httpcache.js +1 -1
- package/lib/imports/vinyl.bluedynamics.eu.d.ts +4011 -53
- package/lib/imports/vinyl.bluedynamics.eu.js +1786 -157
- package/lib/plone.js +1 -1
- package/lib/vinylcache.d.ts +3 -1
- package/lib/vinylcache.js +3 -2
- package/package.json +6 -6
- package/documentation/sources/_static/brand-theme.css +0 -685
- package/documentation/sources/_static/custom-icons.css +0 -123
- package/documentation/sources/_static/fonts/hack/Hack-Regular.woff2 +0 -0
- package/documentation/sources/_static/fonts/orbitron/Orbitron-Black.woff2 +0 -11
- package/documentation/sources/_static/fonts/orbitron/Orbitron-Bold.woff2 +0 -11
- package/documentation/sources/_static/fonts/orbitron/Orbitron-Regular.woff2 +0 -0
- package/documentation/sources/_static/fonts/rajdhani/Rajdhani-Bold.woff2 +0 -11
- package/documentation/sources/_static/fonts/rajdhani/Rajdhani-Medium.woff2 +0 -11
- package/documentation/sources/_static/fonts/rajdhani/Rajdhani-Regular.woff2 +0 -11
- package/documentation/sources/_static/fonts/rajdhani/Rajdhani-SemiBold.woff2 +0 -11
- package/documentation/sources/_static/kup6s-icon-explanation.svg +0 -32
- package/documentation/sources/_static/kup6s-icon-howto.svg +0 -34
- package/documentation/sources/_static/kup6s-icon-reference.svg +0 -34
- package/documentation/sources/_static/kup6s-icon-tutorials.svg +0 -30
- package/documentation/sources/_static/logo-fix.js +0 -12
- package/documentation/sources/reference/api/.gitkeep +0 -1
- package/examples/blicca/postgres.bitnami.ts +0 -49
- package/examples/production-volto/postgres.bitnami.ts +0 -49
- /package/documentation/sources/_static/{kup6s-icon-plone.svg → logo.svg} +0 -0
- /package/examples/{production-volto → volto}/cdk8s.yaml +0 -0
- /package/examples/{production-volto → volto}/config/varnish.tpl.vcl +0 -0
- /package/examples/{production-volto → volto}/ingress.ts +0 -0
- /package/examples/{production-volto → volto}/jest.config.js +0 -0
- /package/examples/{production-volto → volto}/postgres.cloudnativepg.ts +0 -0
package/examples/blicca/main.ts
CHANGED
|
@@ -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 {
|
|
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:
|
|
20
|
+
let db: PGPlainChart | PGCloudNativePGChart;
|
|
21
21
|
let postgresql_username;
|
|
22
22
|
let postgresql_password;
|
|
23
|
-
if ((process.env.DATABASE ?? '
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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: '
|
|
20
|
-
|
|
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
|
-
#
|
|
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
|
|
39
|
-
- **
|
|
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: '
|
|
93
|
-
DATABASE=
|
|
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
|
-
###
|
|
135
|
+
### Plain PostgreSQL (default, operator-free)
|
|
137
136
|
|
|
138
137
|
**Pros:**
|
|
139
|
-
- No operator required
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
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
|
-
-
|
|
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=
|
|
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
|
-
**
|
|
268
|
+
**Plain PostgreSQL:**
|
|
270
269
|
```bash
|
|
271
|
-
# Check
|
|
272
|
-
kubectl get
|
|
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
|