Zum Inhalt springen

Unabhängiges F&E-Projekt · Köln

Cloud-native und Kubernetes

Deployment-Grenzen, Admission, Netzwerkisolation, Herkunft der Konfiguration und Release-Kontrollen, mit validierten Referenzbeispielen.

Nicht normativ

Companion-Version
1.0
Bezug zu COADF Core
2.2
Status
Aktuell
Zuletzt geprüft
Profilversion
1.0
Codebeispiele
Veranschaulichende Referenzbeispiele

Behandelte Architektureigenschaften

  • P-1Die probabilistische Workload in einem eigenen Namespace, mit ausgehendem Netzwerkverkehr nur zu dem, was sie braucht, und ohne Zugangsdaten für den maßgeblichen Datenspeicher. Eine Ergänzung der Anwendungsgrenze, nie ihr Ersatz.
  • P-4Ausführungskontext einmal pro Workload konfiguriert; eine gesampelte Trace-Pipeline, getrennt von der Prüfspur gehalten; die Herkunft der Konfiguration an jedem Pod ablesbar.
  • P-6Deployment-Admission und Release-Gates als Fence-Flächen, mit ihren typischen Umgehungen benannt.
  • P-8Konfigurations- und Policy-Revisionen, die Rollouts überstehen, und ein Entscheidungsdatensatz, der die Revision nennt, wenn zwei gleichzeitig live sind.
  • P-7Externe Dienste über expliziten ausgehenden Verkehr erreicht, sodass eine neue Abhängigkeit eine geprüfte Änderung an einer Policy ist und keine Codezeile.
  • P-2, P-3Auf Infrastrukturebene nicht behandelt: Es sind Eigenschaften der Anwendung, und COADF veröffentlicht sie nur als Prinzipien.

Architektonische Absicht

Kubernetes bringt eigene Grenzen mit (Namespaces, Netzwerk-Policies, Admission, Rollout) und eigene Fehlermuster: Objekte, die angenommen und nicht durchgesetzt werden, Abgleich, der irgendwann stattfindet, zwei Versionen desselben Dienstes, die gleichzeitig antworten. Dieses Profil bildet die COADF-Eigenschaften auf diese Grenzen ab, ohne Kubernetes als Voraussetzung von COADF zu behandeln und ohne eine Kontrolle im Cluster an die Stelle einer Kontrolle in der Anwendung treten zu lassen.

Die Regel, die sich hindurchzieht: Infrastruktur kann eine Grenze schwerer überschreitbar machen, aber sie kann keine entstehen lassen. Eine Anwendung, die Modellausgaben in ihre eigenen maßgeblichen Tabellen schreibt, wird durch keine Netzwerk-Policy repariert.

Technologiezuordnung

Cloud-native und Kubernetes: Technologiezuordnung
ArchitektureigenschaftCloud-native und Kubernetes
Probabilistische GrenzeEin eigenes Deployment und ein eigener Namespace; NetworkPolicy für ausgehenden Verkehr; die Schreib-Zugangsdaten nur dort angelegt, wo die Domäne läuft; Datenbank-Grants pro Workload
Admission-FenceValidatingAdmissionPolicy (CEL, im Prozess) oder OPA Gatekeeper (Rego, mit einem Audit bestehender Ressourcen)
AusführungskontextOpenTelemetry-SDK-Konfiguration pro Workload; eine Collector-Pipeline für Traces
PrüfspurDer eigene Append-only-Speicher der Anwendung, außerhalb der Telemetrie-Pipeline
Herkunft der KonfigurationRevisions-Annotationen, unveränderliche, nach Revision benannte ConfigMaps, per Digest fixierte Images; ein GitOps-Controller, der die synchronisierte Revision festhält
Release-KontrollePflicht-Checks, die nicht dadurch bestehen können, dass sie übersprungen werden; Deployment-Umgebungen; Promotion per Digest
PolicyOPA als Dienst oder Sidecar, seine Bundle-Revision in den Entscheidungsprotokollen; Admission-Policies für Infrastrukturregeln

