# Abschreiben im Cluster (Spec T7 6.3 und 11.1): alle 2 Minuten ein Pod mit # drei Containern, die nacheinander laufen: # fetch (initContainer) claimt Aufnahmen, entschluesselt, legt Ton nach /work/in # whisper (initContainer) liest /work/in, schreibt /work/out; ohne Netz, # ohne Schluessel, ohne Datenbank-Zugang # ingest (Hauptcontainer) liest /work/out, verschluesselt, speichert, loescht Ton # # Der gemeinsame CronJob-Patch aus components/backend-roles trifft alle # CronJobs mit app=apicore-job und wuerde diesem Pod einen Container `job` # (Backend-Image, alle Secrets) hinzufuegen. Darum traegt das CronJob-Objekt # app=apicore-voice-job; nur das Pod-Template traegt app=apicore-job (damit die # NetworkPolicy apicore-jobs gilt: Egress nur Postgres und DNS). Haertung, # Zeitzone und Forbid stehen deshalb hier vollstaendig. # # fetch, whisper und ingest laufen mit derselben uid 1000 und fsGroup 1000: # /work/in und /work/out sind 0700, die Dateien 0600. apiVersion: batch/v1 kind: CronJob metadata: name: apicore-job-voice-transcribe labels: app: apicore-voice-job apicore.io/job: voice-transcribe spec: schedule: "*/2 * * * *" timeZone: Europe/Berlin concurrencyPolicy: Forbid startingDeadlineSeconds: 120 successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 3 jobTemplate: spec: backoffLimit: 0 activeDeadlineSeconds: 1500 ttlSecondsAfterFinished: 86400 template: metadata: labels: app: apicore-job apicore.io/job: voice-transcribe db-client: "true" spec: restartPolicy: Never automountServiceAccountToken: false enableServiceLinks: false securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 seccompProfile: type: RuntimeDefault volumes: # Entschluesselter Ton und Abschriften liegen nur im RAM, nie auf # einer Platte. Das Backend rechnet mit diesen 32Mi (work-dir.ts). - name: work emptyDir: medium: Memory sizeLimit: 32Mi # /tmp von fetch und ingest (HOME=/tmp). Whisper bekommt ein eigenes # Volume: ein gemeinsames /tmp liesse einen kompromittierten # Decoder Code unter $HOME/.node_modules ablegen, den ingest mit # allen Secrets laedt. - name: tmp emptyDir: sizeLimit: 64Mi - name: whisper-tmp emptyDir: medium: Memory sizeLimit: 16Mi initContainers: - name: fetch image: git.encry.de/nick.rosenloecher/apicore-backend imagePullPolicy: IfNotPresent command: ["node", "dist/cli.js", "voice-transcribe", "--phase=fetch"] env: - name: APICORE_ROLE value: job - name: HOME value: /tmp envFrom: - configMapRef: name: apicore-backend-config - secretRef: name: apicore-backend-secret securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] volumeMounts: - name: work mountPath: /work - name: tmp mountPath: /tmp resources: requests: cpu: 50m memory: 192Mi limits: cpu: 500m memory: 512Mi # Kein envFrom, kein secretKeyRef, kein Service-Account-Token. Nur # die Thread-Zahl kommt von aussen; alles andere steht im Image. - name: whisper image: git.encry.de/nick.rosenloecher/apicore-whisper imagePullPolicy: IfNotPresent env: - name: WHISPER_CPU_THREADS value: "2" securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 capabilities: drop: ["ALL"] seccompProfile: type: RuntimeDefault volumeMounts: # Eingabe nur lesbar (Manifest und Ton kann der Decoder nicht # veraendern), Ausgabe schreibbar. fetch legt in/ und out/ an # (clearWorkDir, Modus 0700, uid 1000), bevor dieser Container startet. - name: work mountPath: /work/in subPath: in readOnly: true - name: work mountPath: /work/out subPath: out - name: whisper-tmp mountPath: /tmp resources: requests: cpu: 50m memory: 1280Mi limits: cpu: 2000m memory: 1280Mi containers: - name: ingest image: git.encry.de/nick.rosenloecher/apicore-backend imagePullPolicy: IfNotPresent command: ["node", "dist/cli.js", "voice-transcribe", "--phase=ingest"] env: - name: APICORE_ROLE value: job - name: HOME value: /tmp envFrom: - configMapRef: name: apicore-backend-config - secretRef: name: apicore-backend-secret securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] volumeMounts: - name: work mountPath: /work - name: tmp mountPath: /tmp resources: requests: cpu: 50m memory: 192Mi limits: cpu: 500m memory: 512Mi