Skip to content

fix(shim): synchronously check cgroup for OOM at container exit#12843

Open
kpurdon wants to merge 1 commit intogoogle:masterfrom
kpurdon:kpurdon/12838/fix-aarch64-oom-reporting
Open

fix(shim): synchronously check cgroup for OOM at container exit#12843
kpurdon wants to merge 1 commit intogoogle:masterfrom
kpurdon:kpurdon/12838/fix-aarch64-oom-reporting

Conversation

@kpurdon
Copy link
Copy Markdown

@kpurdon kpurdon commented Apr 1, 2026

Why

On aarch64 (ARM64/Graviton), the async OOM notification via inotify/EventChan (cgroups v2) loses the race against the container exit from runtime.Wait(). Containerd processes the TaskExit before TaskOOM arrives, so kubelet reports reason: Error instead of reason: OOMKilled. This breaks monitoring, autoscaling, and alerting on aarch64 gVisor nodes.

What

  • Added isOOM(id string) bool to the oomPoller interface for synchronous OOM checking at exit time (one-shot: consumes the cgroup reference)
  • Implemented isOOM for cgroups v2 (watcherV2) using cg.Stat() to read memory.events directly, bypassing the async inotify path
  • Promoted lastOOMMap from goroutine-local in run() to a shared mutex-protected field, coordinating between async and sync paths to prevent duplicate TaskOOM events
  • Guarded the sync OOM check to init process exits only — exec processes share the sandbox cgroup and would produce spurious events
  • Added no-op isOOM for cgroups v1 (epoller) since its eventfd mechanism doesn't have this race
  • Added 6 unit tests covering async publish, dedup, sync/async coordination, and error cleanup

Fixes #12838

@google-cla
Copy link
Copy Markdown

google-cla bot commented Apr 1, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@kpurdon kpurdon force-pushed the kpurdon/12838/fix-aarch64-oom-reporting branch 2 times, most recently from da73340 to 89555b6 Compare April 1, 2026 17:04
On aarch64, the async OOM notification via inotify/EventChan (cgroups
v2) loses the race against the container exit notification from
runtime.Wait(). This causes containerd to process the TaskExit before
TaskOOM arrives, leading kubelet to report reason=Error instead of
reason=OOMKilled.

Add a synchronous check of the cgroup's memory.events at container exit
time. When OOM kills are detected, publish the TaskOOM event through the
same sequential event pipeline as TaskExit, guaranteeing the OOM event
arrives first. The async and sync paths coordinate through a shared
lastOOM map under mutex to prevent duplicate events.

Fixes google#12838
@kpurdon kpurdon force-pushed the kpurdon/12838/fix-aarch64-oom-reporting branch from 89555b6 to f1c7618 Compare April 1, 2026 17:46
@kpurdon kpurdon marked this pull request as ready for review April 1, 2026 17:49
@tranji-cloud tranji-cloud requested a review from milantracy April 3, 2026 23:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OOMKilled reason not reported on aarch64 — container shows reason: Error instead of reason: OOMKilled

1 participant