# CNPG (CloudNative PostgreSQL)

Production-grade PostgreSQL operator. **Application Blueprint** (see [`docs/PLATFORM-TECH-STACK.md`](../../docs/PLATFORM-TECH-STACK.md) §4.1 — Data services). Used by Organizations that want managed Postgres; also the underlying engine for FerretDB (MongoDB-compatible) and Gitea metadata. Replication via WAL streaming to async standby (Application-tier choice).

**Status:** Accepted | **Updated:** 2026-04-27

---

## Overview

CloudNative PostgreSQL (CNPG) provides production-grade PostgreSQL with:
- Kubernetes-native operator
- WAL streaming for multi-region DR
- Automated backups to SeaweedFS/S3
- High availability with automatic failover

---

## Architecture

### Single Region

```mermaid
flowchart TB
    subgraph Cluster["CNPG Cluster"]
        Primary[Primary]
        Replica1[Replica 1]
        Replica2[Replica 2]
    end

    subgraph Backup["Backup"]
        SeaweedFS[SeaweedFS]
    end

    Primary -->|"WAL Stream"| Replica1
    Primary -->|"WAL Stream"| Replica2
    Primary -->|"WAL Archive"| SeaweedFS
```

### Multi-Region DR

```mermaid
flowchart TB
    subgraph Region1["Region 1 (Primary)"]
        PG1[CNPG Primary]
    end

    subgraph Region2["Region 2 (DR)"]
        PG2[CNPG Standby]
    end

    subgraph Backup["Backup"]
        SeaweedFS[SeaweedFS]
    end

    PG1 -->|"WAL Streaming"| PG2
    PG1 -->|"WAL Archive"| SeaweedFS
    PG2 -->|"WAL Restore"| SeaweedFS
```

---

## Configuration

### Cluster Definition

```yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: <org>-postgres
  namespace: databases
spec:
  instances: 3

  postgresql:
    parameters:
      max_connections: "200"
      shared_buffers: 256MB

  storage:
    size: 10Gi
    storageClass: <storage-class>

  backup:
    barmanObjectStore:
      destinationPath: s3://cnpg-backups/<org>
      endpointURL: http://seaweedfs.storage.svc:8333
      s3Credentials:
        accessKeyId:
          name: seaweedfs-credentials
          key: access-key
        secretAccessKey:
          name: seaweedfs-credentials
          key: secret-key
      wal:
        compression: gzip
    retentionPolicy: "30d"

  monitoring:
    enablePodMonitor: true
```

### DR Replica (Region 2)

```yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: <org>-postgres-dr
  namespace: databases
spec:
  instances: 1

  replica:
    enabled: true
    source: <org>-postgres

  externalClusters:
    - name: <org>-postgres
      connectionParameters:
        host: postgres.<env>.<sovereign-domain>
        user: streaming_replica
      password:
        name: pg-replica-credentials
        key: password
```

---

## Backup Strategy

| Type | Schedule | Retention |
|------|----------|-----------|
| WAL Archive | Continuous | 7 days |
| Base Backup | Daily 2 AM | 30 days |
| Point-in-Time | On-demand | Per backup |

### Scheduled Backup

```yaml
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
  name: <org>-daily-backup
  namespace: databases
spec:
  schedule: "0 2 * * *"
  backupOwnerReference: self
  cluster:
    name: <org>-postgres
```

---

## Failover

### Automatic (Within Region)

CNPG automatically promotes replicas when primary fails.

### Manual (Cross-Region)

```bash
# Promote DR cluster
kubectl cnpg promote <org>-postgres-dr -n databases
```

---

## Monitoring

| Metric | Description |
|--------|-------------|
| `cnpg_pg_replication_lag` | Replication lag in seconds |
| `cnpg_pg_database_size_bytes` | Database size |
| `cnpg_pg_stat_activity_count` | Active connections |

---

## PgBouncer Integration

Connection pooling with PgBouncer:

```yaml
apiVersion: postgresql.cnpg.io/v1
kind: Pooler
metadata:
  name: <org>-pooler
  namespace: databases
spec:
  cluster:
    name: <org>-postgres
  instances: 2
  type: rw
  pgbouncer:
    poolMode: transaction
    parameters:
      max_client_conn: "1000"
      default_pool_size: "20"
```

---

*Part of [OpenOva](https://openova.io)*
