kubectl apply --server-side -f  https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.28/releases/cnpg-1.28.0.yaml--force-conflicts
curl -sSfL  https://github.com/cloudnative-pg/cloudnative-pg/raw/main/hack/install-cnpg-plugin.sh |  sudo sh -s -- -b /usr/local/bin

kubectl apply -f \
        https://github.com/cloudnative-pg/plugin-barman-cloud/releases/download/v0.13.0/manifest.yaml

kubectl create namespace database


database.yaml:

---
apiVersion: v1
kind: Secret
metadata:
  name: pg-app-user
  namespace: demo-apps
type: kubernetes.io/basic-auth
stringData:
  username: admin
  password: admin
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: pg-test
  namespace: demo-apps
spec:
  instances: 3
 
  storage:
    size: 1Gi
    storageClass: csi-rbdfs-sc
  
  walStorage:
    storageClass: csi-rbdfs-sc
    size: 1Gi	

  bootstrap:
    initdb:
      database: testdb
      owner: admin
      secret:
        name: pg-app-user

  postgresql:
    parameters:
      max_connections: "300"
      shared_buffers: "1GB"

  resources:
    requests:
      cpu: "500m"
      memory: "1Gi"
    limits:
      cpu: "2"
      memory: "2Gi"


#test
kubectl run psql-client -n database --rm -it --image=postgres:16 --env="PGPASSWORD=admin" -- psql -h pg-test-rw.demo-apps.svc -U admin -d appdb

kubectl patch pvc pg-test-1-wal -n demo_apps -p '{"spec":{"resources":{"requests":{"storage":"32Gi"}}}}'

backup:
  barmanObjectStore:
    destinationPath: s3://pg-backups/prod
    endpointURL: http://minio.minio.svc:9000
    s3Credentials:
      accessKeyId:
        name: s3-creds
        key: ACCESS_KEY
      secretAccessKey:
        name: s3-creds
        key: SECRET_KEY




--- pgadmin -------------------
apiVersion: v1
kind: ConfigMap
metadata:
  name: pgadmin-servers