Referenzmuster

Drei Namespaces: inference für den Modell-Client und seine Grenze, model-serving für den Modell-Endpunkt, records für die Aufnahme der Vorschläge, den Domänenkern und die Datenbank. Die Seite Probabilistische Grenze zeichnet dasselbe System als Cluster-Diagramm.

P-1 · Kein Weg zu den Datensätzen

Veranschaulichendes ReferenzbeispielKeine Route von der probabilistischen Seite zu den Datensätzen
Zweck
Wenn die probabilistische Seite als eigener Workload läuft, ihr keine Route zum maßgeblichen Speicher geben.
Architektureigenschaft
Netzwerkisolation als zusätzliche Durchsetzung der Grenze aus P-1 auf Ebene der Infrastruktur. Sie ergänzt die Grenze in der Anwendung und ersetzt sie nicht.
networkpolicy.yamlyamlP-1
# Illustrative reference example: the inference workloads can reach the model# endpoint, the domain's proposal intake and DNS, and nothing else. The records# database sits in the same namespace as the intake, and no rule here opens a# route to it: selecting the intake pods and port is what keeps it closed.# Enforced only by a network plugin that implements NetworkPolicy, and only as an# addition: the application boundary is still required, and this replaces none of it.apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:  name: inference-egress  namespace: inferencespec:  podSelector: {}  # every pod in this namespace  policyTypes:    - Egress  egress:    - to:        - namespaceSelector:            matchLabels:              kubernetes.io/metadata.name: model-serving      ports:        - protocol: TCP          port: 8080    - to:        - namespaceSelector:            matchLabels:              kubernetes.io/metadata.name: records          podSelector:  # same list item: this namespace AND these pods            matchLabels:              app: proposal-intake      ports:        - protocol: TCP          port: 8443    - to:        - namespaceSelector:            matchLabels:              kubernetes.io/metadata.name: kube-system          podSelector:            matchLabels:              k8s-app: kube-dns      ports:        - protocol: UDP          port: 53        - protocol: TCP          port: 53

Was es bewusst weglässt

  • Das Netzwerk-Plugin. Ohne eines, das NetworkPolicy umsetzt, wird dieses Objekt angenommen und bewirkt nichts.
  • Ingress-Regeln und eine Default-Deny-Policy für den Namespace.
  • Die Labels der DNS-Pods, die sich zwischen Clustern unterscheiden.
  • Egress zu einem außerhalb des Clusters gehosteten Modell, der eine eigene Regel braucht.

So lässt es sich prüfen

Für diesen Companion nicht ausgeführt: Das Manifest wurde gegen die Kubernetes-Schemata validiert, was seine Struktur belegt und nichts über die Durchsetzung. Um die Durchsetzung zu verifizieren, in einem Testcluster mit einem durchsetzenden Netzwerk-Plugin, von einem Inferenz-Pod aus: Der Modell-Endpunkt antwortet, und die Datenbank der Datensätze antwortet nicht; die Policy löschen, und die Datenbank antwortet, was belegt, dass es die Policy war, die sie blockiert hat.

Adressiertes Fehlermuster

Eine NetworkPolicy, die in einen Cluster eingespielt wird, dessen Netzwerk-Plugin sie nicht durchsetzt. Das Manifest ist gültig, das Review besteht, und nichts ist isoliert.

P-6 · Ein Fence zum Zeitpunkt des Deployments

ValidatingAdmissionPolicy ist seit Kubernetes 1.30 stabil und läuft innerhalb des API-Servers, braucht also keinen verfügbaren Webhook. Dieselben Regeln lassen sich für OPA Gatekeeper schreiben, das ein Audit bereits vorhandener Ressourcen und Durchsetzungsaktionen wie dryrun und warn ergänzt; beides ist tragfähig, und die Eigenschaft hängt nicht von der Wahl ab.

