Skip to content

Commit efaa16f

Browse files
authored
add cloudnativepg example integration guide (#443)
1 parent 51185d9 commit efaa16f

3 files changed

Lines changed: 384 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: 382 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
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+
storage:
153+
size: 1Gi
154+
bootstrap:
155+
initdb:
156+
secret:
157+
name: cluster-example-app-credentials
158+
EOF
159+
```
160+
161+
### Wait for Provisioning
162+
163+
The kube-bind konnector and the CloudNativePG operator should now be busy provisioning your
164+
database. You can observe the provisioned database and connection Secret in the provider cluster:
165+
166+
```bash
167+
kubectl -n kube-bind-xbrxn-default get clusters
168+
169+
NAME AGE INSTANCES READY STATUS PRIMARY
170+
cluster-example 22m 3 3 Cluster in healthy state cluster-example-1
171+
```
172+
173+
```bash
174+
kubectl -n kube-bind-xbrxn-default get clusters cluster-example -o yaml
175+
```
176+
177+
```yaml
178+
apiVersion: postgresql.cnpg.io/v1
179+
kind: Cluster
180+
metadata:
181+
annotations:
182+
kube-bind.io/cluster-namespace: kube-bind-xbrxn
183+
kubectl.kubernetes.io/last-applied-configuration: |
184+
{"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"}}}
185+
creationTimestamp: "2026-01-22T10:13:57Z"
186+
generation: 1
187+
name: cluster-example
188+
namespace: kube-bind-xbrxn-default
189+
resourceVersion: "4329"
190+
uid: a8949c70-c3b7-417f-9191-fb43cbd2d667
191+
spec:
192+
affinity:
193+
podAntiAffinityType: preferred
194+
bootstrap:
195+
initdb:
196+
database: app
197+
encoding: UTF8
198+
localeCType: C
199+
localeCollate: C
200+
owner: app
201+
secret:
202+
name: cluster-example-app-credentials
203+
enablePDB: true
204+
enableSuperuserAccess: false
205+
failoverDelay: 0
206+
imageName: ghcr.io/cloudnative-pg/postgresql:18.1-system-trixie
207+
instances: 3
208+
logLevel: info
209+
maxSyncReplicas: 0
210+
minSyncReplicas: 0
211+
monitoring:
212+
customQueriesConfigMap:
213+
- key: queries
214+
name: cnpg-default-monitoring
215+
disableDefaultQueries: false
216+
enablePodMonitor: false
217+
postgresGID: 26
218+
postgresUID: 26
219+
postgresql:
220+
parameters:
221+
archive_mode: "on"
222+
archive_timeout: 5min
223+
dynamic_shared_memory_type: posix
224+
full_page_writes: "on"
225+
log_destination: csvlog
226+
log_directory: /controller/log
227+
log_filename: postgres
228+
log_rotation_age: "0"
229+
log_rotation_size: "0"
230+
log_truncate_on_rotation: "false"
231+
logging_collector: "on"
232+
max_parallel_workers: "32"
233+
max_replication_slots: "32"
234+
max_worker_processes: "32"
235+
shared_memory_type: mmap
236+
shared_preload_libraries: ""
237+
ssl_max_protocol_version: TLSv1.3
238+
ssl_min_protocol_version: TLSv1.3
239+
wal_keep_size: 512MB
240+
wal_level: logical
241+
wal_log_hints: "on"
242+
wal_receiver_timeout: 5s
243+
wal_sender_timeout: 5s
244+
syncReplicaElectionConstraint:
245+
enabled: false
246+
primaryUpdateMethod: restart
247+
primaryUpdateStrategy: unsupervised
248+
probes:
249+
liveness:
250+
isolationCheck:
251+
connectionTimeout: 1000
252+
enabled: true
253+
requestTimeout: 1000
254+
replicationSlots:
255+
highAvailability:
256+
enabled: true
257+
slotPrefix: _cnpg_
258+
synchronizeReplicas:
259+
enabled: true
260+
updateInterval: 30
261+
resources: {}
262+
smartShutdownTimeout: 180
263+
startDelay: 3600
264+
stopDelay: 1800
265+
storage:
266+
resizeInUseVolumes: true
267+
size: 1Gi
268+
switchoverDelay: 3600
269+
status:
270+
availableArchitectures:
271+
- goArch: amd64
272+
hash: 527e2e3b680dfba7f7578b98530f755f36156e7be00acda3318ef36fe4f4418f
273+
- goArch: arm64
274+
hash: aaa74c6061f3fe30f230a664b4f6076bb886c9a89d4eba3293483525c5cff533
275+
certificates:
276+
clientCASecret: cluster-example-ca
277+
expirations:
278+
cluster-example-ca: 2026-04-22 10:08:57 +0000 UTC
279+
cluster-example-replication: 2026-04-22 10:08:57 +0000 UTC
280+
cluster-example-server: 2026-04-22 10:08:57 +0000 UTC
281+
replicationTLSSecret: cluster-example-replication
282+
serverAltDNSNames:
283+
- cluster-example-rw
284+
- cluster-example-rw.kube-bind-xbrxn-default
285+
- cluster-example-rw.kube-bind-xbrxn-default.svc
286+
- cluster-example-rw.kube-bind-xbrxn-default.svc.cluster.local
287+
- cluster-example-r
288+
- cluster-example-r.kube-bind-xbrxn-default
289+
- cluster-example-r.kube-bind-xbrxn-default.svc
290+
- cluster-example-r.kube-bind-xbrxn-default.svc.cluster.local
291+
- cluster-example-ro
292+
- cluster-example-ro.kube-bind-xbrxn-default
293+
- cluster-example-ro.kube-bind-xbrxn-default.svc
294+
- cluster-example-ro.kube-bind-xbrxn-default.svc.cluster.local
295+
serverCASecret: cluster-example-ca
296+
serverTLSSecret: cluster-example-server
297+
cloudNativePGCommitHash: a9696201f
298+
cloudNativePGOperatorHash: 527e2e3b680dfba7f7578b98530f755f36156e7be00acda3318ef36fe4f4418f
299+
conditions:
300+
- lastTransitionTime: "2026-01-22T10:30:08Z"
301+
message: A single, unique system ID was found across reporting instances.
302+
reason: Unique
303+
status: "True"
304+
type: ConsistentSystemID
305+
- lastTransitionTime: "2026-01-22T10:31:06Z"
306+
message: Cluster is Ready
307+
reason: ClusterIsReady
308+
status: "True"
309+
type: Ready
310+
- lastTransitionTime: "2026-01-22T10:30:08Z"
311+
message: Continuous archiving is working
312+
reason: ContinuousArchivingSuccess
313+
status: "True"
314+
type: ContinuousArchiving
315+
configMapResourceVersion:
316+
metrics:
317+
cnpg-default-monitoring: "2120"
318+
currentPrimary: cluster-example-1
319+
currentPrimaryTimestamp: "2026-01-22T10:30:07.986099Z"
320+
healthyPVC:
321+
- cluster-example-1
322+
- cluster-example-2
323+
- cluster-example-3
324+
image: ghcr.io/cloudnative-pg/postgresql:18.1-system-trixie
325+
instanceNames:
326+
- cluster-example-1
327+
- cluster-example-2
328+
- cluster-example-3
329+
instances: 3
330+
instancesReportedState:
331+
cluster-example-1:
332+
ip: 10.244.0.21
333+
isPrimary: true
334+
timeLineID: 1
335+
cluster-example-2:
336+
ip: 10.244.0.24
337+
isPrimary: false
338+
timeLineID: 1
339+
cluster-example-3:
340+
ip: 10.244.0.27
341+
isPrimary: false
342+
timeLineID: 1
343+
instancesStatus:
344+
healthy:
345+
- cluster-example-1
346+
- cluster-example-2
347+
- cluster-example-3
348+
latestGeneratedNode: 3
349+
managedRolesStatus: {}
350+
pgDataImageInfo:
351+
image: ghcr.io/cloudnative-pg/postgresql:18.1-system-trixie
352+
majorVersion: 18
353+
phase: Cluster in healthy state
354+
poolerIntegrations:
355+
pgBouncerIntegration: {}
356+
pvcCount: 3
357+
readService: cluster-example-r
358+
readyInstances: 3
359+
secretsResourceVersion:
360+
applicationSecretVersion: "3969"
361+
clientCaSecretVersion: "2089"
362+
replicationSecretVersion: "2092"
363+
serverCaSecretVersion: "2089"
364+
serverSecretVersion: "2090"
365+
switchReplicaClusterStatus: {}
366+
systemID: "7598131281368047651"
367+
targetPrimary: cluster-example-1
368+
targetPrimaryTimestamp: "2026-01-22T10:13:58.221403Z"
369+
timelineID: 1
370+
topology:
371+
instances:
372+
cluster-example-1: {}
373+
cluster-example-2: {}
374+
cluster-example-3: {}
375+
nodesUsed: 1
376+
successfullyExtracted: true
377+
writeService: cluster-example-rw
378+
```
379+
380+
---
381+
382+
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)