From 5067b604f6e5be30f3233a15d98af997332bfff9 Mon Sep 17 00:00:00 2001 From: Jun-te Kim Date: Sun, 28 Dec 2025 12:58:07 +0000 Subject: [PATCH] added produciton db --- db/.gitignore | 1 + db/atlas/atlas.hcl | 6 +- .../migrations/0004_login_tokens.sql | 7 ++ db/atlas/stripe_invoice/migrations/atlas.sum | 3 +- db/k8s/backups/pg-backup-cronjob.yaml | 49 +++++++- ...ml => postgres-dev-stripe-to-invoice.yaml} | 2 +- .../postgres-prod-stripe-to-invoice.yaml | 111 ++++++++++++++++++ 7 files changed, 169 insertions(+), 10 deletions(-) create mode 100644 db/.gitignore create mode 100644 db/atlas/stripe_invoice/migrations/0004_login_tokens.sql rename db/k8s/postgres/{deployment.yaml => postgres-dev-stripe-to-invoice.yaml} (99%) create mode 100644 db/k8s/postgres/postgres-prod-stripe-to-invoice.yaml diff --git a/db/.gitignore b/db/.gitignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/db/.gitignore @@ -0,0 +1 @@ +.env \ No newline at end of file diff --git a/db/atlas/atlas.hcl b/db/atlas/atlas.hcl index d2d7dfe..a2c53d8 100644 --- a/db/atlas/atlas.hcl +++ b/db/atlas/atlas.hcl @@ -1,5 +1,5 @@ env "stripe_invoice_dev" { - url = "postgres://${getenv("POSTGRES_USER")}:${getenv("POSTGRES_PASSWORD")}@postgres.default.svc.cluster.local:5432/stripe_invoice?sslmode=disable" + url = "postgres://${getenv("POSTGRES_USER")}:${getenv("POSTGRES_PASSWORD")}@postgres-dev.default.svc.cluster.local:5432/stripe_invoice?sslmode=disable" migration { dir = "file://./db/atlas/stripe_invoice/migrations" @@ -7,9 +7,11 @@ env "stripe_invoice_dev" { } env "stripe_invoice_prod" { - url = "postgres://${getenv("POSTGRES_USER")}:${getenv("POSTGRES_PASSWORD")}@postgres.default.svc.cluster.local:5432/stripe_invoice_prod?sslmode=disable" + url = "postgres://${getenv("POSTGRES_USER")}:${getenv("POSTGRES_PASSWORD")}@postgres-prod.default.svc.cluster.local:5432/stripe_invoice_prod?sslmode=disable" + migration { dir = "file://./db/atlas/stripe_invoice/migrations" } } + diff --git a/db/atlas/stripe_invoice/migrations/0004_login_tokens.sql b/db/atlas/stripe_invoice/migrations/0004_login_tokens.sql new file mode 100644 index 0000000..8366b1d --- /dev/null +++ b/db/atlas/stripe_invoice/migrations/0004_login_tokens.sql @@ -0,0 +1,7 @@ +CREATE TABLE login_tokens ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + token TEXT NOT NULL UNIQUE, + expires_at TIMESTAMPTZ NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); \ No newline at end of file diff --git a/db/atlas/stripe_invoice/migrations/atlas.sum b/db/atlas/stripe_invoice/migrations/atlas.sum index c8772cc..37a363f 100644 --- a/db/atlas/stripe_invoice/migrations/atlas.sum +++ b/db/atlas/stripe_invoice/migrations/atlas.sum @@ -1,4 +1,5 @@ -h1:R/iRQ2a7u+QeDRyEVRvl8TcvAzRjWXbjBpn4dNpyMAA= +h1:ELwFHTBDb63mdRBhmjXMMSpy05pUSVxH03zuUuHYAto= 0001_init.sql h1:gzb02ZbjrrJkXOC+2qIZsngnj7A+29O2/b4awScPlPs= 0002_auth.sql h1:4NhBu26dIBMy9gxMxM3tf6Z2CS2kfKlGjFBj07T/aBw= 0003_stripe_xero.sql h1:E2bcdUDnondsXwbdIwVlZqR4DQwzcoDiyeRFJwVxXwg= +0004_login_tokens.sql h1:rj1KcWu/0znh2YvtI7JV8Z2nwtL5rZzONbPwX1P+/PI= diff --git a/db/k8s/backups/pg-backup-cronjob.yaml b/db/k8s/backups/pg-backup-cronjob.yaml index e36d71b..5d7c265 100644 --- a/db/k8s/backups/pg-backup-cronjob.yaml +++ b/db/k8s/backups/pg-backup-cronjob.yaml @@ -1,9 +1,10 @@ apiVersion: batch/v1 kind: CronJob metadata: - name: postgres-backup + name: postgres-backup-dev + namespace: default spec: - schedule: "30 18 * * 5" # weekly on friday at 18:30 + schedule: "30 18 * * 5" # weekly Friday 18:30 jobTemplate: spec: template: @@ -16,11 +17,47 @@ spec: - /bin/sh - -c - | - pg_dump stripe_invoice \ + pg_dump \ + -h postgres-dev.default.svc.cluster.local \ + -U $POSTGRES_USER \ + stripe_invoice \ | gzip \ - | aws s3 cp - s3://$S3_BUCKET/stripe_invoice/$(date +%F).sql.gz + | aws s3 cp - s3://$S3_BUCKET/dev/stripe_invoice/$(date +%F).sql.gz envFrom: - secretRef: - name: postgres-secret + name: postgres-secret # DEV DB creds - secretRef: - name: aws-backup-secret + name: aws-backup-secret # shared AWS creds + +--- + +apiVersion: batch/v1 +kind: CronJob +metadata: + name: postgres-backup-prod + namespace: default +spec: + schedule: "30 01 * * *" # daily at 01:30 (recommended for prod) + jobTemplate: + spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: backup + image: postgres:16 + command: + - /bin/sh + - -c + - | + pg_dump \ + -h postgres-prod.default.svc.cluster.local \ + -U $POSTGRES_USER \ + stripe_invoice_prod \ + | gzip \ + | aws s3 cp - s3://$S3_BUCKET/prod/stripe_invoice/$(date +%F).sql.gz + envFrom: + - secretRef: + name: postgres-prod-secret # PROD DB creds + - secretRef: + name: aws-backup-secret # shared AWS creds diff --git a/db/k8s/postgres/deployment.yaml b/db/k8s/postgres/postgres-dev-stripe-to-invoice.yaml similarity index 99% rename from db/k8s/postgres/deployment.yaml rename to db/k8s/postgres/postgres-dev-stripe-to-invoice.yaml index b17f542..6c33bff 100644 --- a/db/k8s/postgres/deployment.yaml +++ b/db/k8s/postgres/postgres-dev-stripe-to-invoice.yaml @@ -84,7 +84,7 @@ spec: apiVersion: v1 kind: Service metadata: - name: postgres + name: postgres-dev namespace: default spec: type: ClusterIP diff --git a/db/k8s/postgres/postgres-prod-stripe-to-invoice.yaml b/db/k8s/postgres/postgres-prod-stripe-to-invoice.yaml new file mode 100644 index 0000000..4bb53f1 --- /dev/null +++ b/db/k8s/postgres/postgres-prod-stripe-to-invoice.yaml @@ -0,0 +1,111 @@ +# -------------------------------------------------- +# PersistentVolume (local disk on mist) — PROD +# -------------------------------------------------- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: postgres-prod-pv +spec: + capacity: + storage: 20Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: local-storage + hostPath: + path: /home/kimjunte/k8s_storage/postgres/stripe_invoice_prod + +--- +# -------------------------------------------------- +# PersistentVolumeClaim — PROD +# -------------------------------------------------- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: postgres-prod-pvc + namespace: default +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 20Gi + storageClassName: local-storage + +--- +# -------------------------------------------------- +# PostgreSQL Secret — PROD +# (DO NOT COMMIT real values) +# -------------------------------------------------- +apiVersion: v1 +kind: Secret +metadata: + name: postgres-prod-secret + namespace: default +type: Opaque +stringData: + POSTGRES_USER: stripe_invoice_prod + POSTGRES_PASSWORD: productionPassword1142M@ke!tH@rd2Br3akWith$ymb0ls + POSTGRES_DB: stripe_invoice_prod + +--- +# -------------------------------------------------- +# PostgreSQL Deployment — PROD +# -------------------------------------------------- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postgres-prod + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: postgres-prod + template: + metadata: + labels: + app: postgres-prod + spec: + containers: + - name: postgres + image: postgres:16 + ports: + - containerPort: 5432 + envFrom: + - secretRef: + name: postgres-prod-secret + volumeMounts: + - name: postgres-data + mountPath: /var/lib/postgresql/data + readinessProbe: + tcpSocket: + port: 5432 + initialDelaySeconds: 10 + periodSeconds: 5 + livenessProbe: + tcpSocket: + port: 5432 + initialDelaySeconds: 30 + periodSeconds: 10 + volumes: + - name: postgres-data + persistentVolumeClaim: + claimName: postgres-prod-pvc + +--- +# -------------------------------------------------- +# PostgreSQL Service (cluster-internal only) — PROD +# -------------------------------------------------- +apiVersion: v1 +kind: Service +metadata: + name: postgres-prod + namespace: default +spec: + type: ClusterIP + selector: + app: postgres-prod + ports: + - port: 5432 + targetPort: 5432