Die Regel muss das Ganze prüfen, das sie benennt. Ein Test auf @sha256: irgendwo in der Image-Referenz lässt image@sha256: ohne irgendetwas dahinter zu; diese Policy prüft auf einen vollständigen SHA-256-Digest und verlangt, dass die Revisions-Annotation eine Revision enthält, nicht bloß existiert.

Veranschaulichendes ReferenzbeispielEin Fence zum Deployment-Zeitpunkt für die Herkunft der Konfiguration
Zweck
Kein Deployment zulassen, dessen Images nicht über einen wohlgeformten Digest fixiert sind oder das nicht in einer nicht leeren Annotation die Konfigurationsrevision nennen kann, aus der es stammt.
Architektureigenschaft
Ein verbotener Zustand verhindert den Übergang, hier das Anlegen oder Aktualisieren eines Deployments (P-6), und die Herkunft der Konfiguration wird zu einer Eigenschaft jedes laufenden Workloads (P-4).
admission-policy.yamlyamlP-4 · P-6
# Illustrative reference example: a Deployment is admitted only if every image# reference ends in a well-formed sha256 digest and the object names, in a# non-empty annotation, the configuration revision it was rendered from.# Admission sees API objects; it never sees application data.apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicymetadata:  name: deployments-declare-provenancespec:  failurePolicy: Fail  matchConstraints:    resourceRules:      - apiGroups: ["apps"]        apiVersions: ["v1"]        operations: ["CREATE", "UPDATE"]        resources: ["deployments"]  validations:    - expression: >-        object.spec.template.spec.containers.all(c,          c.image.matches('^[^@]+@sha256:[0-9a-f]{64}$')) &&        (!has(object.spec.template.spec.initContainers) ||          object.spec.template.spec.initContainers.all(c,            c.image.matches('^[^@]+@sha256:[0-9a-f]{64}$')))      message: "every container image must end in a sha256 digest of 64 hex characters"    - expression: >-        has(object.metadata.annotations) &&        'refapp.example/config-revision' in object.metadata.annotations &&        object.metadata.annotations['refapp.example/config-revision'].matches('^[A-Za-z0-9._-]+$')      message: "the Deployment must name, in a non-empty annotation, the configuration revision it was rendered from"---apiVersion: admissionregistration.k8s.io/v1kind: ValidatingAdmissionPolicyBindingmetadata:  name: deployments-declare-provenancespec:  policyName: deployments-declare-provenance  validationActions: ["Deny"]  matchResources:    namespaceSelector:      matchLabels:        refapp.example/provenance-required: "true"

Was es bewusst weglässt

  • Validierung auf Anwendungsebene. Admission sieht API-Objekte und nie die Anfragen, die der eigene Dienst bearbeitet.
  • Objekte, die bereits existieren. Admission wertet Anfragen aus, wenn sie gestellt werden, und das Hinzufügen dieser Policy prüft nichts erneut, das bereits läuft.
  • Direkt angelegte Pods und andere Workload-Arten (StatefulSet, Job, CronJob, DaemonSet), die jeweils eine eigene Zuordnung brauchen.
  • Ob die genannte Revision existiert oder ob der Digest derjenige ist, den die Continuous Integration gebaut hat. Die Regel prüft die Form eines Digests, nicht seine Herkunft.

So lässt es sich prüfen

Gegen einen echten Kubernetes-API-Server (ein lokaler Wegwerf-kube-apiserver 1.37 ohne Nodes; jeder Fall ein serverseitiger Dry Run): Per Digest fixierte Images werden zugelassen, auch hinter einem Registry-Port und nach einem Tag; ein Image nur mit Tag, ein leerer Digest, ein Digest, der nicht hexadezimal ist, und ein Digest falscher Länge werden abgelehnt, ebenso eine fehlende, leere oder nur aus Leerzeichen bestehende Revisionsannotation (tests/test_admission_policy.py). Mit einer Regel, die nur das Vorhandensein prüft, contains('@sha256:') und einem bloßen in, werden fünf dieser Fälle zugelassen, und deshalb prüft die Regel den gesamten Digest.

Adressiertes Fehlermuster

