Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 47674969a1 | |||
| ce36db0579 |
@@ -1,9 +1,11 @@
|
|||||||
{
|
{
|
||||||
"phase": 0,
|
"phase": 0,
|
||||||
"stage": "clarify",
|
"stage": "complete",
|
||||||
"milestone": "v0.3",
|
"milestone": "v0.3",
|
||||||
"phase_role": "pre_execution",
|
"phase_role": "pre_execution",
|
||||||
"project": "atelier",
|
"project": "atelier",
|
||||||
"attempts": 0,
|
"attempts": 0,
|
||||||
"updated_at": "2026-08-05T03:08:00Z"
|
"updated_at": "2026-08-05T03:17:00Z",
|
||||||
|
"phase_tag": "v0.2.0",
|
||||||
|
"release_id": 468
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ NFR milestone: no separate minor tag. The final patch (v0.1.5) IS the v0.2 deliv
|
|||||||
|
|
||||||
| Phase | Name | Type | Status | Key Deliverables |
|
| Phase | Name | Type | Status | Key Deliverables |
|
||||||
|-------|------|------|--------|------------------|
|
|-------|------|------|--------|------------------|
|
||||||
| 0 | Pre-Execution | docs | active | Spec, clarify, research, ideate, plan, PERSONAS.md (extends platform-engineer, adds ml-engineer) |
|
| 0 | Pre-Execution | docs | complete | Spec, clarify, research, ideate, plan, PERSONAS.md (extends platform-engineer, adds ml-engineer) — shipped v0.2.0 |
|
||||||
| 1 | GitOps + Operators Domain | docs | pending | domains/gitops-operators/{first-principles, argocd, flux, operators, progressive-delivery}.md |
|
| 1 | GitOps + Operators Domain | docs | pending | domains/gitops-operators/{first-principles, argocd, flux, operators, progressive-delivery}.md |
|
||||||
| 2 | AI/ML Domain | docs | pending | domains/ai-ml/{first-principles, data-versioning, model-evaluation, serving, monitoring-drift}.md |
|
| 2 | AI/ML Domain | docs | pending | domains/ai-ml/{first-principles, data-versioning, model-evaluation, serving, monitoring-drift}.md |
|
||||||
| 3 | i18n + Compliance Domains | docs | pending | domains/i18n/{first-principles, locale-resources, formatting, rtl-bidi, testing-i18n}.md, domains/compliance/{first-principles, audit-logs, data-retention, policy-as-code, evidence}.md |
|
| 3 | i18n + Compliance Domains | docs | pending | domains/i18n/{first-principles, locale-resources, formatting, rtl-bidi, testing-i18n}.md, domains/compliance/{first-principles, audit-logs, data-retention, policy-as-code, evidence}.md |
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
# ArgoCD — Derived Rules
|
||||||
|
|
||||||
|
> Derives from `domains/gitops-operators/first-principles.md`.
|
||||||
|
> Applies P1–P10 to ArgoCD specifically. For the ArgoCD-vs-Flux
|
||||||
|
> decision, see the decision matrix at the end of this doc and in
|
||||||
|
> `flux.md`.
|
||||||
|
|
||||||
|
## What ArgoCD Is (P1 Git is the Source of Truth, P3 Pull, Don't Push)
|
||||||
|
|
||||||
|
- ArgoCD is a pull-based GitOps controller for Kubernetes. It runs
|
||||||
|
inside the target cluster, pulls desired state from git, and
|
||||||
|
reconciles the cluster to match. CI never holds `kubectl` rights
|
||||||
|
against the cluster (P3).
|
||||||
|
- An Application is a declarative binding of "this git path" to
|
||||||
|
"this cluster destination." The Application CRD is the unit of
|
||||||
|
reconciliation. The cluster is a derivative of git, never the
|
||||||
|
authority (P1).
|
||||||
|
- ArgoCD supports Helm charts, Kustomize overlays, ksonnet, and raw
|
||||||
|
manifests as source formats — see `domains/kubernetes/helm.md`
|
||||||
|
and `domains/kubernetes/kustomize.md`.
|
||||||
|
|
||||||
|
## Application CRD (P2 Declarative Over Imperative, P4 Continuous Reconciliation)
|
||||||
|
|
||||||
|
- An Application declares `source` (repo, path, revision, chart),
|
||||||
|
`destination` (server, namespace), and `syncPolicy`. The
|
||||||
|
reconciler loops continuously; drift is corrected automatically,
|
||||||
|
not on-demand (P4).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: payments-api
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
source:
|
||||||
|
repoURL: https://git.example.com/platform/payments
|
||||||
|
targetRevision: 1.2.3
|
||||||
|
path: manifests/prod
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: payments
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=false
|
||||||
|
```
|
||||||
|
|
||||||
|
- `automated.prune: true` deletes resources removed from git.
|
||||||
|
`selfHeal: true` corrects hand-edited drift back to git (P8).
|
||||||
|
Disable both for workloads that need manual approval gates.
|
||||||
|
|
||||||
|
## App-of-Apps (P6 Operators Encode Domain Knowledge, C6 Composability)
|
||||||
|
|
||||||
|
- The App-of-Apps pattern: one root Application points at a git
|
||||||
|
directory of child Application manifests. The root app reconciles
|
||||||
|
the children; the children reconcile the workloads. This is the
|
||||||
|
ArgoCD expression of composition — a fleet of apps as a tree of
|
||||||
|
Applications.
|
||||||
|
- Use App-of-Apps for cluster bootstrapping (one repo, many
|
||||||
|
clusters, many apps). Do not use it as a substitute for a package
|
||||||
|
manager; if you are templating hundreds of near-identical
|
||||||
|
Applications, use a generator (ApplicationSet) instead.
|
||||||
|
|
||||||
|
## Sync Waves and Hooks (P4 Continuous Reconciliation, P7 Reversibility)
|
||||||
|
|
||||||
|
- Sync waves order resources within a sync: `PreSync` → `Sync` →
|
||||||
|
`PostSync`. Use waves to run a job before a Deployment, or a
|
||||||
|
migration before the app that depends on it.
|
||||||
|
- Sync hooks (`PreSync`, `Sync`, `PostSync`, `SyncFail`) are
|
||||||
|
Resources annotated to execute at a wave boundary. A `SyncFail`
|
||||||
|
hook runs on sync failure — the abort path (P7).
|
||||||
|
- Wave ordering is a correctness mechanism, not a performance one.
|
||||||
|
Mis-ordered waves (e.g., app starts before its migration job)
|
||||||
|
are a correctness bug.
|
||||||
|
|
||||||
|
## Health and Status (P9 Failure is Observable and Surfaced)
|
||||||
|
|
||||||
|
- ArgoCD assesses every resource's health (`Healthy`, `Progressing`,
|
||||||
|
`Degraded`, `Missing`, `Suspended`) and surfaces the aggregate as
|
||||||
|
Application status. Sync status (`Synced`, `OutOfSync`) reports
|
||||||
|
drift against git.
|
||||||
|
- Health checks are pluggable via Lua scripts for custom CRDs. An
|
||||||
|
Operator-managed CRD without a health check reads as `Progressing`
|
||||||
|
forever — write one (see `operators.md`).
|
||||||
|
- Out-of-sync or degraded status must emit a notification (Slack,
|
||||||
|
PagerDuty, webhook). Silent drift is the bug (P9). Wire status to
|
||||||
|
`domains/observability/metrics.md`.
|
||||||
|
|
||||||
|
## Diff and Drift (P8 Reconcile, Don't Mutate by Hand, P4)
|
||||||
|
|
||||||
|
- `argocd app diff` shows the diff between git and live cluster.
|
||||||
|
A non-empty diff on a synced app is hand-edit drift — the
|
||||||
|
recovery is `selfHeal`, not a manual `kubectl apply` (P8).
|
||||||
|
- Drift detection runs continuously (P4). The gap between "git
|
||||||
|
changed" and "cluster matches git" is observable, not assumed.
|
||||||
|
|
||||||
|
## RBAC and SSO (P10 Least Privilege Reconciliation)
|
||||||
|
|
||||||
|
- ArgoCD's own RBAC governs who can view, sync, and admin
|
||||||
|
Applications. Bind to SSO (OIDC, SAML) for human identity; bind
|
||||||
|
the controller's service account to a Role scoped to the
|
||||||
|
namespaces it reconciles.
|
||||||
|
- The controller's credentials must not be `cluster-admin` (P10).
|
||||||
|
Use namespace-scoped Roles via `ApplicationSet` namespaces or
|
||||||
|
cluster-wide AppProject restrictions. See
|
||||||
|
`domains/kubernetes/rbac.md` and `domains/security/authorization.md`.
|
||||||
|
- AppProjects bound the blast radius of what an Application can
|
||||||
|
deploy (allowed repos, destinations, roles). One AppProject per
|
||||||
|
team or environment; the default project is for nothing in
|
||||||
|
production.
|
||||||
|
|
||||||
|
## Multi-Cluster (P4 Locality, P10)
|
||||||
|
|
||||||
|
- ArgoCD registers external clusters by secret. The controller
|
||||||
|
pulls from git and pushes to the registered cluster's API server.
|
||||||
|
The "pull, don't push" boundary (P3) is between the target
|
||||||
|
cluster's reconciler and CI — the controller-to-apiserver hop is
|
||||||
|
internal to the platform.
|
||||||
|
- Scope each registered cluster's credentials to the namespaces
|
||||||
|
ArgoCD manages there. Do not register a cluster with cluster-admin
|
||||||
|
and call it done (P10).
|
||||||
|
|
||||||
|
## Sync Windows (P5 Reversibility, P7)
|
||||||
|
|
||||||
|
- Sync windows restrict when automated sync runs (e.g., no syncs
|
||||||
|
during business hours, or syncs only in a maintenance window).
|
||||||
|
They are a reversibility mechanism: a bad commit lands in git,
|
||||||
|
but the sync window holds it until review.
|
||||||
|
- Sync windows do not replace health monitoring (P9). A degraded
|
||||||
|
app inside a window is still an incident.
|
||||||
|
|
||||||
|
## Secrets (P10, cross-link security/secrets)
|
||||||
|
|
||||||
|
- Do not store raw Secrets in the GitOps repo. Use a sealed-secret
|
||||||
|
controller (Bitnami Sealed Secrets, SOPS, External Secrets
|
||||||
|
Operator) so the git store holds encrypted material only. See
|
||||||
|
`domains/security/secrets.md` for the general secret-hygiene
|
||||||
|
principles.
|
||||||
|
|
||||||
|
## ArgoCD vs Flux — Decision Matrix (IDEATE-21, D-039)
|
||||||
|
|
||||||
|
| Axis | ArgoCD | Flux |
|
||||||
|
|------|--------|------|
|
||||||
|
| Architecture | Monolithic controller + Application CRD | Composable GitOps Toolkit controllers (source, kustomize, helm, notification) |
|
||||||
|
| Reconciliation unit | Application (one CRD per app) | Kustomization / HelmRelease (one per deploy unit) |
|
||||||
|
| UI | Web UI + CLI (full dashboard, tree view, diff viewer) | CLI-first; UI via Weave GitOps or FluxUI (add-on) |
|
||||||
|
| Sync model | Periodic poll or webhook; sync waves + hooks | Poll + webhook; runs continuously, no explicit sync waves |
|
||||||
|
| Multi-cluster | One ArgoCD manages many clusters (hub-and-spoke) | One Flux per cluster (per-cluster autonomy) |
|
||||||
|
| Templating in repo | Helm, Kustomize, ksonnet, raw manifests, Jsonnet | Helm, Kustomize, raw manifests |
|
||||||
|
| RBAC | Built-in RBAC + SSO + AppProjects | Kubernetes RBAC (no built-in RBAC layer) |
|
||||||
|
| Progressive delivery | Argo Rollouts (sister project, tight integration) | Flagger (sister project, tight integration) |
|
||||||
|
| Best for | Teams wanting a UI, multi-cluster from one pane, App-of-Apps bootstrapping | Teams wanting composable controllers, per-cluster autonomy, minimal footprint |
|
||||||
|
| Watch out for | Monolithic controller scaling, UI as ops crutch, AppProject sprawl | No native UI, steeper learning curve, manual multi-cluster orchestration |
|
||||||
|
|
||||||
|
- Use ArgoCD when you want a UI, central multi-cluster management,
|
||||||
|
and sync-wave ordering. Use Flux when you want composable
|
||||||
|
controllers, per-cluster autonomy, and a minimal footprint.
|
||||||
|
- Both are CNCF graduated and both implement the OpenGitOps
|
||||||
|
principles. The choice is architectural fit, not correctness. See
|
||||||
|
`flux.md` for the Flux-side perspective.
|
||||||
|
|
||||||
|
## What Violates ArgoCD Discipline
|
||||||
|
|
||||||
|
| Violation | Principle |
|
||||||
|
|-----------|-----------|
|
||||||
|
| CI pipeline with `kubectl` rights pushing to the cluster | P3 Pull, Don't Push |
|
||||||
|
| `argocd app set` used as the steady state instead of git | P1 Git is the Source of Truth |
|
||||||
|
| `selfHeal: false` on a prod app with no manual gate | P8 Reconcile, Don't Mutate by Hand |
|
||||||
|
| Controller ServiceAccount bound to `cluster-admin` | P10 Least Privilege Reconciliation |
|
||||||
|
| Sync failure with no notification wired | P9 Failure is Observable and Surfaced |
|
||||||
|
| AppProject with no destination restrictions in prod | P10 Least Privilege Reconciliation |
|
||||||
|
| Raw Secret in the GitOps repo | P10, `domains/security/secrets.md` |
|
||||||
|
| Manual `kubectl edit` on an ArgoCD-managed resource | P8 Reconcile, Don't Mutate by Hand |
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
# GitOps + Operators — First Principles
|
||||||
|
|
||||||
|
## 1. The Principles
|
||||||
|
|
||||||
|
### P1. Git is the Source of Truth
|
||||||
|
Desired state lives in a versioned, immutable git store. The
|
||||||
|
cluster is a derivative of git, never the authority. If a state
|
||||||
|
exists only in the cluster and not in git, it is drift, not truth.
|
||||||
|
The commit history is the audit trail and the rollback path.
|
||||||
|
|
||||||
|
### P2. Declarative Over Imperative
|
||||||
|
Express the desired cluster state, not the commands to reach it.
|
||||||
|
A manifest says what should exist; the reconciler makes it so.
|
||||||
|
Imperative `kubectl` is for inspection and incident response, not
|
||||||
|
for the steady state. This is the GitOps expression of
|
||||||
|
`domains/kubernetes/P1 Declarative Desired State` and
|
||||||
|
`domains/infrastructure-as-code/P1 Declarative Intent`.
|
||||||
|
|
||||||
|
### P3. Pull, Don't Push
|
||||||
|
Agents running inside the target pull desired state from git; the
|
||||||
|
target never accepts outside push credentials. No CI pipeline holds
|
||||||
|
`kubectl` rights against the production cluster. The cluster reaches
|
||||||
|
out to git, not the other way around. This is the security primitive
|
||||||
|
of GitOps: the blast radius of a compromised CI is bounded by what CI
|
||||||
|
can push, and a pull model gives CI nothing to push.
|
||||||
|
|
||||||
|
### P4. Continuous Reconciliation
|
||||||
|
The reconciliation loop is the primitive. Drift is detected and
|
||||||
|
corrected automatically, not on-demand. A manual `apply` is an
|
||||||
|
exception, not the workflow. The loop runs continuously; the gap
|
||||||
|
between "git changed" and "cluster matches git" is measured in
|
||||||
|
seconds, not tickets.
|
||||||
|
|
||||||
|
### P5. State is Immutable and Versioned
|
||||||
|
Every change to desired state is a commit. History is the audit
|
||||||
|
trail and the rollback path. A revert is a rollback; a force-push is
|
||||||
|
history deletion. The git store is treated like
|
||||||
|
`domains/infrastructure-as-code/P3 State is Truth` — lose it or
|
||||||
|
tamper with it, and you lose the ability to reason about the system.
|
||||||
|
|
||||||
|
### P6. Operators Encode Domain Knowledge
|
||||||
|
Operational expertise lives as CRDs plus controllers, not as
|
||||||
|
runbooks that humans must remember. An operator is a control loop
|
||||||
|
that encodes how to reconcile a specific domain (a database, a
|
||||||
|
message queue, a certificate). The operator is the deepest
|
||||||
|
expression of `domains/kubernetes/P1 Declarative Desired State` —
|
||||||
|
the domain knowledge is the desired state.
|
||||||
|
|
||||||
|
### P7. Progressive Delivery is Reversible by Construction
|
||||||
|
Canary and blue-green are staged, metric-gated, and one-command
|
||||||
|
abortable. Promotion without a rollback path is a violation. A
|
||||||
|
rollout that cannot be aborted is a deploy, not a progressive
|
||||||
|
delivery. This is the GitOps extension of
|
||||||
|
`domains/devops/P5 Progressive Delivery` and
|
||||||
|
`domains/kubernetes/P10 Roll Forward, Roll Back`.
|
||||||
|
|
||||||
|
### P8. Reconcile, Don't Mutate by Hand
|
||||||
|
Manual `kubectl apply` or `kubectl edit` on a GitOps-managed
|
||||||
|
resource is an incident. The reconciler will overwrite the hand
|
||||||
|
edit on the next loop; the hand edit was never truth. Drift back to
|
||||||
|
git is the recovery, not the failure. This is the GitOps angle on
|
||||||
|
`domains/infrastructure-as-code/P9 Drift is Recoverable`.
|
||||||
|
|
||||||
|
### P9. Failure is Observable and Surfaced
|
||||||
|
Sync failures, health degradation, and rollout-stall events emit
|
||||||
|
status and notifications. Silent drift is the bug. A GitOps
|
||||||
|
controller that fails to sync without surfacing the failure has
|
||||||
|
violated the contract — you cannot fix what you cannot see
|
||||||
|
(`domains/observability/metrics.md`).
|
||||||
|
|
||||||
|
### P10. Least Privilege Reconciliation
|
||||||
|
The controller's credentials are scoped to the namespaces and
|
||||||
|
resources it reconciles. No `cluster-admin` GitOps robots. One
|
||||||
|
credential set per boundary; the reconciler sees only what it
|
||||||
|
reconciles. This is the GitOps angle on
|
||||||
|
`domains/kubernetes/P7 RBAC by Intent, Not Identity` and
|
||||||
|
`domains/security/authorization.md`.
|
||||||
|
|
||||||
|
## 2. Core Principle Trace
|
||||||
|
|
||||||
|
Each GitOps + Operators P-rule derives from one or more core
|
||||||
|
C-rules (C1–C8). The matrix extension lands in P4 of the v0.3
|
||||||
|
plan; the traces below are authoritative.
|
||||||
|
|
||||||
|
| P-rule | Core | Why |
|
||||||
|
|--------|------|-----|
|
||||||
|
| P1 Git is the Source of Truth | C1, C5 | Correctness of state; reversibility via history |
|
||||||
|
| P2 Declarative Over Imperative | C2, C3 | Clarity of intent; simplicity of mental model |
|
||||||
|
| P3 Pull, Don't Push | C1, C4 | Correctness via security; locality of credentials |
|
||||||
|
| P4 Continuous Reconciliation | C7, C1 | Observability of drift; correctness of convergence |
|
||||||
|
| P5 State is Immutable and Versioned | C5 | Reversibility via version history |
|
||||||
|
| P6 Operators Encode Domain Knowledge | C6, C2 | Composability of expertise; clarity of operational intent |
|
||||||
|
| P7 Progressive Delivery is Reversible | C5, C1 | Reversibility of promotion; correctness of abort |
|
||||||
|
| P8 Reconcile, Don't Mutate by Hand | C1, C7 | Correctness of single source; observability of drift |
|
||||||
|
| P9 Failure is Observable and Surfaced | C7 | Observability of reconciliation |
|
||||||
|
| P10 Least Privilege Reconciliation | C1, C8 | Correctness via security; economy of trust |
|
||||||
|
|
||||||
|
## 3. What Violates These Principles
|
||||||
|
|
||||||
|
| Violation | Principle Breached |
|
||||||
|
|-----------|-------------------|
|
||||||
|
| CI pipeline pushes manifests to the cluster | P3 Pull, Don't Push |
|
||||||
|
| A resource exists in the cluster but not in git | P1 Git is the Source of Truth |
|
||||||
|
| `kubectl edit` on a GitOps-managed resource | P8 Reconcile, Don't Mutate by Hand |
|
||||||
|
| Reconciler with `cluster-admin` ClusterRoleBinding | P10 Least Privilege Reconciliation |
|
||||||
|
| Sync failure with no status or notification | P9 Failure is Observable and Surfaced |
|
||||||
|
| Canary with no abort/rollback path | P7 Progressive Delivery is Reversible |
|
||||||
|
| Operator runbook that exists only in a wiki | P6 Operators Encode Domain Knowledge |
|
||||||
|
| Reconciler that applies on a cron, not continuously | P4 Continuous Reconciliation |
|
||||||
|
| Force-push rewrites GitOps repo history | P5 State is Immutable and Versioned |
|
||||||
|
| Imperative deploy script as the steady state | P2 Declarative Over Imperative |
|
||||||
|
|
||||||
|
## 4. Relationship to Other Domains
|
||||||
|
|
||||||
|
GitOps + Operators is the deployment-automation layer above
|
||||||
|
`domains/kubernetes/` and `domains/infrastructure-as-code/`. It
|
||||||
|
borrows their declarative-reconciliation model and adds the
|
||||||
|
git-as-source-of-truth and pull-based credential boundaries. Cross
|
||||||
|
links are one-directional (per D-026 extended):
|
||||||
|
|
||||||
|
- `domains/kubernetes/P1 Declarative Desired State` ← P2
|
||||||
|
- `domains/kubernetes/P10 Roll Forward, Roll Back` ← P7
|
||||||
|
- `domains/infrastructure-as-code/P1 Declarative Intent` ← P2
|
||||||
|
- `domains/infrastructure-as-code/P3 State is Truth` ← P1, P5
|
||||||
|
- `domains/infrastructure-as-code/P9 Drift is Recoverable` ← P4, P8
|
||||||
|
- `domains/devops/P4 Rollback First` ← P5, P7
|
||||||
|
- `domains/devops/P5 Progressive Delivery` ← P7
|
||||||
|
- `domains/devops/P6 Configuration as Code` ← P1, P2
|
||||||
|
- `domains/security/secrets.md` ← P3, P10 (reconciliation credentials)
|
||||||
|
- `domains/security/supply-chain.md` ← P5 (signed, immutable provenance)
|
||||||
|
- `domains/observability/metrics.md` ← P4, P9 (reconciliation + rollout metrics)
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
# Flux — Derived Rules
|
||||||
|
|
||||||
|
> Derives from `domains/gitops-operators/first-principles.md`.
|
||||||
|
> Applies P1–P10 to Flux specifically. For the ArgoCD-vs-Flux
|
||||||
|
> decision, see the decision matrix at the end of this doc and in
|
||||||
|
> `argocd.md`.
|
||||||
|
|
||||||
|
## What Flux Is (P1 Git is the Source of Truth, P3 Pull, Don't Push)
|
||||||
|
|
||||||
|
- Flux is a set of composable controllers — the GitOps Toolkit —
|
||||||
|
that run inside the target cluster, pull desired state from git
|
||||||
|
or OCI registries, and reconcile the cluster to match. CI never
|
||||||
|
holds `kubectl` rights against the cluster (P3).
|
||||||
|
- The composable-controller architecture is a C6 (Composability)
|
||||||
|
exemplar: each controller does one thing (source, kustomize, helm,
|
||||||
|
notification) and the controllers compose into a full GitOps
|
||||||
|
system.
|
||||||
|
- Flux supports Helm releases, Kustomize overlays, and raw
|
||||||
|
manifests — see `domains/kubernetes/helm.md` and
|
||||||
|
`domains/kubernetes/kustomize.md`.
|
||||||
|
|
||||||
|
## GitOps Toolkit Controllers (P6 Composability, P4 Continuous Reconciliation)
|
||||||
|
|
||||||
|
- **source-controller** — pulls git, Helm, OCI, and bucket sources;
|
||||||
|
emits artifacts (tarballs) with a digest. The source is the
|
||||||
|
pinned input to reconciliation (P5 versioning by digest).
|
||||||
|
- **kustomize-controller** — reconciles Kustomization CRDs against
|
||||||
|
the artifacts from source-controller. Runs continuously (P4).
|
||||||
|
- **helm-controller** — reconciles HelmRelease CRDs against Helm
|
||||||
|
charts from source-controller.
|
||||||
|
- **notification-controller** — emits events and notifications for
|
||||||
|
sync, health, and source-readiness events (P9).
|
||||||
|
- **image-automation-controller** (optional) — updates git with new
|
||||||
|
image tags when a policy matches, closing the "latest image"
|
||||||
|
loop declaratively.
|
||||||
|
|
||||||
|
## Kustomization CRD (P2 Declarative Over Imperative, P4)
|
||||||
|
|
||||||
|
- A Kustomization binds "this source" to "this target namespace"
|
||||||
|
with a reconciliation interval. The reconciler loops
|
||||||
|
continuously; drift is corrected automatically (P4).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: payments-api
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: platform
|
||||||
|
namespace: flux-system
|
||||||
|
path: ./manifests/prod
|
||||||
|
targetNamespace: payments
|
||||||
|
interval: 1m
|
||||||
|
prune: true
|
||||||
|
wait: true
|
||||||
|
healthChecks:
|
||||||
|
- apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: payments-api
|
||||||
|
namespace: payments
|
||||||
|
```
|
||||||
|
|
||||||
|
- `prune: true` deletes resources removed from git. `wait: true`
|
||||||
|
waits for health checks before declaring the Kustomization ready.
|
||||||
|
Disable prune for workloads that need manual removal gates.
|
||||||
|
|
||||||
|
## HelmRelease CRD (P6 Composability, cross-link helm.md)
|
||||||
|
|
||||||
|
- A HelmRelease binds a Helm chart (from a HelmRepository or OCI
|
||||||
|
source) to target values and a target namespace. helm-controller
|
||||||
|
renders and applies it. See `domains/kubernetes/helm.md` for the
|
||||||
|
chart model.
|
||||||
|
- Pin the chart version in the HelmRepository or the HelmRelease.
|
||||||
|
Never float `latest` — unversioned charts drift (P5).
|
||||||
|
|
||||||
|
## OCI Sources (P5 State is Immutable and Versioned)
|
||||||
|
|
||||||
|
- source-controller can pull from OCI registries (Helm charts as
|
||||||
|
OCI artifacts, or generic OCI repositories). The digest is the
|
||||||
|
version — immutable by construction (P5).
|
||||||
|
- OCI sources close the supply-chain loop: the manifest is signed
|
||||||
|
and immutable in the registry, and Flux pulls it by digest. Cross-
|
||||||
|
link `domains/security/supply-chain.md` for signed-provenance
|
||||||
|
principles.
|
||||||
|
|
||||||
|
## Reconciliation and Drift (P4 Continuous Reconciliation, P8)
|
||||||
|
|
||||||
|
- Flux reconciles on `interval` (default 1m) and on webhook event.
|
||||||
|
Drift between git and cluster is detected each interval and
|
||||||
|
corrected (with `prune` + `selfHeal` semantics).
|
||||||
|
- Hand-edited drift on a Flux-managed resource is overwritten on the
|
||||||
|
next loop — the hand edit was never truth (P8). The recovery is
|
||||||
|
to fix git, not to `kubectl apply`.
|
||||||
|
|
||||||
|
## Notifications and Events (P9 Failure is Observable and Surfaced)
|
||||||
|
|
||||||
|
- notification-controller emits events for source readiness, sync
|
||||||
|
success/failure, and health transitions. Wire them to Slack,
|
||||||
|
PagerDuty, or a webhook. Silent drift is the bug (P9).
|
||||||
|
- Events flow to `domains/observability/metrics.md` via the
|
||||||
|
notification controller's provider model — sync and health as
|
||||||
|
first-class signals.
|
||||||
|
|
||||||
|
## RBAC and Multi-Cluster (P10 Least Privilege Reconciliation, P4)
|
||||||
|
|
||||||
|
- Flux's controllers run with a ServiceAccount in `flux-system`.
|
||||||
|
Scope that account to the namespaces Flux reconciles. Do not bind
|
||||||
|
it to `cluster-admin` (P10). See `domains/kubernetes/rbac.md` and
|
||||||
|
`domains/security/authorization.md`.
|
||||||
|
- Flux is per-cluster by design (one Flux install per cluster). For
|
||||||
|
multi-cluster, use one repo with per-cluster paths, or a fleet
|
||||||
|
tool that bootstraps Flux per cluster. Per-cluster autonomy is a
|
||||||
|
feature, not a limitation — it bounds the blast radius of a
|
||||||
|
compromised controller (P4 locality, P10).
|
||||||
|
|
||||||
|
## Secrets (P10, cross-link security/secrets)
|
||||||
|
|
||||||
|
- Do not store raw Secrets in the GitOps repo. Use the
|
||||||
|
SOPS-compatible decryption in kustomize-controller, or External
|
||||||
|
Secrets Operator, so the git store holds encrypted material only.
|
||||||
|
See `domains/security/secrets.md`.
|
||||||
|
|
||||||
|
## ArgoCD vs Flux — Decision Matrix (IDEATE-21, D-039)
|
||||||
|
|
||||||
|
| Axis | ArgoCD | Flux |
|
||||||
|
|------|--------|------|
|
||||||
|
| Architecture | Monolithic controller + Application CRD | Composable GitOps Toolkit controllers (source, kustomize, helm, notification) |
|
||||||
|
| Reconciliation unit | Application (one CRD per app) | Kustomization / HelmRelease (one per deploy unit) |
|
||||||
|
| UI | Web UI + CLI (full dashboard, tree view, diff viewer) | CLI-first; UI via Weave GitOps or FluxUI (add-on) |
|
||||||
|
| Sync model | Periodic poll or webhook; sync waves + hooks | Poll + webhook; runs continuously, no explicit sync waves |
|
||||||
|
| Multi-cluster | One ArgoCD manages many clusters (hub-and-spoke) | One Flux per cluster (per-cluster autonomy) |
|
||||||
|
| Templating in repo | Helm, Kustomize, ksonnet, raw manifests, Jsonnet | Helm, Kustomize, raw manifests |
|
||||||
|
| RBAC | Built-in RBAC + SSO + AppProjects | Kubernetes RBAC (no built-in RBAC layer) |
|
||||||
|
| Progressive delivery | Argo Rollouts (sister project, tight integration) | Flagger (sister project, tight integration) |
|
||||||
|
| Best for | Teams wanting a UI, multi-cluster from one pane, App-of-Apps bootstrapping | Teams wanting composable controllers, per-cluster autonomy, minimal footprint |
|
||||||
|
| Watch out for | Monolithic controller scaling, UI as ops crutch, AppProject sprawl | No native UI, steeper learning curve, manual multi-cluster orchestration |
|
||||||
|
|
||||||
|
- Use Flux when you want composable controllers, per-cluster
|
||||||
|
autonomy, and a minimal footprint. Use ArgoCD when you want a UI,
|
||||||
|
central multi-cluster management, and sync-wave ordering.
|
||||||
|
- Both are CNCF graduated and both implement the OpenGitOps
|
||||||
|
principles. The choice is architectural fit, not correctness. See
|
||||||
|
`argocd.md` for the ArgoCD-side perspective.
|
||||||
|
|
||||||
|
## What Violates Flux Discipline
|
||||||
|
|
||||||
|
| Violation | Principle |
|
||||||
|
|-----------|-----------|
|
||||||
|
| CI pipeline with `kubectl` rights pushing to the cluster | P3 Pull, Don't Push |
|
||||||
|
| HelmRelease with no pinned chart version | P5 State is Immutable and Versioned |
|
||||||
|
| Flux ServiceAccount bound to `cluster-admin` | P10 Least Privilege Reconciliation |
|
||||||
|
| Kustomization with no `healthChecks` on a prod app | P9 Failure is Observable and Surfaced |
|
||||||
|
| No notification provider wired for sync failures | P9 Failure is Observable and Surfaced |
|
||||||
|
| Raw Secret in the GitOps repo | P10, `domains/security/secrets.md` |
|
||||||
|
| Manual `kubectl edit` on a Flux-managed resource | P8 Reconcile, Don't Mutate by Hand |
|
||||||
|
| `interval: 24h` on a prod Kustomization (drift window too wide) | P4 Continuous Reconciliation |
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
# Operators — Derived Rules
|
||||||
|
|
||||||
|
> Derives from `domains/gitops-operators/first-principles.md`.
|
||||||
|
> Applies P6 (Operators Encode Domain Knowledge) primarily, with
|
||||||
|
> P1, P4, P8, P9, P10. Cross-links `domains/kubernetes/workloads.md`
|
||||||
|
> and `domains/kubernetes/rbac.md` for the underlying controller
|
||||||
|
> model, and `domains/infrastructure-as-code/modules.md` for the
|
||||||
|
> module-vs-operator boundary.
|
||||||
|
|
||||||
|
## What an Operator Is (P6 Operators Encode Domain Knowledge)
|
||||||
|
|
||||||
|
- An Operator is a Kubernetes controller that encodes human
|
||||||
|
operational knowledge as CRDs plus a control loop. The operator
|
||||||
|
reconciles a domain-specific resource (a database, a message
|
||||||
|
queue, a certificate, a ML model) to a desired state.
|
||||||
|
- The operator is the deepest expression of
|
||||||
|
`domains/kubernetes/P1 Declarative Desired State`: the domain
|
||||||
|
knowledge itself is the desired state. A runbook that lives only
|
||||||
|
in a wiki is operational knowledge that has not been encoded —
|
||||||
|
the operator is the encoding (P6).
|
||||||
|
- An operator runs inside the cluster, observes its CRDs, and acts.
|
||||||
|
It is a pull-based reconciler by construction — see
|
||||||
|
`domains/gitops-operators/first-principles.md` P3.
|
||||||
|
|
||||||
|
## CRDs and Controllers (P2 Declarative Over Imperative, P4 Continuous Reconciliation)
|
||||||
|
|
||||||
|
- A CustomResourceDefinition (CRD) defines the schema of the
|
||||||
|
domain resource. The controller watches instances of that CRD
|
||||||
|
and reconciles current → desired (P4).
|
||||||
|
- The CRD is the public contract of the operator. Version it
|
||||||
|
(`v1alpha1` → `v1beta1` → `v1`) and preserve backward
|
||||||
|
compatibility — see `domains/api/versioning.md` for the general
|
||||||
|
API-evolution principles. A CRD is an API surface, not an
|
||||||
|
internal type.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: postgres.example.com/v1
|
||||||
|
kind: PostgresCluster
|
||||||
|
metadata:
|
||||||
|
name: payments-db
|
||||||
|
namespace: payments
|
||||||
|
spec:
|
||||||
|
replicas: 3
|
||||||
|
version: "16"
|
||||||
|
storage:
|
||||||
|
size: 100Gi
|
||||||
|
storageClass: fast-ssd
|
||||||
|
backup:
|
||||||
|
schedule: "0 2 * * *"
|
||||||
|
retention: 7d
|
||||||
|
```
|
||||||
|
|
||||||
|
- The controller reconciles this spec: creates StatefulSets, PVCs,
|
||||||
|
Services, backup CronJobs. The user declares intent; the operator
|
||||||
|
makes it so (P2, P6).
|
||||||
|
|
||||||
|
## The Control Loop (P4 Continuous Reconciliation, P8)
|
||||||
|
|
||||||
|
- The loop watches CRD instances, compares current vs desired, and
|
||||||
|
acts to converge. Drift (a hand-deleted pod, a failed backup) is
|
||||||
|
detected and corrected each loop (P4).
|
||||||
|
- An operator-managed resource should not be hand-edited (P8). The
|
||||||
|
operator owns the subordinate resources (StatefulSets, PVCs); a
|
||||||
|
manual `kubectl edit` on a subordinate is drift the operator will
|
||||||
|
overwrite.
|
||||||
|
|
||||||
|
## Operator SDK and OLM (P6 Composability, C6)
|
||||||
|
|
||||||
|
- The Operator SDK scaffolds a controller from a CRD (Go, Ansible,
|
||||||
|
Helm). Use it to avoid re-implementing the controller boilerplate.
|
||||||
|
- Operator Lifecycle Manager (OLM) installs, updates, and manages
|
||||||
|
operators as first-class cluster components. OLM is the package
|
||||||
|
manager for operators — the operator analogue of
|
||||||
|
`domains/kubernetes/helm.md` for workloads.
|
||||||
|
- An operator published via OLM is a versioned, catalog-tracked
|
||||||
|
artifact. Pin the operator version; do not float `latest` (P5
|
||||||
|
applies to operators as much as to manifests).
|
||||||
|
|
||||||
|
## When to Write an Operator vs a Helm Chart (P6, C6 Composability)
|
||||||
|
|
||||||
|
| Axis | Helm chart | Operator |
|
||||||
|
|------|-----------|----------|
|
||||||
|
| Day-2 operations | None — chart installs, you operate | Encoded — operator reconciles lifecycle (backup, resize, failover, upgrade) |
|
||||||
|
| State | Static manifests | Live control loop watching CRDs |
|
||||||
|
| Day-1 install | Strong fit — package and install | Overkill if install is all you need |
|
||||||
|
| Day-2 reconcile | None — drift is manual | Continuous — drift corrected each loop |
|
||||||
|
| Domain knowledge | Lives in runbooks + on-call | Lives in the controller code |
|
||||||
|
| Best for | Off-the-shelf apps, stateless services, one-shot deploys | Stateful apps, complex lifecycles, day-2 automation (backup, scale, failover, version upgrades) |
|
||||||
|
| Watch out for | Templating complexity, no day-2 reconcile | Controller complexity, multi-team maintenance burden, scope creep |
|
||||||
|
|
||||||
|
- Write an operator when the day-2 operations (backup, failover,
|
||||||
|
resize, version upgrade) are non-trivial and repeated. Write a
|
||||||
|
Helm chart when install is all you need and day-2 is run by a
|
||||||
|
human or a separate tool.
|
||||||
|
- Do not write an operator to wrap a Helm chart and call it day-2
|
||||||
|
automation — that is a Helm chart with extra steps. See
|
||||||
|
`domains/infrastructure-as-code/modules.md` for the
|
||||||
|
module-vs-copy boundary (the operator-vs-chart boundary is its
|
||||||
|
analogue).
|
||||||
|
|
||||||
|
## Scope and Responsibility Boundaries (P10 Least Privilege, C6)
|
||||||
|
|
||||||
|
- An operator owns one domain. An operator that manages databases
|
||||||
|
and message queues and certificates is doing three jobs — split
|
||||||
|
it. Scope creep is the most common operator failure mode (P6
|
||||||
|
violation: the encoded knowledge is no longer coherent).
|
||||||
|
- The operator's ServiceAccount must be scoped to the resources it
|
||||||
|
manages (P10). A database operator that needs `cluster-admin` to
|
||||||
|
create a StatefulSet has the wrong RBAC — see
|
||||||
|
`domains/kubernetes/rbac.md` and `domains/security/authorization.md`.
|
||||||
|
- One operator per CRD family; one ServiceAccount per operator; one
|
||||||
|
namespace per operator (or a shared `operators` namespace with
|
||||||
|
strict RoleBindings). Default namespace is for nothing in
|
||||||
|
production.
|
||||||
|
|
||||||
|
## Failure and Observability (P9 Failure is Observable and Surfaced)
|
||||||
|
|
||||||
|
- An operator must surface its reconcile status on the CRD
|
||||||
|
(`status.conditions`, `status.observedGeneration`). A CRD with no
|
||||||
|
status is an operator that fails silently (P9).
|
||||||
|
- Wire operator events to notifications and metrics. A failed
|
||||||
|
backup, a stuck failover, a version-upgrade stall must emit a
|
||||||
|
signal — see `domains/observability/metrics.md`.
|
||||||
|
- An operator that reconciles but does not report health is a
|
||||||
|
black box. The GitOps controller (ArgoCD/Flux) will read it as
|
||||||
|
`Progressing` forever — write the health check (see `argocd.md`
|
||||||
|
"Health and Status").
|
||||||
|
|
||||||
|
## What Violates Operator Discipline
|
||||||
|
|
||||||
|
| Violation | Principle |
|
||||||
|
|-----------|-----------|
|
||||||
|
| Operator that manages databases + queues + certs | P6 Operators Encode Domain Knowledge (scope creep) |
|
||||||
|
| Operator ServiceAccount bound to `cluster-admin` | P10 Least Privilege Reconciliation |
|
||||||
|
| CRD with no `status.conditions` | P9 Failure is Observable and Surfaced |
|
||||||
|
| Operator with no health check wired to GitOps | P9, `argocd.md` Health and Status |
|
||||||
|
| Unversioned CRD (`v1` shipped without alpha/beta) | P5, `domains/api/versioning.md` |
|
||||||
|
| Manual `kubectl edit` on an operator-managed subordinate | P8 Reconcile, Don't Mutate by Hand |
|
||||||
|
| Operator that wraps a Helm chart and adds no day-2 logic | P6 (no knowledge encoded) |
|
||||||
|
| Operator runbook that exists only in a wiki | P6 Operators Encode Domain Knowledge |
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
# Progressive Delivery — Derived Rules
|
||||||
|
|
||||||
|
> Derives from `domains/gitops-operators/first-principles.md`.
|
||||||
|
> Applies P7 (Progressive Delivery is Reversible by Construction)
|
||||||
|
> primarily, with P4, P9. Cross-links `domains/devops/first-principles.md`
|
||||||
|
> P4 Rollback First and P5 Progressive Delivery, and
|
||||||
|
> `domains/observability/metrics.md` for the analysis signals.
|
||||||
|
|
||||||
|
## What Progressive Delivery Is (P7 Reversible by Construction)
|
||||||
|
|
||||||
|
- Progressive delivery shifts traffic in stages (canary, blue-green)
|
||||||
|
gated by analysis (metrics, counters, error rates). Each stage is
|
||||||
|
metric-checked; a failed gate aborts the rollout and reverts to
|
||||||
|
the prior stable version. Promotion without a rollback path is a
|
||||||
|
violation (P7).
|
||||||
|
- Progressive delivery is the GitOps extension of
|
||||||
|
`domains/devops/P5 Progressive Delivery` and
|
||||||
|
`domains/kubernetes/P10 Roll Forward, Roll Back`. The k8s rolling
|
||||||
|
update is the floor; progressive delivery adds metric-gated
|
||||||
|
promotion and one-command abort.
|
||||||
|
- Two sister projects dominate: **Argo Rollouts** (Argo ecosystem)
|
||||||
|
and **Flagger** (Flux ecosystem). Both implement the same pattern
|
||||||
|
— a Rollout CRD replaces a Deployment, an analysis drives the
|
||||||
|
gates, an abort reverts traffic.
|
||||||
|
|
||||||
|
## The Rollout CRD (P2 Declarative Over Imperative, P7)
|
||||||
|
|
||||||
|
- A Rollout (Argo Rollouts) or Canary/Flag (Flagger) is a CRD that
|
||||||
|
replaces the Deployment as the reconciled resource. It declares
|
||||||
|
the strategy (canary, blue-green), the traffic split, and the
|
||||||
|
analysis gates. The controller reconciles traffic and pods to
|
||||||
|
match.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Rollout
|
||||||
|
metadata:
|
||||||
|
name: payments-api
|
||||||
|
namespace: payments
|
||||||
|
spec:
|
||||||
|
replicas: 10
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: payments-api
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: payments-api
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: api
|
||||||
|
image: registry.example.com/payments-api:1.2.3
|
||||||
|
strategy:
|
||||||
|
canary:
|
||||||
|
trafficRouting:
|
||||||
|
istio:
|
||||||
|
virtualService:
|
||||||
|
name: payments-vs
|
||||||
|
routes: [primary]
|
||||||
|
steps:
|
||||||
|
- setWeight: 5
|
||||||
|
- pause: { duration: 2m }
|
||||||
|
- analysis:
|
||||||
|
templates:
|
||||||
|
- templateName: success-rate
|
||||||
|
- setWeight: 25
|
||||||
|
- pause: { duration: 5m }
|
||||||
|
- analysis:
|
||||||
|
templates:
|
||||||
|
- templateName: success-rate
|
||||||
|
- setWeight: 50
|
||||||
|
- pause: { duration: 5m }
|
||||||
|
- setWeight: 100
|
||||||
|
```
|
||||||
|
|
||||||
|
- Each `setWeight` shifts traffic; each `pause` holds for
|
||||||
|
observation; each `analysis` runs a metric gate. A failed
|
||||||
|
analysis aborts the rollout and reverts traffic to the stable
|
||||||
|
ReplicaSet (P7).
|
||||||
|
|
||||||
|
## Canary vs Blue-Green (P7, C3 Simplicity)
|
||||||
|
|
||||||
|
| Strategy | Mechanism | Cost | Best for |
|
||||||
|
|----------|-----------|------|----------|
|
||||||
|
| Canary | Shift a small % of traffic to the new version; increase on gate success | Low (few new pods) | Most production rollouts; metric-gated, gradual |
|
||||||
|
| Blue-Green | Run two full environments; switch traffic all-at-once | High (2× capacity) | Schema-breaking changes, instant rollback, low-frequency deploys |
|
||||||
|
|
||||||
|
- Canary is the default — it is reversible by construction (P7)
|
||||||
|
and economical (C8). Blue-green is for changes that cannot be
|
||||||
|
partial (a breaking schema migration, a full cutover).
|
||||||
|
- A canary with no analysis gate is a slow blue-green — it is not
|
||||||
|
progressive delivery. The gate is what makes it progressive (P7).
|
||||||
|
|
||||||
|
## Analysis Templates (P9 Failure is Observable and Surfaced, P7)
|
||||||
|
|
||||||
|
- An AnalysisTemplate declares the metric query, the success
|
||||||
|
threshold, and the count of samples. The rollout controller runs
|
||||||
|
the analysis at each gate; a failed analysis aborts the rollout.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: AnalysisTemplate
|
||||||
|
metadata:
|
||||||
|
name: success-rate
|
||||||
|
namespace: payments
|
||||||
|
spec:
|
||||||
|
metrics:
|
||||||
|
- name: success-rate
|
||||||
|
interval: 1m
|
||||||
|
successCondition: result[0] >= 0.99
|
||||||
|
failureLimit: 2
|
||||||
|
provider:
|
||||||
|
prometheus:
|
||||||
|
address: http://prometheus.observability:9090
|
||||||
|
query: |
|
||||||
|
sum(rate(http_requests_total{job="payments-api",code!~"5.."}[2m]))
|
||||||
|
/
|
||||||
|
sum(rate(http_requests_total{job="payments-api"}[2m]))
|
||||||
|
```
|
||||||
|
|
||||||
|
- `successCondition` is the gate; `failureLimit` is the tolerance
|
||||||
|
for transient blips. A single failed sample aborts immediately if
|
||||||
|
`failureLimit: 0`; tolerate noise with `failureLimit: 2`.
|
||||||
|
- The metric is the abort signal — see `domains/observability/metrics.md`
|
||||||
|
for the SLI/SLO discipline that makes the gate meaningful. A gate
|
||||||
|
on an undefined SLO is a gate on noise.
|
||||||
|
|
||||||
|
## Argo Rollouts vs Flagger (P6 Composability, P7)
|
||||||
|
|
||||||
|
| Axis | Argo Rollouts | Flagger |
|
||||||
|
|------|---------------|---------|
|
||||||
|
| Ecosystem | Argo (ArgoCD sister project) | Flux (Flux sister project) |
|
||||||
|
| CRD | `Rollout` (replaces `Deployment`) | `Canary` / `Flag` (wraps a `Deployment`) |
|
||||||
|
| Traffic providers | Istio, NGINX, ALB, SMI, Traefik, Ambassador | Istio, NGINX, Linkerd, SMI, App Mesh, Gloo, Contour |
|
||||||
|
| Analysis sources | Prometheus, Datadog, Wavefront, NewRelic, CloudWatch, Graphite, Kayenta | Prometheus, Datadog, CloudWatch, Stackdriver, Elasticsearch, Graphite |
|
||||||
|
| Integration | Tight with ArgoCD (UI shows rollout) | Tight with Flux (events via notification-controller) |
|
||||||
|
| Learning curve | Rollout CRD replaces Deployment (migration cost) | Wraps existing Deployment (lower migration cost) |
|
||||||
|
| Best for | ArgoCD shops wanting rollout in the Argo UI | Flux shops wanting progressive delivery with minimal migration |
|
||||||
|
|
||||||
|
- Both implement the same pattern. The choice follows your GitOps
|
||||||
|
controller — Argo Rollouts with ArgoCD, Flagger with Flux. Mixing
|
||||||
|
is possible but not idiomatic.
|
||||||
|
|
||||||
|
## Abort and Rollback (P7 Reversible by Construction, P5)
|
||||||
|
|
||||||
|
- An abort reverts traffic to the stable ReplicaSet immediately. A
|
||||||
|
rollout without a tested abort is a prototype (P7).
|
||||||
|
- The abort must be one-command (or one-gate-failure). A
|
||||||
|
progressive delivery that requires manual rollback steps has
|
||||||
|
lost the "reversible by construction" property — it is a deploy
|
||||||
|
with extra steps.
|
||||||
|
- Test the abort path in staging. An abort that has never been
|
||||||
|
exercised will fail when you need it most — see
|
||||||
|
`domains/devops/first-principles.md` P4 Rollback First.
|
||||||
|
|
||||||
|
## Observability (P9 Failure is Observable and Surfaced)
|
||||||
|
|
||||||
|
- Progressive delivery is only as good as its metrics. A rollout
|
||||||
|
gated on a metric that is not tracked is ungated — the gate is
|
||||||
|
theater (P9).
|
||||||
|
- Wire rollout status (phase, weight, analysis result) to
|
||||||
|
notifications and dashboards. A stalled rollout with no signal is
|
||||||
|
silent drift (P9). See `domains/observability/metrics.md`.
|
||||||
|
- Cross-link `domains/kubernetes/workloads.md` for the underlying
|
||||||
|
Deployment/ReplicaSet model that progressive delivery replaces.
|
||||||
|
|
||||||
|
## What Violates Progressive Delivery Discipline
|
||||||
|
|
||||||
|
| Violation | Principle |
|
||||||
|
|-----------|-----------|
|
||||||
|
| Canary with no analysis gate | P7 Progressive Delivery is Reversible by Construction |
|
||||||
|
| Rollout with no tested abort path | P7, `domains/devops/P4 Rollback First` |
|
||||||
|
| Analysis gate on an undefined SLO | P9 Failure is Observable and Surfaced |
|
||||||
|
| Blue-green with no 2× capacity budget | C8 Economy (blue-green is a cost decision) |
|
||||||
|
| Rollout stalled with no notification | P9 Failure is Observable and Surfaced |
|
||||||
|
| Manual `kubectl` traffic shift on a Rollout-managed service | P8 Reconcile, Don't Mutate by Hand |
|
||||||
|
| `failureLimit: 0` on a noisy metric (constant false aborts) | P4 Continuous Reconciliation (gate noise tolerance) |
|
||||||
Reference in New Issue
Block a user