Day-2 operations
The operator acts on one cluster-scoped ClusterRuntime named cluster. Each
change it makes to the GPU stack is a cluster-scoped RuntimeRollout between
two plans, and each plan is an immutable ConfigMap in the operator namespace
(aicr-system below). Everything it decides can be read from those objects,
their conditions and their Events, without the operator’s logs.
Reading status
Runtime conditions
A failure carries its error code in the message, for example [NOT_FOUND] plan aicr-plan-1a2b… is missing. A failure inside an AICR Job carries AICR’s exit
code and the end of its error output: aicr render exited 3: ….
Runtime status
Rollouts
kubectl get runtimerollouts shows each rollout’s phase, approval state,
target plan (first 16 hex characters) and deadline. The phases are
AwaitingApproval, Progressing, AwaitingAcknowledgement (a manual
release is applied and waits for kubectl aicr acknowledge of its post-apply
steps), Stalled and Validating, and the terminal
Succeeded, Failed, Expired, Revoked, Superseded and Orphaned. A
rollout that has not started shows no phase (kubectl aicr describe prints
Pending). The terminal outcome is also set once as the
operator.aicr.run/outcome label, and a validated success carries its evidence
reference as the operator.aicr.run/evidence annotation.
status.message says why a rollout is where it is (release gpu-operator: HealthProgressing, no step starts: Paused), status.current names the step
in flight, and status.releases the state of each release (Progressing,
Ready, Failed, Suspended for the step in flight while halted,
Deleting, Removed).
Events
ClusterRuntime and RuntimeRollout are cluster-scoped, so their Events are
in the default namespace; kubectl describe shows them.
Metrics
The operator serves Prometheus metrics on port 8080; the chart creates no
Service, so scrape the pod or port-forward
(kubectl port-forward -n aicr-system deploy/aicr-operator 8080):
Every outcome, result, stage and retry class is exported at zero from startup, so a rate reads zero rather than nothing before its first event.
How a change reaches the cluster
- An input changes. The runtime’s
spec(intent, platform, profile, criteria, placement, configuration, overrides), the AICR image (a chart upgrade), or the discovery snapshot. A new snapshot is taken by the first resolution of each UTC day, when the accelerated placement, the AICR image, the set of distinct accelerated node types, or the active plan’sgpu-operatorrelease changes, and on request. - The resolver renders a candidate. It runs
aicr snapshot,aicr recipeandaicr bundleas Jobs, mirrors the charts into your registry, and writes the plan (status.candidatePlanDigest,Resolved=True). The same rendered output is the same digest, so nothing further happens. - The candidate stabilizes for
spec.rollout.stabilizationWindow(default 10 minutes) from its creation (Reconciling=True,Stabilizing). - The transition is assessed. An
aicr upgrade-checkJob compares the active plan’s recipe with the target’s (Assessing). A blocked verdict, or a release that changes namespace or chart name, stops here withTransitionBlocked. A renamed release is aRemoveof the old and anInstallof the new. - A rollout is created from the assessment and the live Applications
(
RolloutCreated). Its steps, deadline and starting inventory are fixed. - It waits for approval when any step needs it (below).
- Steps run one at a time in dependency order, each with one write to
Argo CD, and each must be ready at its current revision within
spec.rollout.actionTimeout(default 30 minutes). Removals run last, in reverse order. Amanualrelease with recorded steps after the apply stops the rollout inAwaitingAcknowledgementuntil those steps are done and an approver runskubectl aicr acknowledge. - Deployment validation runs once when
spec.validation.deploymentisRequired, against a new snapshot taken after every step is ready. - The rollout succeeds and its target becomes the active plan. The whole
rollout must finish within
spec.rollout.deadline(default 6 hours) of its creation.
Changing spec.rollout affects rollouts created afterwards; a rollout keeps
the deadline and action timeout it was created with.
Approving a rollout
A rollout needs approval when any step does:
AICR has transition records for few components, so most upgrades need
approval. Approval is the approver’s statement that workloads are prepared:
the operator never drains nodes, and GPU Operator owns driver-upgrade drains.
For an upgrade AICR assesses manual, approving also takes on the record’s
precondition and every step but the apply, which is the only one the operator
performs; kubectl aicr describe lists them under “Recorded steps”.
Approvers are the users and groups in the chart’s approvers value. They hold
the aicr-operator-approver roles, which grant no ClusterRuntime edits, so
the person who changes the runtime cannot approve the result alone. With the
plugin:
describe shows the transition, every step with its operation, AICR verdict
and CRD change, and AICR’s assessment report. An approval binds the rollout’s
target plan, starting inventory (each Application’s identity, plan and a
fingerprint of its source, values and destination), steps and deadline,
records the approver’s username as the API server reports it, and can be
neither changed nor extended. If the inventory changes after approval,
including a hand edit of an Application’s source, values or destination, the
rollout stalls with InventoryDrift instead of acting on a state nobody
approved. An edit of the release whose step is in flight instead stays
SpecDrifted until it is undone or the step’s action timeout fails the
rollout (troubleshooting).
When an approval expires, the step in flight finishes and the rollout ends
Expired. The rollout’s own deadline still applies while it waits: a rollout
nobody approves ends Expired at its deadline.
Revoking an approval
Any approver can revoke, once. The step in flight finishes, no further step
starts, and the rollout ends Revoked. The record keeps who approved and who
revoked. A rollout that has ended or is in Validating can no longer be
revoked: every change has been made by then.
Retrying
A Failed, Expired or Revoked rollout leaves the runtime Stalled
(RolloutFailed, RolloutExpired, RolloutRevoked) until the target changes
or you ask for a retry with a new token:
The retry creates a new rollout to the same target from the live state, which
needs a fresh approval. A retry while a rollout is Stalled (for example on
InventoryDrift) first ends it Superseded. A token acts once: if the
stalled rollout recovers before the retry ends it, the token is spent, and a
later stall needs a new one. Releases a failed rollout already moved stay on its target
plan; nothing rolls back automatically.
Pausing versus suspending the engine
Clearing the field resumes; neither deletes anything. Both are different from revocation, which withdraws the approval itself.
Time paused or suspended does not count against the step in flight. The
operator keeps observing it without writing: its release reads Suspended,
status.message names its last observation, and a step that becomes ready
meanwhile is recorded. When you clear the field, the step’s actionTimeout
starts again (status.current.timeoutFrom), so a release that never becomes
ready fails with its own reason a full timeout later. The rollout’s deadline
keeps running throughout.
A stalled resolution, such as a cluster that no longer matches its criteria, holds a rollout in progress at its next step boundary, as a pause does, and the rollout’s deadline keeps running.
Rolling back by pinning
Nothing rolls back on its own. To go back to an earlier plan, pin it:
The pinned plan becomes the target. After the stabilization window, the
operator assesses the transition from the active plan and creates a rollout,
which needs approval like any other. A rollout’s spec.fromPlanDigest names
the plan it replaced. The operator keeps the active, candidate and pinned
plans and the five most recent others; pinning a plan whose ConfigMap is gone
stalls with NotFound. Return to automatic selection with
{"spec":{"selection":{"policy":"Automatic","pinnedPlanDigest":""}}}.
A rollout is created only while the runtime’s current inputs resolve
(Resolved=True). If an input change stalls resolution (an AICR upgrade that
fails, unavailable registry credentials), no pinned rollout starts until that
input is fixed or reverted; the active plan is unaffected meanwhile, since a
stalled resolution writes nothing.
Reverting the input that changed (an override, the AICR version) is the other way back: when it renders the earlier output again, the candidate is the earlier plan’s digest.
Changing inputs
-
Overrides (
spec.overrides) are AICR--setvalues per component. A path absent from the base render and the chart’s defaults fails resolution withOverridePathUnknown, unless the override setsadditive: true. A values change assessesUnknownand needs approval. -
Criteria (
spec.criteria) declare what discovery cannot yet measure, such as the accelerator before the GPU stack is installed. They must agree with the snapshot (CriteriaConflict). -
A new snapshot on request:
Upgrading AICR within v1
AICR is an installation value, not a runtime field. Upgrade it with a chart upgrade that sets the version, the image and, with validation, the validator images together:
For example, from v1.0.0 to v1.1.2, the newest release tested in CI:
The same chart upgrade moves validation to the v1.1 identities: the launcher
loses cluster-admin, the aicr-validator ServiceAccount gains it, and the
snapshot launcher loses its namespace grant. For
h100-eks-ubuntu-training-kubeflow the new recipe moves gpu-operator and nodewright-operator, which AICR assesses safe,
and nvsentinel, which it assesses manual with recorded steps, so the
rollout needs approval.
The chart refuses a version outside >=1.0.0, <2.0.0, and the operator stops
on an image that reports a version other than aicr.version
(AICRVersionMismatch). If the new AICR renders the same output, no rollout
results. Otherwise the new plan follows the usual path: stabilization,
assessment, approval. An AICR version the operator was not qualified with is in
range but unqualified (support policy).
To go back to an older AICR, pin an earlier plan first, while the newer AICR is
still installed (rolling back by pinning), and lower
aicr.version only once that rollout has succeeded. Lowering it first stalls
assessment with AICRInvalidRequest: upgrade-check runs from the recipe the
live releases carry, and an older AICR rejects a recipe a newer one wrote (from
v1.1.2 to v1.0.0: ownedPaths["nvsentinel"] must include synthetic path "enabled"). Nothing is written while it stalls; raising
aicr.version again clears it.