advanced28 min studyLesson 350 in Engineering

Container forensics: reconstruct the failing transition

Correlate runtime phases, process identity, namespace and mount state, file descriptors, and cgroup event deltas before assigning a cause.

On this page

What you’ll understand

  • Locate a failure in create, start, application execution, shutdown, or cleanup.
  • Collect namespace, mount, descriptor, credential, and cgroup observations with stable identity.
  • Interpret counter deltas and exit conventions without inferring an unsupported cause.

The statement that a container failed hides several possible failures: its root could not be mounted, a setup hook failed, exec was denied, the application exited, or cleanup left resources referenced. A useful investigation reconstructs the transition that failed before changing privileges or limits. This lesson uses Linux 6.12 observations with the OCI v1.3.0 lifecycle vocabulary. Concrete runtime and supervisor behavior can differ, so preserve their versions, effective configuration, and timestamps instead of treating a dashboard status as the complete kernel state.

Identify the instance and the lifecycle phase

Record container ID, bundle/configuration identity, runtime version, host PID, process start time, and the relevant namespace identifiers. A host PID can be reused after exit; a later process with the same number is not the original instance. Runtime created and running states also describe different points: setup can create a container environment before the user program executes. If exec never succeeded, searching only application logs misses the failure. Align runtime errors, hook outcomes, and actual process observations on a consistent timeline.

Observe from the intended namespace. A path visible to the host inspector can resolve differently for the target process, and a proc mount can expose a different PID view. Record root, current directory, mountinfo, and descriptors alongside the process credentials, mappings, capabilities, no_new_privs, and seccomp state. A namespace link identifies a kernel namespace object, not an entire container security policy. Two processes sharing one namespace can still differ in credentials, cgroups, open files, and the other namespaces.

Iobservation=(containerID⁡,hostPID⁡,startTime⁡,namespaceIDs⁡,timestamp⁡)I_{\rm observation}=(\operatorname{containerID},\operatorname{hostPID},\operatorname{startTime},\operatorname{namespaceIDs},\operatorname{timestamp})
This is an investigation record key, not a kernel atomic identity tuple. IDs and times must be interpreted in their observed contexts; retaining them helps detect PID reuse and stale-instance comparisons, but collecting the tuple is not an atomic snapshot of all process state.↔ Scroll wide equations horizontally.

References can outlive names and process status

An unlinked file can remain allocated while an open reference or mapping still uses it. A detached mount or namespace object can also remain referenced through descriptors or other holders. Therefore absence from one pathname listing does not prove resource reclamation, and a stopped application does not prove every runtime or sidecar released its handles. Inspect actual holders before attributing retained disk space to an OverlayFS leak. The type and lifetime of the reference matter more than the human-readable path that disappeared.

Preserve evidence before aggressive cleanup changes it. Collect descriptor targets and mount relationships with appropriate permission, then distinguish a deleted filename, a whiteout, a detached mount, and a still-live underlying object. A namespace file descriptor can pin an object, but does not make a PID namespace whose init died usable for new processes. Joining namespaces or rerunning hooks can itself alter state and is not a neutral observation. Prefer a reproducible fixture when a hypothesis requires a state-changing experiment.

ΔC=C(t1)−C(t0),t1>t0\Delta C=C(t_1)-C(t_0),\qquad t_1>t_0
This counter delta applies only to the same counter instance with understood units and no reset or wrap during the interval. It does not by itself establish causation; process and cgroup replacement, hierarchy, and collection timing must be checked.↔ Scroll wide equations horizontally.

Explain one mechanism with corroborating evidence

For CPU problems, compare quota, ancestors, usage, throttling, runnable work, and pressure. For memory problems, correlate charged usage and local versus hierarchical events with the same workload instance. For denied syscalls, identify the attempted operation, actual errno or signal, credentials, filter, and LSM evidence where available. Conventional status 137 points toward SIGKILL-style termination, not uniquely OOM. Preserve a competing explanation, such as orchestrator escalation, until evidence distinguishes it. Changing several controls at once removes the ability to attribute the result.