Ungeprüfte Annahmen über das Release: ein Tag, der nach dem Review verschoben wurde, oder ein laufendes Deployment, das niemand der Konfiguration zuordnen kann, aus der es gerendert wurde.

P-4 und P-8 · Herkunft der Konfiguration am Pod

Veranschaulichendes ReferenzbeispielHerkunft der Konfiguration, ablesbar an einem laufenden Pod
Zweck
Die Konfigurationsrevision im Objekt, im Pod-Template und im Namen einer unveränderlichen ConfigMap sichtbar machen.
Architektureigenschaft
Eine neue Revision ist ein Rollout, und kein Pod läuft mit einer Konfiguration, die er nicht benennen kann. Die Revision der Prompt-Vorlage, die der Modellaufruf meldet (prompt_revision in der Python-Grenze), hat hier ein deploybares Gegenstück.
deployment.yamlyamlP-4 · P-8
# Illustrative reference example: configuration provenance you can read off a# running pod. The revision is in the object, in the pod template and in the# name of the immutable ConfigMap, so a new revision is a new rollout and no# pod runs a configuration it cannot name.apiVersion: v1kind: ConfigMapmetadata:  name: prompt-templates-3f9c2d1  namespace: inferenceimmutable: truedata:  service-report.txt: |    Read the service report and propose next_service_due and component_class.---apiVersion: apps/v1kind: Deploymentmetadata:  name: report-extraction  namespace: inference  annotations:    refapp.example/config-revision: "3f9c2d1"spec:  replicas: 2  selector:    matchLabels:      app: report-extraction  template:    metadata:      labels:        app: report-extraction      annotations:        refapp.example/config-revision: "3f9c2d1"    spec:      automountServiceAccountToken: false      containers:        - name: worker          image: registry.example/refapp/extraction@sha256:3f9c2d1e3f9c2d1e3f9c2d1e3f9c2d1e3f9c2d1e3f9c2d1e3f9c2d1e3f9c2d1e          env:            - name: OTEL_SERVICE_NAME              value: report-extraction            - name: OTEL_RESOURCE_ATTRIBUTES              value: service.version=3f9c2d1          volumeMounts:            - name: prompts              mountPath: /etc/refapp/prompts              readOnly: true      volumes:        - name: prompts          configMap:            name: prompt-templates-3f9c2d1

Was es bewusst weglässt

  • Überlappung beim Rollout. Während eines Rolling Updates bedienen alte und neue Pods gleichzeitig, sodass zwei Revisionen zugleich aktiv sind; die Revision nennen muss der Entscheidungssatz, nicht der Zustand des Deployments.
  • Secrets, Probes, Ressourcen und Security Context.
  • Der Service Account und seine Berechtigungen.

So lässt es sich prüfen

Den Prompt-Text unter demselben Namen bearbeiten: Die ConfigMap ist unveränderlich, und die Änderung wird abgelehnt. Eine neue ConfigMap anlegen und den Namen und die Annotationen aktualisieren: Ein Rollout folgt, und jeder Pod meldet seine Revision als service.version.

Adressiertes Fehlermuster

Umgebungen, die ohne Herkunftsnachweis unterschiedliche Konfiguration ausführen. Eine über Umgebungsvariablen gelesene ConfigMap wird erst übernommen, wenn Pods neu starten, eine eingehängte irgendwann, und in der Zwischenzeit kann niemand sagen, welche Konfiguration eine bestimmte Antwort erzeugt hat.

P-4 · Die Trace-Pipeline ist nicht die Prüfspur

OpenTelemetry-SDKs lesen OTEL_PROPAGATORS und verwenden standardmäßig tracecontext,baggage, sodass der Ausführungskontext Dienstgrenzen ohne Code überquert. Die Audit-Identität reist nicht auf diesem Weg: Sie ist Teil des Vertrags jeder Nachricht, und die Audit-Einträge schreibt die Anwendung in ihren eigenen Speicher.

