Skip to content

docs: design for init-container GPU resource accounting#2064

Open
maishivamhoo123 wants to merge 3 commits into
Project-HAMi:masterfrom
maishivamhoo123:docs/init-container-gpu-support-design
Open

docs: design for init-container GPU resource accounting#2064
maishivamhoo123 wants to merge 3 commits into
Project-HAMi:masterfrom
maishivamhoo123:docs/init-container-gpu-support-design

Conversation

@maishivamhoo123

@maishivamhoo123 maishivamhoo123 commented Jul 14, 2026

Copy link
Copy Markdown
Member

Currently HAMi sums init and app container requests as if they run together, causing false quota passes, scheduler rejections, and inflated usage that never shrinks. This PR corrects all three layers – admission, scheduling, and usage recording – to use the correct formula effective = max(sum(app), max(init)). Usage is stored as the peak value and automatically reduced to app‑only once init containers terminate. Pod annotations remain untouched.
Related to #1667
#1773

Summary by CodeRabbit

  • Documentation
    • Added a new design document outlining improved GPU resource accounting for workloads that use init containers.
    • Clarifies consistent handling for admission checks, scheduling fit/scoring, and usage tracking across init + app phases.
    • Specifies how resources are adjusted after successful init completion and includes safeguards to prevent repeated adjustments.

Signed-off-by: maishivamhoo123 <maishivamhoo@gmail.com>
@hami-robot

hami-robot Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: maishivamhoo123
Once this PR has been reviewed and has the lgtm label, please assign shouren for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@hami-robot
hami-robot Bot requested review from archlitchi and lengrongfu July 14, 2026 05:30
@github-actions github-actions Bot added the kind/documentation Improvements or additions to documentation label Jul 14, 2026
@hami-robot hami-robot Bot added the size/L label Jul 14, 2026
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

An error occurred during the review process. Please try again later.

📝 Walkthrough

Walkthrough

Added a design document defining HAMi’s init-container GPU accounting model, including admission checks, scheduler fit and scoring, usage aggregation, post-init shrinking, and idempotency handling.

Changes

Init container accounting design

Layer / File(s) Summary
Effective footprint and lifecycle rules
docs/develop/initContainer-design.md
Defines per-resource/per-device max(app sum, init peak) accounting and specifies admission, scheduling, usage updates, post-init shrink behavior, and the initContainersShrunk flag.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: archlitchi, lengrongfu

Poem

A bunny reviewed the init-container plan,
With GPU footprints neatly in span.
“Peak before sum, then shrink when they’re done—
Track every device, one by one!”
🐇 Hops celebrate accounting begun.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR only adds a design document and does not implement the device-allocation fix required by #1667. Implement the init-container device allocation changes in code, or retarget the PR as a design-only follow-up if implementation is not included.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The only change is a design doc directly aligned with the init-container accounting topic, so no unrelated scope is apparent.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the added design doc for init-container GPU resource accounting.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive design document and supporting SVG diagrams detailing HAMi's support for init container GPU resource accounting. The design addresses the issue of simultaneous resource allocation for sequential containers by proposing a formula that calculates the effective GPU footprint as the maximum of the app container requests and the single largest init container request. The review feedback focuses on correcting several typos, grammatical errors, and phrasing issues within the design document to improve its overall readability and professionalism.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread docs/develop/initContainer-design.md Outdated
Comment thread docs/develop/initContainer-design.md Outdated
Comment thread docs/develop/initContainer-design.md Outdated
Comment thread docs/develop/initContainer-design.md Outdated
@maishivamhoo123

Copy link
Copy Markdown
Member Author

@DSFans2014 @archlitchi and @Shouren can i added the docs for #1773 can you please review this ?
Thank you!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
docs/develop/initContainer-design.md (1)

15-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add language identifiers to fenced code blocks.

The document has multiple untyped fences, triggering markdownlint MD040. Use go for Go snippets and text (or another appropriate language) for formulas/pseudocode.

