Skip to content

Commit da1f65f

Browse files
committed
add cloudnativepg example integration guide
On-behalf-of: @SAP christoph.mewes@sap.com
1 parent 9b8bd78 commit da1f65f

3 files changed

Lines changed: 386 additions & 1 deletion

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
nav:
22
- cert-manager.md
33
- crossplane.md
4+
- cloudnativepg.md
45
- kro.md
Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
---
2+
title: CloudNativePG
3+
description: |
4+
Guide on integrating kube-bind with CloudNativePG for automated Postgres database management.
5+
weight: 30
6+
---
7+
8+
# CloudNativePG Integration
9+
10+
This document shows how the [CloudNativePG](https://cloudnative-pg.io/) Postgres database operator
11+
can be integrated and provided using kube-bind.
12+
13+
## Setup
14+
15+
The following sections will guide you through the one-time setup that is required for providing
16+
Postgres databases using CloudNativePG and kube-bind.
17+
18+
### Install CloudNativePG
19+
20+
Install CloudNativePG in your Kubernetes cluster, where kube-bind backend is running, if you
21+
haven't already. Follow the [official installation guide](https://cloudnative-pg.io/docs/1.28/installation_upgrade)
22+
in the CloudNativePG documentation. In its simplest form, the installation consists of applying this
23+
manifest:
24+
25+
```bash
26+
kubectl apply \
27+
--server-side \
28+
--filename https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.28/releases/cnpg-1.28.0.yaml
29+
```
30+
31+
### Export the Cluster CRD
32+
33+
To export the `Cluster` CRD in the provider cluster, add the kube-bind export label to it:
34+
35+
```bash
36+
kubectl label crd clusters.postgresql.cnpg.io kube-bind.io/exported=true --overwrite
37+
```
38+
39+
### Create a APIServiceExportTemplate
40+
41+
It's now time to configure kube-bind to export the `clusters` resource. To do so, create a
42+
kube-bind `APIServiceExportTemplate` in the provider cluster like this one:
43+
44+
```yaml
45+
kubectl apply -f - <<EOF
46+
apiVersion: kube-bind.io/v1alpha2
47+
kind: APIServiceExportTemplate
48+
metadata:
49+
labels:
50+
provider: cloudnativepg
51+
name: pg-clusters
52+
spec:
53+
permissionClaims:
54+
- group: ""
55+
resource: secrets
56+
selector:
57+
references:
58+
- resource: clusters
59+
group: postgresql.cnpg.io
60+
jsonPath:
61+
name: 'spec.bootstrap.initdb.secret.name'
62+
resources:
63+
- group: postgresql.cnpg.io
64+
resource: clusters
65+
versions:
66+
- v1
67+
scope: Namespaced
68+
EOF
69+
```
70+
71+
## Usage
72+
73+
Now that everything is set up, users can begin to bind to your backend and begin consuming the new
74+
API.
75+
76+
### Login to kube-bind
77+
78+
```bash
79+
kubectl bind login https://kube-bind.example.com
80+
```
81+
82+
### Request a Binding
83+
84+
Request a binding to the `pg-clusters` template created above. This will allow you to create
85+
`Database` objects in your consumer cluster.
86+
87+
**NB::** Make sure you've set your `KUBECONFIG` to the consumer cluster.
88+
89+
```bash
90+
# you will get redirected to UI to authenticate and pick the template
91+
kubectl bind
92+
```
93+
94+
!!! note
95+
If you're using one of the [dev environments](../../developers/dev-environment/index.md), you
96+
might need to add additional arguments to the `bind` command, like `--konnector-host-alias`.
97+
98+
### Wait for the Binding to be Established
99+
100+
Once the binding is active, you can create `Cluster` object in your consumer cluster,
101+
and you will get `Cluster` objects synced from the provider cluster.
102+
103+
```bash
104+
kubectl bind
105+
🌐 Opening kube-bind UI in your browser...
106+
https://kube-bind.example.com?redirect_url=....
107+
108+
Browser opened successfully
109+
Waiting for binding completion from UI...
110+
(Press Ctrl+C to cancel)
111+
112+
Binding completed successfully!
113+
🔒 Updated secret kube-bind/kubeconfig-zxrdn for host https://kube-bind.example.com, namespace kube-bind-bp52k
114+
🚀 Deploying konnector v0.6.0 to namespace kube-bind.
115+
✅ Created APIServiceBinding pg-clusters-pk5c8 for 1 resources
116+
Created 1 APIServiceBinding(s):
117+
- pg-clusters-pk5c8
118+
Resources bound successfully!
119+
```
120+
121+
### Create a Managed Database
122+
123+
Verify that a `clusters.postgresql.cnpg.io` CRD is synced to the consumer cluster:
124+
125+
```bash
126+
k get crd clusters.postgresql.cnpg.io
127+
NAME CREATED AT
128+
clusters.postgresql.cnpg.io 2025-11-27T14:22:18Z
129+
```
130+
131+
Order a new consumer database instance by creating a Postgres cluster. We need to provide our own
132+
credentials, otherwise the automatically generated credentials on the provider cluster will be
133+
inaccessible to consumers.
134+
135+
```yaml
136+
kubectl apply -f - <<EOF
137+
apiVerson: v1
138+
kind: Secret
139+
metadata:
140+
name: cluster-example-app-credentials
141+
data:
142+
username: bXktYXBwbGljYXRpb24=
143+
password: c3VwZXItc2VjcjN0LXBhc3N3MHJk
144+
145+
---
146+
apiVersion: postgresql.cnpg.io/v1
147+
kind: Cluster
148+
metadata:
149+
name: cluster-example
150+
spec:
151+
instances: 3
152+
153+
storage:
154+
size: 1Gi
155+
156+
bootstrap:
157+
initdb:
158+
secret:
159+
name: cluster-example-app-credentials
160+
EOF
161+
```
162+
163+
### Wait for Provisioning
164+
165+
The kube-bind konnector and the CloudNativePG operator should now be busy provisioning your
166+
database. You can observe the provisioned database and connection Secret in the provider cluster:
167+
168+
```bash
169+
kubectl -n kube-bind-xbrxn-default get clusters
170+
171+
NAME AGE INSTANCES READY STATUS PRIMARY
172+
cluster-example 22m 3 3 Cluster in healthy state cluster-example-1
173+
```
174+
175+
```bash
176+
kubectl -n kube-bind-xbrxn-default get clusters cluster-example -o yaml
177+
```
178+
179+
```yaml
180+
apiVersion: postgresql.cnpg.io/v1
181+
kind: Cluster
182+
metadata:
183+
annotations:
184+
kube-bind.io/cluster-namespace: kube-bind-xbrxn
185+
kubectl.kubernetes.io/last-applied-configuration: |
186+
{"apiVersion":"postgresql.cnpg.io/v1","kind":"Cluster","metadata":{"annotations":{},"name":"cluster-example","namespace":"default"},"spec":{"bootstrap":{"initdb":{"secret":{"name":"cluster-example-app-credentials"}}},"instances":3,"storage":{"size":"1Gi"}}}
187+
creationTimestamp: "2026-01-22T10:13:57Z"
188+
generation: 1
189+
name: cluster-example
190+
namespace: kube-bind-xbrxn-default
191+
resourceVersion: "4329"
192+
uid: a8949c70-c3b7-417f-9191-fb43cbd2d667
193+
spec:
194+
affinity:
195+
podAntiAffinityType: preferred
196+
bootstrap:
197+
initdb:
198+
database: app
199+
encoding: UTF8
200+
localeCType: C
201+
localeCollate: C
202+
owner: app
203+
secret:
204+
name: cluster-example-app-credentials
205+
enablePDB: true
206+
enableSuperuserAccess: false
207+
failoverDelay: 0
208+
imageName: ghcr.io/cloudnative-pg/postgresql:18.1-system-trixie
209+
instances: 3
210+
logLevel: info
211+
maxSyncReplicas: 0
212+
minSyncReplicas: 0
213+
monitoring:
214+
customQueriesConfigMap:
215+
- key: queries
216+
name: cnpg-default-monitoring
217+
disableDefaultQueries: false
218+
enablePodMonitor: false
219+
postgresGID: 26
220+
postgresUID: 26
221+
postgresql:
222+
parameters:
223+
archive_mode: "on"
224+
archive_timeout: 5min
225+
dynamic_shared_memory_type: posix
226+
full_page_writes: "on"
227+
log_destination: csvlog
228+
log_directory: /controller/log
229+
log_filename: postgres
230+
log_rotation_age: "0"
231+
log_rotation_size: "0"
232+
log_truncate_on_rotation: "false"
233+
logging_collector: "on"
234+
max_parallel_workers: "32"
235+
max_replication_slots: "32"
236+
max_worker_processes: "32"
237+
shared_memory_type: mmap
238+
shared_preload_libraries: ""
239+
ssl_max_protocol_version: TLSv1.3
240+
ssl_min_protocol_version: TLSv1.3
241+
wal_keep_size: 512MB
242+
wal_level: logical
243+
wal_log_hints: "on"
244+
wal_receiver_timeout: 5s
245+
wal_sender_timeout: 5s
246+
syncReplicaElectionConstraint:
247+
enabled: false
248+
primaryUpdateMethod: restart
249+
primaryUpdateStrategy: unsupervised
250+
probes:
251+
liveness:
252+
isolationCheck:
253+
connectionTimeout: 1000
254+
enabled: true
255+
requestTimeout: 1000
256+
replicationSlots:
257+
highAvailability:
258+
enabled: true
259+
slotPrefix: _cnpg_
260+
synchronizeReplicas:
261+
enabled: true
262+
updateInterval: 30
263+
resources: {}
264+
smartShutdownTimeout: 180
265+
startDelay: 3600
266+
stopDelay: 1800
267+
storage:
268+
resizeInUseVolumes: true
269+
size: 1Gi
270+
switchoverDelay: 3600
271+
status:
272+
availableArchitectures:
273+
- goArch: amd64
274+
hash: 527e2e3b680dfba7f7578b98530f755f36156e7be00acda3318ef36fe4f4418f
275+
- goArch: arm64
276+
hash: aaa74c6061f3fe30f230a664b4f6076bb886c9a89d4eba3293483525c5cff533
277+
certificates:
278+
clientCASecret: cluster-example-ca
279+
expirations:
280+
cluster-example-ca: 2026-04-22 10:08:57 +0000 UTC
281+
cluster-example-replication: 2026-04-22 10:08:57 +0000 UTC
282+
cluster-example-server: 2026-04-22 10:08:57 +0000 UTC
283+
replicationTLSSecret: cluster-example-replication
284+
serverAltDNSNames:
285+
- cluster-example-rw
286+
- cluster-example-rw.kube-bind-xbrxn-default
287+
- cluster-example-rw.kube-bind-xbrxn-default.svc
288+
- cluster-example-rw.kube-bind-xbrxn-default.svc.cluster.local
289+
- cluster-example-r
290+
- cluster-example-r.kube-bind-xbrxn-default
291+
- cluster-example-r.kube-bind-xbrxn-default.svc
292+
- cluster-example-r.kube-bind-xbrxn-default.svc.cluster.local
293+
- cluster-example-ro
294+
- cluster-example-ro.kube-bind-xbrxn-default
295+
- cluster-example-ro.kube-bind-xbrxn-default.svc
296+
- cluster-example-ro.kube-bind-xbrxn-default.svc.cluster.local
297+
serverCASecret: cluster-example-ca
298+
serverTLSSecret: cluster-example-server
299+
cloudNativePGCommitHash: a9696201f
300+
cloudNativePGOperatorHash: 527e2e3b680dfba7f7578b98530f755f36156e7be00acda3318ef36fe4f4418f
301+
conditions:
302+
- lastTransitionTime: "2026-01-22T10:30:08Z"
303+
message: A single, unique system ID was found across reporting instances.
304+
reason: Unique
305+
status: "True"
306+
type: ConsistentSystemID
307+
- lastTransitionTime: "2026-01-22T10:31:06Z"
308+
message: Cluster is Ready
309+
reason: ClusterIsReady
310+
status: "True"
311+
type: Ready
312+
- lastTransitionTime: "2026-01-22T10:30:08Z"
313+
message: Continuous archiving is working
314+
reason: ContinuousArchivingSuccess
315+
status: "True"
316+
type: ContinuousArchiving
317+
configMapResourceVersion:
318+
metrics:
319+
cnpg-default-monitoring: "2120"
320+
currentPrimary: cluster-example-1
321+
currentPrimaryTimestamp: "2026-01-22T10:30:07.986099Z"
322+
healthyPVC:
323+
- cluster-example-1
324+
- cluster-example-2
325+
- cluster-example-3
326+
image: ghcr.io/cloudnative-pg/postgresql:18.1-system-trixie
327+
instanceNames:
328+
- cluster-example-1
329+
- cluster-example-2
330+
- cluster-example-3
331+
instances: 3
332+
instancesReportedState:
333+
cluster-example-1:
334+
ip: 10.244.0.21
335+
isPrimary: true
336+
timeLineID: 1
337+
cluster-example-2:
338+
ip: 10.244.0.24
339+
isPrimary: false
340+
timeLineID: 1
341+
cluster-example-3:
342+
ip: 10.244.0.27
343+
isPrimary: false
344+
timeLineID: 1
345+
instancesStatus:
346+
healthy:
347+
- cluster-example-1
348+
- cluster-example-2
349+
- cluster-example-3
350+
latestGeneratedNode: 3
351+
managedRolesStatus: {}
352+
pgDataImageInfo:
353+
image: ghcr.io/cloudnative-pg/postgresql:18.1-system-trixie
354+
majorVersion: 18
355+
phase: Cluster in healthy state
356+
poolerIntegrations:
357+
pgBouncerIntegration: {}
358+
pvcCount: 3
359+
readService: cluster-example-r
360+
readyInstances: 3
361+
secretsResourceVersion:
362+
applicationSecretVersion: "3969"
363+
clientCaSecretVersion: "2089"
364+
replicationSecretVersion: "2092"
365+
serverCaSecretVersion: "2089"
366+
serverSecretVersion: "2090"
367+
switchReplicaClusterStatus: {}
368+
systemID: "7598131281368047651"
369+
targetPrimary: cluster-example-1
370+
targetPrimaryTimestamp: "2026-01-22T10:13:58.221403Z"
371+
timelineID: 1
372+
topology:
373+
instances:
374+
cluster-example-1: {}
375+
cluster-example-2: {}
376+
cluster-example-3: {}
377+
nodesUsed: 1
378+
successfullyExtracted: true
379+
writeService: cluster-example-rw
380+
```
381+
382+
---
383+
384+
For troubleshooting and more information, check the [kube-bind documentation](https://kube-bind.io/docs/).

docs/mkdocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
site_name: docs.kube-bind.io
1+
site_name: kube-bind
22
repo_url: https://github.com/kube-bind/kube-bind
33
repo_name: kube-bind/kube-bind
44
site_url: https://docs.kube-bind.io/

0 commit comments

Comments
 (0)