Veranschaulichendes ReferenzbeispielEine Trace-Pipeline, die sampelt, und deshalb nicht die Prüfspur ist
Zweck
Eine gewöhnliche, gesampelte Trace-Pipeline zeigen und warum die Prüfspur nie durch eine solche läuft.
Architektureigenschaft
Ausführungstelemetrie und Prüfspur sind verschiedene Artefakte und versprechen Verschiedenes. Sie werden über die trace_id der Prüfspur korreliert, und die Prüfspur läuft nie durch eine Pipeline, die so konfiguriert ist, dass sie Daten verwirft (P-4).
otel-collector.yamlyamlP-4
# Illustrative reference example: an OpenTelemetry Collector pipeline for# traces. Sampling is legitimate here, and it is exactly why this pipeline is# not the audit trail: audit entries are written to their own append-only# store by the application, and never pass through this configuration.receivers:  otlp:    protocols:      grpc: {}      http: {} processors:  memory_limiter:    check_interval: 1s    limit_percentage: ${env:MEMORY_LIMIT_PERCENTAGE}  probabilistic_sampler:    sampling_percentage: ${env:TRACE_SAMPLE_PERCENTAGE}  batch: {} exporters:  otlp:    endpoint: tracing-backend.observability:4317 service:  pipelines:    traces:      receivers: [otlp]      processors: [memory_limiter, probabilistic_sampler, batch]      exporters: [otlp]

Was es bewusst weglässt

  • Tail Sampling, das verlangt, dass jeder Span eines Traces dieselbe Collector-Instanz erreicht.
  • Das Trace-Backend und seine Aufbewahrung.
  • Pipelines für Logs und Metriken.
  • Die Prozentsätze. Sie sind betriebliche Einstellungen, geliefert über die Expansion von Umgebungsvariablen, und ihre Werte sind für die Architektureigenschaft ohne Belang.

So lässt es sich prüfen

otelcol-contrib validate akzeptiert die Konfiguration, wenn die beiden Prozentsätze aus der Umgebung kommen, und lehnt sie ab, wenn sie fehlen. Eine bekannte Anzahl von Traces senden und zählen, was ankommt: Bei jedem Sampling, das Traces verwirft, kommen einige nicht an, und genau diese Eigenschaft schließt diesen Pfad als Prüfspur aus.

Adressiertes Fehlermuster

Ein Trace, der nur im Tracing-Backend vorliegt: Die Frage „Was ist mit diesem Vorgang geschehen?“ wird aus einem Speicher beantwortet, der ihn verwerfen durfte.

P-6 · Release-Kontrollen

Der Workflow definiert die Checks und lässt seinen Zusammenfassungsjob scheitern, wenn ein Fence fehlschlägt, abgebrochen oder übersprungen wird. Zur Pflicht machen kann er diesen Job nicht: Das leistet Branch Protection oder ein Ruleset in den Repository-Einstellungen, und ohne sie ignoriert der Merge-Button das Ergebnis.

Veranschaulichendes ReferenzbeispielFences, die ein Release stoppen, und ein Check, der nicht durch Überspringen bestehen kann
Zweck
Den Merge und das Release bei einem gescheiterten Fence stoppen, mit einem erforderlichen Check, der rot bleibt, wenn ein Fence übersprungen wird.
Architektureigenschaft
Ein gescheiterter, abgebrochener oder übersprungener Fence lässt den Job fences scheitern, und das Release läuft nicht (P-6). Der Workflow kann fences nicht zum erforderlichen Check machen: Nur Branch Protection oder ein Ruleset in den Repository-Einstellungen blockiert darauf gestützt einen Merge.
release-workflow.yamlyamlP-6
# Illustrative reference example: fences that stop a release, and one summary# check that cannot turn green by being skipped. Making it a REQUIRED check is a# repository setting (branch protection or a ruleset), not part of this file.name: releaseon:  pull_request:  push:    branches: [main] jobs:  architecture:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v7      - uses: actions/setup-python@v7        with:          python-version: "3.12"      - run: pip install -r requirements.txt      - run: lint-imports   tests:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v7      - uses: actions/setup-python@v7        with:          python-version: "3.12"      - run: pip install -r requirements.txt      - run: pytest -q   publication:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v7      - run: make site  # writes the public build to build/      - name: Fence the built output        env:          PATTERNS: ${{ secrets.PUBLICATION_PATTERNS }}        run: |          printf '%s\n' "$PATTERNS" > "$RUNNER_TEMP/patterns.txt"          python -m refapp.fence build/ "$RUNNER_TEMP/patterns.txt"   # The one job branch protection requires. A skipped job reports success,  # so this job runs whatever happened above and fails unless all passed.  fences:    if: ${{ always() }}    needs: [architecture, tests, publication]    runs-on: ubuntu-latest    steps:      - if: >-          contains(needs.*.result, 'failure') ||          contains(needs.*.result, 'cancelled') ||          contains(needs.*.result, 'skipped')        run: exit 1   release:    if: github.event_name == 'push'    needs: fences  # never `if: always()` here: that would release after a failed fence    runs-on: ubuntu-latest    environment: production    steps:      - run: echo "promote the artifact built from ${{ github.sha }}"