Also applies to: 27-31, 46-50, 70-72, 134-138, 152-156, 173-175, 200-204

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/develop/initContainer-design.md` around lines 15 - 20, Update all fenced
code blocks in initContainer-design.md, including the sections around the shown
loop and the additional referenced ranges, to include explicit language
identifiers; use go for Go snippets and text (or another suitable identifier)
for formulas or pseudocode, without changing the block contents.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/develop/initContainer-design.md`:
- Around line 208-210: In the idempotency description for PodManager, correct
the typo by changing “never re-applie” to “never re-applied.”
- Around line 76-79: Update the resource-dimension sentence to use “per-device
UUID (a multi-GPU pod...” and replace “those devices usage merged together” with
clearer wording such as “usage on those devices merged.”
- Around line 200-204: Update the initContainer usage-collapse pseudocode so
new_usage[uuid] aggregates the same per-container actual usage fields consumed
by AddUsage and getNodesUsage, including fields such as Usedmem, rather than
app-container requests. Preserve request-based calculations for admission and
scheduling, then compute delta from the usage values and apply it to
QuotaManager and PodManager.
- Around line 76-82: Clarify the GPU-count behavior in the admission quota
design around FitQuota: either specify how GPU count is passed through and
checked as an independent quota dimension, or explicitly document that it is
incorporated into the memory/core multiplier and is not checked separately.
Ensure the documented formula matches the actual admission behavior.

---

Nitpick comments:
In `@docs/develop/initContainer-design.md`:
- Around line 15-20: Update all fenced code blocks in initContainer-design.md,
including the sections around the shown loop and the additional referenced
ranges, to include explicit language identifiers; use go for Go snippets and
text (or another suitable identifier) for formulas or pseudocode, without
changing the block contents.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e77d858d-8e5e-44bd-8cad-029d0e179a4b

📥 Commits

Reviewing files that changed from the base of the PR and between a1b418c and aac35b1.

⛔ Files ignored due to path filters (3)
  • docs/develop/imgs/before-after-math.svg is excluded by !**/*.svg
  • docs/develop/imgs/pod-lifecycle-journey.svg is excluded by !**/*.svg
  • docs/develop/imgs/timeline-init-vs-app.svg is excluded by !**/*.svg
📒 Files selected for processing (1)
  • docs/develop/initContainer-design.md

Comment thread docs/develop/initContainer-design.md Outdated
Comment thread docs/develop/initContainer-design.md Outdated
Comment thread docs/develop/initContainer-design.md
Comment thread docs/develop/initContainer-design.md Outdated
Signed-off-by: maishivamhoo123 <maishivamhoo@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/develop/initContainer-design.md (1)

202-205: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Base shrinking on init completion, not Phase == Running. Succeeded/Failed pods can still be observed after all init containers have finished, so requiring Running can skip the shrink and leave init peak usage charged. Use Initialized=True (or an equivalent init-status predicate) as the primary gate and keep phase only as a consistency check.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/develop/initContainer-design.md` around lines 202 - 205, Update the
documented init-container completion condition so Initialized=True, or an
equivalent predicate confirming all init containers terminated successfully, is
the primary gate for base shrinking. Do not require pod.Status.Phase == Running,
since Succeeded or Failed pods may still need the shrink; retain phase only as
an optional consistency check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/develop/initContainer-design.md`:
- Around line 225-227: Update the shrink transition design for both QuotaManager
and PodManager so retries and concurrent execution cannot apply the same delta
twice. Persist a durable shrink operation/version keyed by pod UID and reconcile
absolute desired usage, or have both managers deduplicate the operation before
marking initContainersShrunk complete; retain initContainersShrunk only as
completion state, not the sole idempotency mechanism.
- Line 5: Update the GPU allocation design for init containers to distinguish
classic init containers from native sidecars identified by restartPolicy:
Always. Exclude native sidecars from the sequential init-container assumption
and define their separate resource accounting and shrink behavior when they
overlap app containers; retain the existing sequential handling for classic init
containers.

---

Outside diff comments:
In `@docs/develop/initContainer-design.md`:
- Around line 202-205: Update the documented init-container completion condition
so Initialized=True, or an equivalent predicate confirming all init containers
terminated successfully, is the primary gate for base shrinking. Do not require
pod.Status.Phase == Running, since Succeeded or Failed pods may still need the
shrink; retain phase only as an optional consistency check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f2eb52d7-4ba9-4995-9bdb-7943eb4944ce

📥 Commits

Reviewing files that changed from the base of the PR and between aac35b1 and 1c9153d.

📒 Files selected for processing (1)
  • docs/develop/initContainer-design.md

Comment thread docs/develop/initContainer-design.md
Comment thread docs/develop/initContainer-design.md Outdated

### Scheduler Fit & Scoring

1. **Init pass:** fit each init container independently against a fresh

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the reqNum value for all initContainers is 1, will all initContainers be allocated on the same cardID?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DSFans2014 thank you for review yes when all init containers have reqNum=1, each independent fresh-copy fit will select the same physical card whose score will be highest on a clean node state.because init containers are sequential, they can genuinely reuse the same device. The per-UUID max formula handles both outcomes correctly: if all land on GPU0, effective_mem[GPU0] = max(IC1, IC2, and so on) .
if they land on different devices, each gets its own independent peak. Neither case over-counts.
am i correct ?

Comment thread docs/develop/initContainer-design.md Outdated

![The journey of one pod](./imgs/pod-lifecycle-journey.svg)

**Condition:** `pod.Status.Phase == Running` **and** every init container

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any issue if the main container exits immediately after being started?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No i think there is no any problem because if the app container exits immediately and the pod goes straight to Succeeded/failed state before our shrink logic runs that's fine. because When the pod gets deleted, we always remove exactly whatever number is stored at that point. So even if the shrink never fired and we still have the full max(app, init) value stored, deletion will remove exactly that. End result is still zero. Nothing leaks. The initContainersShrunk flag just makes sure the shrink can't accidentally fire after deletion has already cleaned everything up.
am i correct ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Condition: pod.Status.Phase == Running and every init container has Status.Terminated{ExitCode: 0}

My concern is whether the Running state will appear in this case. I'm not sure whether Kubernetes merges transient intermediate states and sends a single final state.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DSFans2014 thank you for review The Running phase will always appear, even if the app container exits immediately after init containers finish. Kubernetes does not merge transient phases.
as we can see in this function

// updateStatusInternal updates the internal status cache, and queues an update to the api server if
// necessary.
// This method IS NOT THREAD SAFE and must be called from a locked function.
func (m *manager) updateStatusInternal(logger klog.Logger, pod *v1.Pod, status v1.PodStatus, forceUpdate, podIsFinished bool) (bool, *podStatusNotification) {
	var oldStatus v1.PodStatus
	cachedStatus, isCached := m.podStatuses[pod.UID]
	if isCached {

https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/status/status_manager.go#L849

In updateStatusInternal, the new status is cached, its version is incremented, and a message is pushed onto podStatusChannel to trigger a sync. There is no any logic that skips intermediate phases. So whenever the kubelet starts the first app container, it computes a Running phase and calls SetPodStatus, which immediately triggers a patch to the API. If the container then terminates, a second status (Succeeded) is computed and sent in the same way. Both updates are visible to any informer or controller.
and i verified it locally also :-
Screenshot 2026-07-16 101704

The sleep 1 just makes the phase long enough to observe manually.
does it make sense ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can test it as follows. First, start the monitoring script

NS="phase-race"

rv=$(kubectl get pods -n "$NS" -o jsonpath='{.metadata.resourceVersion}' 2>/dev/null)

kubectl get --raw "/api/v1/namespaces/$NS/pods?watch=1&resourceVersion=$rv&allowWatchBookmarks=true" \
| jq -r --unbuffered 'select(.type != "BOOKMARK" and .object != null) | [.type, .object.metadata.name, .object.status.phase] | @tsv' \
| while IFS=$'\t' read -r type name phase; do
    timestamp=$(date '+%H:%M:%S.%3N') 
    echo "[$timestamp] $type | $name | $phase"
done

then start test pod as below:

NS=phase-race
ITER=5

kubectl create ns "$NS" --dry-run=client -o yaml | kubectl apply -f -

for i in $(seq 1 "$ITER"); do
P="race-$i"
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: $P
  namespace: $NS
  labels:
    race: phase
spec:
  restartPolicy: Never
  initContainers:
  - name: init-1
    image: busybox:latest
    command: ["sh","-c","sleep 0.2"]
  - name: init-2
    image: busybox:latest
    command: ["sh","-c","sleep 0.3"]
  containers:
  - name: main
    image: busybox:latest
    command: ["sh","-c","echo start; sleep 0.01; exit 0"]
EOF
kubectl -n "$NS" wait --for=jsonpath='{.status.phase}'=Succeeded pod/"$P" --timeout=120s >/dev/null || true
done

we may see the output as below:
ScreenShot_2026-07-16_155124_394

If there are any issues with the testing process, please let me know

@maishivamhoo123 maishivamhoo123 Jul 16, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DSFans2014 thank you for pointing this out , I checked it properly with the help of the above conditions . I ran the test again and watched both Phase and initContainerStatuses together while creating pods live.
For race-1: both init containers show Terminated{ExitCode:0} while the pod is still Pending. Then it jumps straight to Succeeded. Running never shows up at all.
But for race-2 in the same run, Running does show up before Succeeded.

Screenshot 2026-07-16 150410 Screenshot 2026-07-16 145354

So it's random — same pod spec, but one pod skips Running and the next one doesn't. It depends on timing, not something we can control. That means we can't rely on Phase == Running in the condition, since it might just never happen for a given pod.
so i am thinking to remove pod.Status.Phase == Running so the new condition will now become : all init containers show Terminated{ExitCode:0}. That field is stable once it's set and doesn't depend on this timing issue.

am i correct? can i move forward with this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, looks like Running status doesn’t always show up from this result. We should change the condition


## Problem Summary

When a pod has both init containers and app containers requesting GPU resources, HAMi allocates the resources simultaneously/parallelly. But Kubernetes runs the init container sequentially to completion before any app container starts, so init and app containers never execute at the same time.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread got marked resolved but sidecar containers are still not mentioned anywhere in the doc, same gap i found in pr 1773

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mesutoezdil This is totally intentional i will create a different pr for the sidecar container as it have a lot of difference compared to the init container so i am thinking to raise a different issue and pr for sidecar container.
is it ok ?

Comment thread docs/develop/initContainer-design.md Outdated

Only ever runs **after** `pod.Status` confirms completion.

**Idempotency:** `PodManager` stores a boolean `initContainersShrunk` flag

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this thread got marked resolved too but the doc still only describes one boolean flag, no crash safe delta reconciliation across the two managers

@maishivamhoo123 maishivamhoo123 Jul 16, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mesutoezdil the boolean flag is only there to avoid running the same shrink twice while the controller is still running. It’s not the crash-safety mechanism.For crashes, the real safety net is:- every time the controller checks the pod, it will recalculate the correct usage directly from the pod annotations, spec, and status. So if we crash mid-shrink, on restart the next check will recompute the right numbers and apply only the difference (delta) to both managers. The flag is just a temporary inmemory guard that will disappears on restart, so the recalculation fixes everything automatically.
does it make sence?

@mesutoezdil

Copy link
Copy Markdown
Contributor

issue 1667 was about wrong device assignment which pr 1650 already fixed, this doc only changes accounting and does not touch device assignment, might be better to change fixes 1667 to part of 1667

Signed-off-by: maishivamhoo123 <maishivamhoo@gmail.com>
@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Flag Coverage Δ
unittests 60.16% <ø> (+0.56%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 16 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@maishivamhoo123

maishivamhoo123 commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

@DSFans2014 i resolved all your comments can you please look in to this once and let me know is everything is perfect or not ?
Thank you!

So the correct formula for a pod's GPU footprint at any instant is:

```
effective = max( sum(app container requests), max(single init container request) )

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure whether a single machine can take different devices. Should we also consider the scenario where a request contains multiple devices? @archlitchi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes and no, a single request shouldn't contain multiple kinds of devices, but a single node can have multiple kinds of devices

@DSFans2014 DSFans2014 Jul 17, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a single request shouldn't contain multiple kinds of devices

Can different containers (including init containers ) in the same Pod request different devices? @archlitchi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DSFans2014 @archlitchi Can we simplify the scenario for init containers by assuming, for now, that the resources requested by the init container will always be the same as one of the app containers? If other needs come up later, we can implement them then.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DSFans2014 @archlitchi Can we simplify the scenario for init containers by assuming, for now, that the resources requested by the init container will always be the same as one of the app containers? If other needs come up later, we can implement them then.

yeah, we can assume this for now

- **All init containers exited `ExitCode: 0`, pod not yet terminal:**
app containers have started or are starting → shrink to
app-containers-only usage.
- **Any init container exited non-zero, pod not yet terminal:** pod may still restart (depending on restartPolicy). It still holds its allocated GPU devices, so usage is not shrunk at this point. The pod will either restart and eventually succeed, or be terminated permanently (phase → Failed), which will then trigger a shrink.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spec:
  restartPolicy: OnFailure
  initContainers:
  - name: init-1
    image: busybox
    command: ["sh","-c","sleep 0.2"]
    resources:
      limits:
        nvidia.com/gpu: 1
        nvidia.com/gpumem: 1024
  - name: init-2
    image: busybox
    command: ["sh","-c","sleep 0.3; exit 1"]
    resources:
      limits:
        nvidia.com/gpu: 1
        nvidia.com/gpumem: 512
  containers:
  ...

Considering the above scenario—where init-1 has completed successfully and init-2 is stuck in a restart loop due to failures (may be waiting for some condition to be met before it can succeed) —should the extra resources claimed by init-1 be released?

@maishivamhoo123 maishivamhoo123 Jul 17, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DSFans2014 currently we are using the all-or-nothing approach: if any init container fails, we don't shrink usage at all. But you're right we are not releasing the extra resource use by init-1. I think we can improve this with the watermark approach track the highest index of an init container that finished with exit 0 (since they run in order). After that, we only count the requests of the remaining init containers. In your example, once init-1 succeeds, the effective peak drops from 1024Mi to 512Mi (only init-2 matters). It's a bit more state to track (an index instead of a simple enum), but it's a utilization improvement, not a correctness fix — we'd never over-admit either way.

@archlitchi @Shouren @DSFans2014 What are your thoughts? Should we include this now, or keep it as a future improvement?
Thank you!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this a critical problem. We can record a TODO item and address it in a future iteration.

Only ever runs **after** `pod.Status` confirms completion.

**Idempotency:** `PodManager` stores a `PodShrinkState` per pod —
`NotShrunk`, `AppOnly`, or `Zero` — replacing a single boolean, since the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these statuses used for? Also, the names are a bit confusing

@maishivamhoo123 maishivamhoo123 Jul 17, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DSFans2014 PodShrinkState guards against two specific problems. First, idempotency: the system checks the same pod over and over, and once it shrinks the usage, it must recognize the shrink is already done on subsequent checks so it doesn't subtract the same memory twice. Second, one-directional transitions: usage should only ever go down from full to app-only, or full straight to zero but never back up.
A simple hasShrunk boolean cannot handle this because it only tracks whether any shrink happened. Once the first shrink (full to app-only) occurs, the boolean flips to true. Later, when the pod dies and a second shrink (app-only to zero) is needed, the system looks at the true boolean, assumes everything is already handled, and skips the second shrink leaving the pod's memory permanently stuck at the app-only level even after the pod is gone.
What each value means
NotShrunk : still the original max(app_sum, init_peak) from admission.
AppOnly : init containers all exited 0 recorded usage = app containers only.
Zero : pod hit a terminal phase recorded usage = 0.
i guess now it is clear ? there is a scope of changing name from Zero to Released other than this is looking fine i am open for any suggestions if you have any suggestions please let me know?
Thank you !

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, idempotency: the system checks the same pod over and over, and once it shrinks the usage, it must recognize the shrink is already done on subsequent checks so it doesn't subtract the same memory twice.

If we address the issue mentioned in #2064 (comment) in the future, how should the state transition?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DSFans2014 in that condition Instead of using a fixed three state flag, we can track a single number called the watermark , basically a counter that keeps track of how many init containers have successfully finished in the order.
this NotShrunk is just watermark 0, and AppOnly is just the final watermark number (when all inits have succeeded). The big win is the middle ground , lets take your example only when init‑1 (1024Mi) succeeds, the watermark moves from 0 to 1, and we immediately release that 1024Mi the effective usage drops to only what the remaining init containers (like init‑2) are asking for. If init‑2 keeps failing and retrying, the watermark stays at 1 and no further shrink happens until either init‑2 finally succeeds (moving the watermark to the top, which then includes app containers) or the whole pod hits a terminal phase and jumps straight to Zero/Released, releasing everything. This watermark only ever moves forward, one step at a time, never backward, and since it's recomputed from the pod's actual status on every check, repeated reconciliations without any status change naturally produce zero delta — so our idempotency stays intact. so we can safely keep it as a future TODO without reworking anything in this PR.
is it a good approach or do you have any further suggestions?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my point of view, we only need one bool variable to track whether the init container's resources have been reclaimed. Moreover, the problems in #2064 (comment) can be resolved by the watermark number described above.

// We use initContainerResourceReleased to indicate whether the init container's resources have been released
// with an initial value of false

// If all init containers have completed and initContainerResourceReleased remains false
// we reclaim the init container resources
if all initContainer terminated and !initContainerResourceReleased:
    // release the resource of initContainer
    initContainerResourceReleased = true

// If the pod terminates, we free up the app containers resources.
if pod.Status.Phase in (Succeeded, Failed):
   // release the resource of app containers

If there are any issues with the above solution, feel free to point them out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes kind/documentation Improvements or additions to documentation size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants