Documentation
¶
Overview ¶
Package jobcgroup owns the per-job parent cgroup: the one cgroup that, on Linux, holds every container of one job.
Layout (cgroup v2, cgroupfs driver — CgroupsPath "/<ns>/<id>"):
/sys/fs/cgroup/ephemerd/<runner-id> runner, no job limit /sys/fs/cgroup/ephemerd-dind-<runner-id>/<cid> dind siblings /sys/fs/cgroup/ephemerd-dind-<runner-id>/runner runner, WITH a job limit
The dind siblings land under the job parent on their own: containerd's default spec sets CgroupsPath to "/<namespace>/<id>", and each job's dind namespace is "ephemerd-dind-<runner-id>". runc creates the parent with MkdirAll and only ever removes the leaf, which is why every finished job used to leave an empty ephemerd-dind-* directory behind (477 on ducks and 541 on sharks, 2026-10-23). Remove and SweepStale clean that up.
With runtime memory_limit_mb set, the runner container is moved under the same parent (Dir(id)/runner) so the job's memory.max covers the runner and its siblings together — one budget per job. It cannot simply nest the siblings under the runner's own cgroup instead: cgroup v2's no-internal-processes rule forbids a cgroup that holds processes from having controller-enabled children.
Index ¶
- Constants
- func Dir(jobID string) string
- func Ensure(root, jobID string, l Limits) error
- func Remove(root, jobID string) error
- func RunnerPath(jobID string) string
- func Sweep(grace time.Duration, live map[string]bool, log *slog.Logger)
- func SweepStale(root string, grace time.Duration, now time.Time, live map[string]bool) (int, error)
- type Limits
Constants ¶
const Prefix = "ephemerd-dind-"
Prefix is the name prefix of every job parent cgroup. It must equal dind.DindNamespacePrefix — the parent IS the cgroup containerd derives from the job's dind namespace — and dind's tests pin that.
const Root = "/sys/fs/cgroup"
Root is the cgroup v2 mount ephemerd manages job cgroups under.
const RunnerLeaf = "runner"
RunnerLeaf is the runner container's cgroup name inside the job parent when a job memory limit is configured. Sibling container ids are 64-hex digests, so it cannot collide with one.
Variables ¶
This section is empty.
Functions ¶
func Dir ¶
Dir returns the job parent cgroup's path relative to the cgroupfs root, in the "/<name>" form OCI CgroupsPath takes.
func Ensure ¶
Ensure creates the job parent cgroup under root if it is missing and writes its memory budget. Idempotent, and called before every container of the job is created, so a parent that SweepStale removed between two of the job's containers comes back with its limits rather than without them.
func Remove ¶
Remove deletes the job parent cgroup once its containers are gone: any leftover empty child first, then the parent. Missing is success. A cgroup that still holds processes is left alone (rmdir refuses it) and reported; SweepStale retries it later.
func RunnerPath ¶
RunnerPath is the runner container's CgroupsPath when the job has a memory budget.
func Sweep ¶
Sweep is SweepStale on the real cgroupfs, logged. A sweep failure is never fatal — the leak it cleans up is slow and harmless in the short term.
func SweepStale ¶
SweepStale removes job parent cgroups under root that hold no processes and no child cgroups, whose directory has not changed for grace, and whose job is not in live. It never removes one with processes or children, and never one belonging to a job this daemon is still running: without a memory limit a live job's parent is empty between two of its sibling containers, and an rmdir landing inside runc's mkdir-parent/mkdir-leaf window would fail that container's start. live is keyed by job (runner container) id; nil means no job is live.
The grace is measured against the directory's mtime, which cgroupfs bumps when a child cgroup is created or removed (not when processes join or a limit is written). It backstops a job the live set cannot see yet.
Returns how many it removed.