Was es bewusst weglässt

  • Der Build der Site selbst; make site steht dafür.
  • Einstellungen der Branch Protection, die in den Repository-Einstellungen liegen und nicht im Workflow.
  • Das Fixieren von Actions auf Commit-Hashes, die stärkere Praxis. Hier werden der Lesbarkeit halber Major-Version-Tags verwendet.

So lässt es sich prüfen

Auf einem Test-Branch einen Fence-Job scheitern lassen: Der Job fences scheitert, und das Release wird übersprungen. Stattdessen einen Fence-Job mit einem falschen if: überspringen lassen: Der Job fences scheitert trotzdem, weil ein übersprungener Job der Branch Protection Erfolg meldet und dieser Job es ablehnt, ihn mitzuzählen.

Adressiertes Fehlermuster

Ein erforderlicher Check, der grün wird, weil er übersprungen wurde. GitHub meldet einen übersprungenen Job als Erfolg, sodass ein erforderlicher Job, der von einem gescheiterten Fence abhängt, den Merge durchlassen kann.

Fehlermuster

  1. Eine NetworkPolicy, die nichts durchsetzt

    Eine NetworkPolicy ohne ein Netzwerk-Plugin, das sie implementiert, hat keine Wirkung. Das Manifest ist gültig, die Prüfung besteht, und nichts ist isoliert.

  2. Ein Bindestrich erweitert die Regel

    Innerhalb eines to-Eintrags wählen ein namespaceSelector und ein podSelector zusammen diese Pods in diesen Namespaces aus. Als zwei Listeneinträge geschrieben, wählen sie den ganzen Namespace aus oder diese Pods im eigenen Namespace der Policy. Die Kubernetes-Dokumentation warnt genau vor diesem YAML-Unterschied.

  3. Admission mit Validierung in der Anwendung verwechselt

    Admission fängt Anfragen an den API-Server ab: Sie sieht Deployments und Pods, nie die Anfragen, die der eigene Dienst verarbeitet, oder die Antworten, die ein Modell liefert. Siehe die Technologie-Notiz.

  4. Ein Fence, der offen versagt

    Ein Webhook mit der Failure Policy Ignore lässt eine Anfrage durch, wenn der Webhook nicht aufgerufen werden kann. Der Tag, an dem der Webhook ausfällt, ist der Tag, an dem die Regel aus ist.

  5. Bestehende Objekte nie erneut geprüft

    Admission beurteilt Anfragen, wenn sie eintreffen. Für LimitRange hält Kubernetes fest, dass bereits laufende Pods unverändert weiterlaufen; ebenso sagt eine neue Admission-Regel nichts über das, was vor ihr zugelassen wurde. Das Audit von Gatekeeper existiert für diese Lücke.

  6. Ein nach der Prüfung verschobener Tag

    Digests sind unveränderlich; Tags lassen sich so verschieben, dass sie auf andere Images zeigen. Ein per Tag geprüftes Image ist nicht notwendigerweise das Image, das läuft.

  7. Unsichtbare Konfigurationsdrift

  8. Zwei Revisionen live während eines Rollouts

    Rolling Updates betreiben alte und neue Versionen gleichzeitig. Alles, was eine Revision nennen muss (eine Entscheidung, eine Extraktion, eine Antwort), muss sie in dem Moment festhalten, in dem es entsteht, und darf sie nicht nachträglich aus dem Deployment ableiten.

  9. Die gesampelte Pipeline als Nachweis verwendet

    Ein nicht gesampelter Trace wird nicht exportiert. Eine Pipeline, die so konfiguriert ist, dass sie einen Bruchteil der Traces behält, ist für die Diagnose richtig und kann keine Audit-Frage beantworten.

  10. Baggage, das das Haus verlässt

    OpenTelemetry warnt, dass Baggage an unbeabsichtigte Empfänger weitergegeben werden kann, APIs von Dritten eingeschlossen. Eine Kennung, die aus Bequemlichkeit ins Baggage gelegt wurde, reist weiter, als ihr Eigentümer beabsichtigt hat.

  11. Ein Gate für namentlich benannte Personen, das der Tarif nicht durchsetzt

    In den GitHub-Tarifen Free, Pro und Team gibt es Required Reviewers für Umgebungen nur für öffentliche Repositories. Ein privates Repository in diesen Tarifen hat den Namen der Einstellung, nicht ihre Wirkung.