The queue lab illustrates evidence-collection pressure rather than the container itself. Reset, explicitly set arrival four and service three, predict pending observation work growing, then Play or Step. For a separate capacity comparison Reset and explicitly set arrival two and service three. Rate edits retain elapsed time and recompute from four initial items. This unbounded fluid model has no finite trace buffer, dropped events, runtime phases, mounts, descriptors, or kernel causes. It motivates checking collector capacity without proving which event an actual investigation missed.

Read throttling deltas without inventing a percentage of time

For the same unchanged cgroup instance, two snapshots report nr_periods increasing from 100 to 140 and nr_throttled from ten to 30. Assume no counter reset or wrap and a kernel counter definition that counts throttled periods. A separate process exit is conventionally reported as 137.

  1. The interval contains 140−100=40 reported enforcement periods and 30−10=20 reported throttled periods. The count ratio is 20/40=0.5, or fifty percent of those periods.

  2. That is not automatically fifty percent of wall time lost or fifty percent of one request's latency. Duration, parallel waiting, workload arrival, ancestor constraints, and the actual counter semantics need separate evidence.

  3. The exit convention 137=128+9 is consistent with signal nine, SIGKILL, but does not identify its sender. Correlate memory events, operator/runtime shutdown records, process identity, and available kernel evidence before calling the event an OOM kill.

The result

Counter deltas narrow the investigation without supplying an unsupported timing or kill-cause claim. The same-instance and no-reset assumptions are essential to the arithmetic.

Explore the model

Interactive lab

Interactive lab · queue

Observation work can fall behind

Compare separate fixed-rate collector analogies with Reset → explicitly set both λ and μ → predict → Play or Step at (4,3), then Reset and (2,3). Edits retain elapsed t and recompute from four initial items. The model does not simulate finite trace-buffer drops, runtime state, namespaces, descriptors, or failure causes.

Observation work can fall behindFluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Current readings: Fluid backlog: 4; Net rate · λ − μ: −1 /s; M/M/1 mean residence: 1 s. All parameters are adjustable with the labeled controls below.02.557.51001.534.56Elapsed time · sFluid backlogλ < μ
Fluid backlogCurrent time
Fluid backlog
4
Net rate · λ − μ
−1 /s
M/M/1 mean residence
1 s
t = 0 s

Fluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.

Look forCollector capacity affects available evidence, but causal diagnosis still needs correctly identified process, mount, descriptor, and cgroup observations.

Check your understanding

A process with host PID 32000 exits, and a later inspection finds another process numbered 32000. What should an investigation do before combining their observations?

Try it yourself

A deleted log file is absent from the directory listing, but an inspector finds a process holding an open descriptor to that unlinked file. Separately, an application never reaches exec because a mount setup step fails. Which two common conclusions should be avoided?

Take a moment to make a prediction or work it out on paper. Open a hint when you need one.

Give me a hint

Separate object lifetime from pathname lifetime, and setup phases from application execution.

Compare with the solution

Avoid concluding that deleting the pathname necessarily reclaimed the file's storage: an open reference or mapping can retain the object, and the relevant holder must release it before final reclamation conditions are met. Also avoid debugging this startup failure solely as an application crash; if mount setup failed before exec, the application may never have run. Preserve the runtime phase error, mount namespace and topology, effective configuration, and process identity, then test a specific setup hypothesis in a controlled fixture rather than broadening privileges indiscriminately.

Take it with you

  • Locate the failed lifecycle transition before changing controls.
  • Names, processes, descriptors, mounts, and namespaces have different lifetimes.
  • Counter deltas and exit conventions require identity, scope, units, and corroborating evidence.

Read further

Original sources and deeper explanations to follow at your own pace.

Optional progress, saved in this browser when available. Revisit any lesson at any time.

Lesson not marked complete.