--- apiVersion: v1 kind: Namespace metadata: name: db --- # Password secret (replace with your own or generate one) apiVersion: v1 kind: Secret metadata: name: pg18-secret namespace: db type: Opaque stringData: POSTGRES_PASSWORD: "pa$$word" --- # Init SQL: keeps your original name and keeps enabling PostGIS + vector apiVersion: v1 kind: ConfigMap metadata: name: pg-init-sql namespace: db data: 00_extensions.sql: | -- enable common extensions in the default DB and template1 so future DBs inherit them \connect gitea CREATE EXTENSION IF NOT EXISTS postgis; CREATE EXTENSION IF NOT EXISTS vector; CREATE COLLATION IF NOT EXISTS arabic (provider = icu, locale = 'ar', deterministic = false); CREATE EXTENSION IF NOT EXISTS tablefunc; -- postpone pg_stat_statements CREATE to postStart (needs preload) CREATE EXTENSION IF NOT EXISTS postgis_topology; CREATE EXTENSION IF NOT EXISTS fuzzystrmatch; CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE EXTENSION IF NOT EXISTS hstore; CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS citext; CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pgcrypto; -- PL/Python (available in your image) DO $$ BEGIN CREATE EXTENSION IF NOT EXISTS plpython3u; EXCEPTION WHEN undefined_file THEN RAISE NOTICE 'plpython3u not available in this image'; END $$; -- Also on template1 for new DBs (heavier, but intentional) \connect template1 CREATE EXTENSION IF NOT EXISTS postgis; CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE EXTENSION IF NOT EXISTS hstore; CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS citext; CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pgcrypto; -- Arabic-friendly ICU collation, non-deterministic for case/diacritics DO $$ BEGIN PERFORM 1 FROM pg_collation WHERE collname='arabic'; IF NOT FOUND THEN CREATE COLLATION arabic (provider = icu, locale = 'ar', deterministic = false); END IF; END$$; 01_tune.sql: | -- Enable pg_stat_statements on next server start DO $$ DECLARE cur text := current_setting('shared_preload_libraries', true); BEGIN IF cur IS NULL OR position('pg_stat_statements' in cur) = 0 THEN PERFORM pg_catalog.pg_reload_conf(); -- harmless even if no changes yet EXECUTE $$ALTER SYSTEM SET shared_preload_libraries = $$ || quote_literal(coalesce(NULLIF(cur,'' ) || ',pg_stat_statements', 'pg_stat_statements')); END IF; END$$; -- Optional tuning (adjust to your limits) ALTER SYSTEM SET shared_buffers = '1GB'; ALTER SYSTEM SET work_mem = '32MB'; ALTER SYSTEM SET maintenance_work_mem = '512MB'; ALTER SYSTEM SET max_connections = 200; -- Reload applies some settings immediately; others need restart (OK after init completes) SELECT pg_reload_conf(); ALTER SYSTEM SET pg_stat_statements.max = 10000; ALTER SYSTEM SET pg_stat_statements.track = 'all'; ALTER SYSTEM SET pg_stat_statements.save = on; pg_hba.conf: | # Allow loopback local all all trust host all all 127.0.0.1/32 trust host all all ::1/128 trust # Allow TLS connections from your IP(s) only hostssl all all YOUR_PUBLIC_IP/32 md5 # (Optional) Add more CIDRs or a private network range here: # hostssl all all 10.0.0.0/8 md5 --- # Headless service required by StatefulSet for stable network IDs apiVersion: v1 kind: Service metadata: name: postgres-hl namespace: db spec: clusterIP: None selector: app: postgres ports: - name: postgres port: 5432 targetPort: 5432 --- # Regular ClusterIP service for clients (keeps your original name) apiVersion: v1 kind: Service metadata: name: postgres namespace: db spec: selector: app: postgres ports: - name: postgres port: 5432 targetPort: 5432 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: postgres namespace: db spec: serviceName: postgres-hl replicas: 1 selector: matchLabels: app: postgres template: metadata: labels: app: postgres spec: securityContext: runAsUser: 999 runAsGroup: 999 fsGroup: 999 fsGroupChangePolicy: "Always" initContainers: # Copy cert-manager certs to a writable path with correct perms for Postgres - name: install-certs image: busybox:1.36 command: - sh - -c - | cp /in/tls.crt /out/server.crt cp /in/tls.key /out/server.key cp /in/ca.crt /out/ca.crt || true chown 999:999 /out/* || true chmod 600 /out/server.key securityContext: runAsUser: 0 volumeMounts: - { name: pg-tls, mountPath: /in, readOnly: true } - { name: pg-certs, mountPath: /out } containers: - name: postgres image: axxs/postgres:18-postgis-vector imagePullPolicy: IfNotPresent args: - -c - ssl=on - -c - ssl_cert_file=/certs/server.crt - -c - ssl_key_file=/certs/server.key - -c - ssl_ca_file=/certs/ca.crt - -c - hba_file=/etc/postgresql-custom/pg_hba.conf lifecycle: postStart: exec: command: - /bin/sh - -c - | set -e # Wait until server accepts connections for i in $(seq 1 30); do pg_isready -h 127.0.0.1 -U "$POSTGRES_USER" -d "$POSTGRES_DB" && break sleep 1 done psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "CREATE EXTENSION IF NOT EXISTS pg_stat_statements;" env: - name: POSTGRES_USER value: "app" - name: POSTGRES_DB value: "gitea" # matches your \connect gitea - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: pg18-secret key: POSTGRES_PASSWORD - name: TZ value: "Europe/Paris" ports: - name: postgres containerPort: 5432 volumeMounts: # ✅ PG 18 requires this parent path; it will create /var/lib/postgresql/18/main - name: data mountPath: /var/lib/postgresql # your init scripts ConfigMap - name: init mountPath: /docker-entrypoint-initdb.d readOnly: true - name: pg-certs mountPath: /certs # pg_hba.conf - name: pg-conf mountPath: /etc/postgresql-custom readinessProbe: exec: command: - /bin/sh - -c - pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" -h 127.0.0.1 initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 6 livenessProbe: exec: command: - /bin/sh - -c - pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" -h 127.0.0.1 initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 6 resources: requests: cpu: "250m" memory: "512Mi" limits: cpu: "1" memory: "2Gi" volumes: - name: init configMap: name: pg-init-sql defaultMode: 0444 - name: pg-tls secret: secretName: pg-tls - name: pg-certs emptyDir: {} - name: pg-conf configMap: name: pg-conf defaultMode: 0444 volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 10Gi # storageClassName: # optionally pin this