Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m19s
Alle Ressourcen tragen den Praefix artista-modelcamp- im Namespace artista; Images <owner>/artista-modelcamp und <owner>/artista-modelcamp-tools. DATABASE_URL-Host, Backup-Host, Traefik-Middleware-Referenz und Betriebsdoku entsprechend angepasst. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
160 lines
5.4 KiB
YAML
160 lines
5.4 KiB
YAML
# --- Migration ----------------------------------------------------------------
|
|
# Als SUSPENDIERTER CronJob definiert, damit Kustomize das Image mit der
|
|
# App gleichzieht. Er laeuft nie von selbst, sondern bewusst vor jedem
|
|
# Rollout:
|
|
# kubectl -n artista create job migrate-$(date +%Y%m%d%H%M) --from=cronjob/artista-modelcamp-migrate
|
|
# kubectl -n artista wait --for=condition=complete job/migrate-… --timeout=5m
|
|
apiVersion: batch/v1
|
|
kind: CronJob
|
|
metadata:
|
|
name: artista-modelcamp-migrate
|
|
spec:
|
|
suspend: true
|
|
schedule: "0 0 1 1 *"
|
|
jobTemplate:
|
|
spec:
|
|
backoffLimit: 0
|
|
ttlSecondsAfterFinished: 86400
|
|
template:
|
|
metadata:
|
|
labels:
|
|
artista/db-client: "true"
|
|
spec:
|
|
restartPolicy: Never
|
|
automountServiceAccountToken: false
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 1001
|
|
seccompProfile: { type: RuntimeDefault }
|
|
containers:
|
|
- name: migrate
|
|
image: artista-modelcamp-tools
|
|
command: ["prisma", "migrate", "deploy"]
|
|
envFrom:
|
|
- secretRef: { name: artista-modelcamp-secrets }
|
|
resources:
|
|
requests: { cpu: 50m, memory: 128Mi }
|
|
limits: { memory: 512Mi }
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
capabilities: { drop: ["ALL"] }
|
|
---
|
|
# --- Worker -------------------------------------------------------------------
|
|
# Gibt abgelaufene Reservierungen frei (nach Rueckfrage bei Stripe), zieht
|
|
# faellige Raten ein, trennt Zahlungsmethoden nach der letzten Rate,
|
|
# versendet den E-Mail-Ausgang. Idempotent; Forbid verhindert
|
|
# ueberlappende Laeufe zusaetzlich.
|
|
apiVersion: batch/v1
|
|
kind: CronJob
|
|
metadata:
|
|
name: artista-modelcamp-worker
|
|
spec:
|
|
schedule: "*/10 * * * *"
|
|
timeZone: "Europe/Berlin"
|
|
concurrencyPolicy: Forbid
|
|
startingDeadlineSeconds: 300
|
|
successfulJobsHistoryLimit: 3
|
|
failedJobsHistoryLimit: 5
|
|
jobTemplate:
|
|
spec:
|
|
backoffLimit: 1
|
|
activeDeadlineSeconds: 900
|
|
template:
|
|
metadata:
|
|
labels:
|
|
artista/db-client: "true"
|
|
spec:
|
|
restartPolicy: Never
|
|
automountServiceAccountToken: false
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 1001
|
|
seccompProfile: { type: RuntimeDefault }
|
|
containers:
|
|
- name: worker
|
|
image: artista-modelcamp-tools
|
|
command: ["tsx", "scripts/worker.ts"]
|
|
envFrom:
|
|
- configMapRef: { name: artista-modelcamp-config }
|
|
- secretRef: { name: artista-modelcamp-secrets }
|
|
resources:
|
|
requests: { cpu: 50m, memory: 192Mi }
|
|
limits: { memory: 512Mi }
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
capabilities: { drop: ["ALL"] }
|
|
---
|
|
# --- Sicherung ----------------------------------------------------------------
|
|
# Taeglicher pg_dump mit 30 Tagen Aufbewahrung. Das Backup-Volume darf ein
|
|
# Netzwerkspeicher (NFS/SMB) sein. Zusaetzlich regelmaessig aus dem Cluster
|
|
# kopieren (docs/BETRIEB.md, "Sicherung und Wiederherstellung").
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: artista-modelcamp-db-backup
|
|
spec:
|
|
accessModes: ["ReadWriteOnce"]
|
|
# storageClassName: smb-backup
|
|
resources:
|
|
requests:
|
|
storage: 10Gi
|
|
---
|
|
apiVersion: batch/v1
|
|
kind: CronJob
|
|
metadata:
|
|
name: artista-modelcamp-db-backup
|
|
spec:
|
|
schedule: "15 3 * * *"
|
|
timeZone: "Europe/Berlin"
|
|
concurrencyPolicy: Forbid
|
|
failedJobsHistoryLimit: 5
|
|
jobTemplate:
|
|
spec:
|
|
backoffLimit: 2
|
|
template:
|
|
metadata:
|
|
labels:
|
|
artista/db-client: "true"
|
|
spec:
|
|
restartPolicy: OnFailure
|
|
automountServiceAccountToken: false
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 70
|
|
runAsGroup: 70
|
|
fsGroup: 70
|
|
seccompProfile: { type: RuntimeDefault }
|
|
containers:
|
|
- name: pg-dump
|
|
# Gleiche Hauptversion wie der Server.
|
|
image: postgres:18.1-alpine
|
|
env:
|
|
- name: PGPASSWORD
|
|
valueFrom:
|
|
secretKeyRef: { name: artista-modelcamp-secrets, key: DB_PASSWORD }
|
|
command: ["/bin/sh", "-c"]
|
|
args:
|
|
- |
|
|
set -eu
|
|
set -o pipefail
|
|
target="/backup/artista-$(date -u +%Y-%m-%d_%H%M).dump"
|
|
# Custom-Format: komprimiert, selektiv wiederherstellbar.
|
|
pg_dump --host=artista-modelcamp-postgres --username=artista --dbname=artista \
|
|
--format=custom --file="${target}.partial"
|
|
mv "${target}.partial" "${target}"
|
|
find /backup -name 'artista-*.dump.partial' -mtime +1 -delete
|
|
find /backup -name 'artista-*.dump' -mtime +30 -delete
|
|
ls -lh /backup
|
|
resources:
|
|
requests: { cpu: 50m, memory: 128Mi }
|
|
limits: { memory: 256Mi }
|
|
securityContext:
|
|
allowPrivilegeEscalation: false
|
|
capabilities: { drop: ["ALL"] }
|
|
volumeMounts:
|
|
- name: backup
|
|
mountPath: /backup
|
|
volumes:
|
|
- name: backup
|
|
persistentVolumeClaim: { claimName: artista-modelcamp-db-backup }
|