data:
  servers.json: |
    {
      "Servers": {
        "1": {
          "Name": "pg-test-rw",
          "Group": "Servers",
          "Host": "leodeancluster-rw.leodean-dev.svc.cluster.local",
          "Port": 5432,
          "MaintenanceDB": "leodean",
          "Username": "leodeanAdmin",
          "SSLMode": "disable"
        }
      }
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pgadmin-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pgadmin
  template:
    metadata:
      labels:
        app: pgadmin
    spec:
      containers:
        - name: pgadmin
          image: dpage/pgadmin4
          ports:
            - containerPort: 80
          env:
            - name: PGADMIN_DEFAULT_EMAIL
              value: pgadmin@italiadatacenter.com
            - name: PGADMIN_DEFAULT_PASSWORD
              value: KAYQE1QA7uwUZ8uI
            - name: PGADMIN_SERVER_JSON_FILE
              value: /pgadmin4/servers.json
          volumeMounts:
            - name: pgadmin-servers-json
              mountPath: /pgadmin4/servers.json
              subPath: servers.json
              readOnly: true
      volumes:
        - name: pgadmin-servers-json
          configMap:
            name: pgadmin-servers
---
apiVersion: v1
kind: Service
metadata:
  name: pgadmin-service
spec:
  selector:
    app: pgadmin
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: demo-route
  namespace: demo-apps
spec:
  hostnames:
  - poc3.italiadatacenter.com
  parentRefs:
  - name: main-gateway
    namespace: nginx-gateway
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: pgadmin-service
      port: 80

	  
	  
	  
	  
--------------------------------------------------------------------------------	  

cat <<EOF | kubectl -n database apply -f -
# This StorageClass is optimized for use with CloudNativePG.
# It disables storage-level replication and ensures data is local to the pod.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: longhorn-cnpg-strict-local
provisioner: driver.longhorn.io
 # allowVolumeExpansion is crucial for scaling database storage without downtime.
allowVolumeExpansion: true
 # reclaimPolicy: Delete ensures that when a PVC is deleted, the underlying
 # Longhorn volume is also removed, preventing orphaned storage.
reclaimPolicy: Delete
parameters:
  # This is the most important setting. We rely on CloudNativePG for replication,
  # so we only need one copy at the storage layer to avoid write amplification.
  numberOfReplicas: "1"
  # dataLocality: strict-local guarantees that the volume data will be stored
  # on the same node as the pod that uses it. This is essential for performance
  # and for aligning with a true shared-nothing architecture.
  dataLocality: "strict-local"
  # A longer timeout for stale replicas is suitable for database workloads.
  staleReplicaTimeout: "2880" # 48 hours in minutes
  # Default filesystem.
  fsType: "ext4"
EOF
 
 



kubectl cnpg psql pg-devops -n devops

CREATE DATABASE giteadb;
CREATE USER gitea WITH PASSWORD 'KAYQE1QA7uwUZ8uI';
GRANT ALL PRIVILEGES ON DATABASE giteadb TO gitea;
ALTER DATABASE giteadb OWNER TO gitea;


cluster production ready:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: mycluster
  namespace: database
spec:
  instances: 3                  # → 3 nodi per HA reale

  primaryUpdateStrategy: unsupervised  
  failover:                     # → Failover automatico
    promoteTimeout: 5m
    targetPromotionRule: "prefer-high-promotion-score"

  # ---------------------------
  # STORAGE (PRODUCTION)
  # ---------------------------
  storage:
    size: 200Gi
    storageClass: fast-rbd     # Ceph, SSD, GP3 ecc.
    resizeInUse: true

  walStorage:                   # Consigliato in produzione
    size: 50Gi
    storageClass: fast-rbd

  # ---------------------------
  # WAL ARCHIVING (S3/MINIO)
  # ---------------------------
  walArchive:
    enabled: true
    destinationPath: "s3://mybucket/wal/"
    s3Credentials:
      accessKeyId:
        name: cnpg-s3-creds
        key: ACCESS_KEY_ID
      secretAccessKey:
        name: cnpg-s3-creds
        key: SECRET_ACCESS_KEY
    endpointURL: "https://s3.myregion.amazonaws.com"
    region: "myregion"
    encryption: AES256

  # ---------------------------
  # BACKUP AUTOMATICI
  # ---------------------------
  backup:
    barmanObjectStore:
      destinationPath: "s3://mybucket/basebackup/"
      endpointURL: "https://s3.myregion.amazonaws.com"
      s3Credentials:
        accessKeyId:
          name: cnpg-s3-creds
          key: ACCESS_KEY_ID
        secretAccessKey:
          name: cnpg-s3-creds
          key: SECRET_ACCESS_KEY
      wal:
        compression: bzip2
        encryption: AES256
    retentionPolicy: "30d"  # → 30 giorni di retention
  monitoring:
    enablePodMonitor: true

  # ---------------------------
  # TLS INTERNO (RACCOMANDATO)
  # ---------------------------
  certificates:
    serverTLSSecret: cnpg-server-tls
    clientTLSSecret: cnpg-client-tls

  # ---------------------------
  # RESOURCE MANAGEMENT
  # ---------------------------
  resources:
    requests:
      cpu: "1"
      memory: "2Gi"
    limits:
      cpu: "4"
      memory: "8Gi"

  # ---------------------------
  # ANTI-AFFINITY & PDB
  # ---------------------------
  affinity:
    enablePodAntiAffinity: true
    topologyKey: "kubernetes.io/hostname"

  podDisruptionBudget:
    minAvailable: 2

  # ---------------------------
  # STARTUP & HEALTH
  # ---------------------------
  postgresql:
    shared_preload_libraries:
      - "pg_stat_statements"
      - "auto_explain"
    parameters:
      max_connections: "300"
      shared_buffers: "2GB"
      effective_cache_size: "6GB"
      maintenance_work_mem: "512MB"
      wal_compression: "on"
      wal_level: "replica"
      max_wal_size: "4GB"
      checkpoint_timeout: "15min"
      synchronous_commit: "remote_apply"

  # ---------------------------
  # SYNCHRONOUS REPLICATION
  # ---------------------------
  replication:
    synchronous:
      mode: " quorum "
      number: 1   # One sync replica; others async

  # ---------------------------
  # SERVICE & NETWORKING
  # ---------------------------
  service:
    type: ClusterIP
    primary:
      type: ClusterIP
    replicas:
      type: ClusterIP

  # ---------------------------
  # ENCRYPTION AT REST (OPZIONALE)
  # ---------------------------
  encryption:
    enabled: true
    mode: aes256-gcm