276 lines
8.4 KiB
YAML
276 lines
8.4 KiB
YAML
---
|
|
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: <your-storageclass> # optionally pin this
|