Verifikation

  • Deployment- oder Admission-Test

    Bestanden, wenn: Gegen einen lokalen Wegwerf-API-Server wird das Beispiel-Deployment in einen Namespace zugelassen, der das Label des Bindings trägt, und ebenso Digests hinter einem Registry-Port oder nach einem Tag.

    Zahnbeweis: Ein Image nur mit Tag, ein leerer oder fehlerhafter Digest und eine fehlende, leere oder nur aus Leerzeichen bestehende Revision werden jeweils von der Policy abgelehnt. Die Regeln für Digest und Revision durch reine Vorhandenseinsprüfungen ersetzen: Fünf dieser Fälle werden zugelassen, und die Tests schlagen fehl.

  • Integrationstest

    Bestanden, wenn: Für diese Revision nicht ausgeführt. Aus einem Inferenz-Pod, mit einem durchsetzenden Netzwerk-Plugin: Der Modell-Endpunkt und die Aufnahme der Vorschläge antworten, der Datenbank-Port nicht.

    Zahnbeweis: Die Policy löschen: Die Datenbank antwortet, was belegt, dass die Policy und nichts anderes sie blockiert hat.

  • Vertragstest

    Bestanden, wenn: Manifeste validieren im Strict Mode gegen die Kubernetes-Schemata jeder unterstützten Minor-Version, sodass ein falsch geschriebenes Feld ein Fehler ist.

    Zahnbeweis: podSelector falsch schreiben: Die strikte Validierung schlägt fehl.

  • Vertragstest

    Bestanden, wenn: Die Collector-Konfiguration validiert mit dem Collector-Binary der deployten Version, mit den Prozentsätzen aus der Umgebung.

    Zahnbeweis: Eine Prozessor-Einstellung falsch schreiben oder die Prozentsätze nicht setzen: Die Validierung schlägt fehl.

  • End-to-End-Test

    Bestanden, wenn: Ein fehlgeschlagener Fence-Job lässt den Zusammenfassungsjob scheitern und überspringt das Release; die Branch Protection führt den Zusammenfassungsjob als Pflicht.

    Zahnbeweis: Einen Fence-Job überspringen, statt ihn scheitern zu lassen: Der Zusammenfassungsjob schlägt trotzdem fehl, weil er sich weigert, einen übersprungenen Job zu zählen.

  • Manueller Nachweis

    Bestanden, wenn: Bei jedem Release werden die Image-Digests und die Konfigurationsrevision festgehalten und mit dem verglichen, was der Cluster meldet.

