feat: Abschreiben im Cluster mit Whisper-Image und Voice-CronJob (T7 L3 Task 13)
ApiCore-Whisper: transcribe.py liest das Manifest im RAM-Arbeitsordner, dekodiert mit festem Demuxer je Endung, misst die Länge vor dem Abschreiben (TOO_LONG > 240 s, DECODE_FAILED bei Länge 0), sperrt das Netz vor dem Modell-Laden und schreibt nur Zähler auf stdout. Image: python:3.12-slim per Digest, Nutzer 1000, alle Pakete mit Hash (faster-whisper 1.2.1, av 18.1.0 wegen Inkompatibilität mit av 19), Modell faster-whisper-small auf fester Revision mit SHA-256 je Datei. CI-Workflow nur bei Änderungen unter ApiCore-Whisper/, Actions per SHA. deploy/k8s/components/voice: CronJob alle 2 Minuten mit fetch, whisper, ingest (gleiche UID, getrennte /tmp-Volumes, damit der Decoder dem Container mit den Secrets nichts unterschieben kann; whisper ohne Secrets und Umgebungsvariablen außer WHISPER_CPU_THREADS), Overlay mit Platzhalter-Digest, ConfigMap-Werte für Sprache, Policy-Tests (55). Die Anbindung des Anthropic-Schlüssels bleibt offen (Ruling 9). Refs #27 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
e614ded967
commit
c53810b8a6
16 files changed
+1448
-5
No files matched your search
@@ -0,0 +1,83 @@
|
||||
name: Whisper Image
|
||||
|
||||
# Nur bei Aenderungen am Abschreib-Image (Spec T7 11.1): das Image ist rund
|
||||
# 1,2 GB gross (Modell + Python-Abhaengigkeiten) und aendert sich selten.
|
||||
# Tag sha-<commit>; das Overlay setzt danach den Digest.
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths: ['ApiCore-Whisper/**', '.gitea/workflows/whisper-image.yml']
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: docker-builder
|
||||
env:
|
||||
# Nur fuer Doku/OCI-Labels, siehe REGISTRY_PUSH fuer den eigentlichen Push.
|
||||
REGISTRY: git.encry.de
|
||||
# Cluster-interner Service-Name statt git.encry.de: Registry-Blob-
|
||||
# Uploads (PUT) vertragen sich nicht mit dem Cloudflare-Proxy vor
|
||||
# git.encry.de ("413 Payload Too Large" unabhaengig von der Groesse).
|
||||
# Der Runner-Pod erreicht den Gitea-Service direkt ueber Kubernetes-DNS.
|
||||
# Push und Pull landen im selben Registry-Pfad (Owner/Repo:Tag), der
|
||||
# Hostname ist nur die Verbindung, daher bleibt der Pull in den
|
||||
# k8s-Manifesten unveraendert ueber git.encry.de.
|
||||
REGISTRY_PUSH: gitea:80
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
|
||||
- name: Image-Namen in Kleinbuchstaben ermitteln
|
||||
# OCI-Registries erlauben nur Kleinbuchstaben im Repository-Pfad;
|
||||
# der Gitea-Owner-Name behaelt Gross-/Kleinschreibung bei.
|
||||
id: image
|
||||
run: echo "name=$(echo '${{ gitea.repository_owner }}/apicore-whisper' | tr '[:upper:]' '[:lower:]')" >> "$GITEA_OUTPUT"
|
||||
|
||||
- name: Docker Buildx einrichten
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||
with:
|
||||
# REGISTRY_PUSH ist Klartext-HTTP (Gitea-Service intern ohne TLS)
|
||||
# statt HTTPS — BuildKit lehnt das ohne diese Freigabe ab.
|
||||
config-inline: |
|
||||
[registry."gitea:80"]
|
||||
http = true
|
||||
|
||||
- name: Bei der Gitea-Container-Registry anmelden
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY_PUSH }}
|
||||
username: ${{ gitea.actor }}
|
||||
# GITEA_TOKEN hat kein Package-Write-Recht — separates Personal
|
||||
# Access Token (Scope "package") als Secret REGISTRY_TOKEN anlegen.
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Metadaten (Tags/Labels) ermitteln
|
||||
id: meta
|
||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY_PUSH }}/${{ steps.image.outputs.name }}
|
||||
tags: |
|
||||
type=sha,format=short
|
||||
|
||||
- name: Image bauen und pushen
|
||||
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
|
||||
with:
|
||||
context: ./ApiCore-Whisper
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha,scope=apicore-whisper
|
||||
cache-to: type=gha,scope=apicore-whisper,mode=max
|
||||
|
||||
- name: Schwachstellen-Scan (nur wenn trivy im Runner vorhanden ist)
|
||||
# Hinweisend (exit-code 0): die Ausgabe gehoert ins Runbook, ein Fund
|
||||
# blockiert den Push nicht, weil das Image dann schon in der Registry
|
||||
# liegt. Der Build selbst ist die harte Sperre (Hashes, Modell-SHA,
|
||||
# pytest in der Test-Stufe).
|
||||
run: |
|
||||
if command -v trivy >/dev/null 2>&1; then
|
||||
first_tag="$(echo '${{ steps.meta.outputs.tags }}' | head -n1)"
|
||||
trivy image --insecure --severity HIGH,CRITICAL --exit-code 0 "$first_tag"
|
||||
else
|
||||
echo "trivy ist im Runner nicht installiert, Scan uebersprungen"
|
||||
fi
|
||||
Reference in new issue
Block a user