Alternative Umsetzungen

  • Gatekeeper, Kyverno oder ValidatingAdmissionPolicy für Admission-Regeln. Die Eigenschaft ist, dass die Regel den Übergang stoppt und dabei beobachtet wurde; die Engine ist eine Wahl.
  • Die Autorisierungs-Policy eines Service Mesh, wo ausgehender Verkehr pro Anfrage statt pro Port kontrolliert werden muss.
  • GitOps-Controller (Argo CD, Flux) als Nachweis, welche Konfigurationsrevision angewendet ist, zusätzlich zu den Annotationen an den Objekten.
  • Eine verwaltete Plattform ohne Kubernetes. Jede Eigenschaft dieses Profils hat dort ein Gegenstück: getrennte deploybare Einheiten, Netzwerkregeln, Deployment-Gates, Konfigurationsrevisionen. COADF setzt keines der hier genannten Werkzeuge voraus.

Abwägungen

  • Admission im Prozess oder eine Policy-Engine. ValidatingAdmissionPolicy braucht keine zusätzliche Komponente und kann nicht getrennt vom API-Server ausfallen; Gatekeeper ergänzt ein Audit bestehender Ressourcen und eine gestufte Durchsetzung und ist ein System mehr im Betrieb.
  • Netzwerkisolation hat ihren Preis: ein durchsetzendes Plugin, zu pflegende Policies und Fehler, die wie Anwendungsfehler aussehen, wenn eine Regel zu eng ist.
  • Getrennte Deployments machen aus einer Grenze einen versionierten Vertrag, der über Rollouts hinweg in beide Richtungen kompatibel bleiben muss.
  • Sampling spart Kosten und nimmt den Nachweiswert. Es beibehalten und die Prüfspur anderswo führen.

Grenzen

  • Die Manifeste wurden gegen die Kubernetes-Schemata für 1.35, 1.36 und 1.37 validiert; die Admission-Policy wurde auf einen lokalen Wegwerf-API-Server ohne Nodes angewendet und mit serverseitigen Dry Runs ausgeübt; die Collector-Konfiguration wurde validiert und der Workflow gelintet. Nichts lief auf einem Cluster mit Nodes: Die Durchsetzung der Netzwerk-Policy, Rollouts und das Laufzeitverhalten des Collectors wurden nicht beobachtet.
  • Die Beispiele lassen Ingress-Regeln, Security Contexts, Ressourcen, Probes und Secrets weg.
  • Kubernetes ist ein Weg, diese Eigenschaften zu deployen. COADF setzt es nicht voraus.

Was dieses Profil nicht begründet

Wer diesem Profil folgt, begründet damit weder die Einhaltung regulatorischer Anforderungen noch eine Zertifizierung oder ein Verfahren zur Bewertung der Übereinstimmung mit Rechtsvorschriften, und nichts hier wird von COADF vorausgesetzt. Ein Cluster, der diese Manifeste zulässt, hat diese Manifeste zugelassen.

Getestete Referenzumgebung

  • kubeconform 0.8.0 · strikte Schemavalidierung gegen Kubernetes 1.35.0, 1.36.0 und 1.37.0; nicht auf einen Cluster angewendet
  • Kubernetes API server (envtest release) 1.37.0 · ein lokaler Wegwerf-kube-apiserver mit etcd und ohne Nodes: die Admission-Policy angewendet und zehn Fälle als serverseitige Dry Runs ausgeführt; nichts eingeplant, keine Durchsetzung im Netzwerk
  • OpenTelemetry Collector (contrib) 0.160.0 · otelcol-contrib validate
  • actionlint 1.7.12 · ohne shellcheck, die Shell in den run-Schritten wurde also nicht gelintet

Quellen

COADF Engineering Companion 1.0 · nicht normativ · bezieht sich auf COADF Core 2.2

Veröffentlichungsrechte vorbehalten. Für den COADF Engineering Companion 1.0 und seine Referenzbeispiele wird derzeit keine öffentliche Lizenz erteilt.

Schutzrechts- und Veröffentlichungsstatus