Skip to content

feat(helm): support externally-managed PVC via pvcExistingClaimName (#938)#988

Open
Anai-Guo wants to merge 1 commit into
vllm-project:mainfrom
Anai-Guo:feat/pvc-existing-claim
Open

feat(helm): support externally-managed PVC via pvcExistingClaimName (#938)#988
Anai-Guo wants to merge 1 commit into
vllm-project:mainfrom
Anai-Guo:feat/pvc-existing-claim

Conversation

@Anai-Guo

@Anai-Guo Anai-Guo commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #938.

Adds an optional per-model pvcExistingClaimName to servingEngineSpec.modelSpec[], so operators can mount a PersistentVolumeClaim that is managed outside the chart instead of one the chart creates. This is useful for GitOps environments where PVC policy requires claims to be provisioned separately and brought in via existingClaim.

Behavior

  • pvcExistingClaimName set → the chart skips rendering the model PVC (pvc.yaml) and the serving-engine deployment mounts the named claim directly.
  • pvcExistingClaimName unset (default) → unchanged: the chart creates and mounts <release>-<model>-storage-claim.

Changes

  • helm/templates/pvc.yaml — guard PVC creation with (empty $modelSpec.pvcExistingClaimName).
  • helm/templates/deployment-vllm-multi.yaml — use pvcExistingClaimName for the volume claimName when set, falling back to the generated name.
  • helm/values.yaml — document the option as a commented example. Kept as a plain comment (not a # -- helm-docs key) so the generated values.schema.json is unaffected; since modelSpec items do not set additionalProperties: false, the new key still validates.
  • helm/tests/pvc_test.yaml — add a case asserting no PVC document is rendered when pvcExistingClaimName is set.

Scope is limited to the per-model storage claim referenced by the serving-engine deployment; the separate sharedPvcStorage path is unchanged.

🤖 Generated with Claude Code

Add an optional per-model `pvcExistingClaimName` so operators can mount a
PersistentVolumeClaim managed outside the chart (e.g. GitOps setups where
PVCs are provisioned separately) instead of one created by the chart.

When set, pvc.yaml skips rendering the model PVC and the serving-engine
deployment mounts the named claim directly; when unset, behavior is
unchanged (the chart creates and mounts `<release>-<model>-storage-claim`).

Documented as a commented example in values.yaml (kept as a plain comment
so the generated values.schema.json is unaffected) and covered by a
pvc_test.yaml case asserting no PVC is rendered when the option is set.

Fixes vllm-project#938

Signed-off-by: Anai-Guo <antai12232931@outlook.com>

@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 the pvcExistingClaimName parameter to allow using an externally-managed PersistentVolumeClaim instead of having the Helm chart create one. The feedback highlights a few issues with this implementation: first, skipping PVC rendering can lead to empty YAML documents due to the placement of the --- separator; second, the deployment template still implicitly requires pvcStorage to be set to a valid string to mount the volume, which should be documented; and third, the outer template guards in the deployment should be updated to check for pvcExistingClaimName directly to prevent silent failures if pvcStorage is omitted.

Comment thread helm/templates/pvc.yaml
{{- range $modelSpec := .Values.servingEngineSpec.modelSpec }}
{{- with $ -}}
{{- if and (hasKey $modelSpec "pvcStorage") (not (empty $modelSpec.pvcStorage)) (kindIs "string" $modelSpec.pvcStorage) }}
{{- if and (hasKey $modelSpec "pvcStorage") (not (empty $modelSpec.pvcStorage)) (kindIs "string" $modelSpec.pvcStorage) (empty $modelSpec.pvcExistingClaimName) }}

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.

medium

Skipping PVC rendering when pvcExistingClaimName is set will result in empty YAML documents (consecutive --- separators) because the --- separator at line 39 is rendered for every model in the loop, regardless of whether the PVC itself is rendered.

To prevent generating empty documents or trailing/consecutive --- separators, the --- separator should be moved inside the if block (e.g., at the very beginning of the if block, before apiVersion: v1), and the hardcoded --- at line 39 should be removed.

{{- if and (hasKey $modelSpec "pvcStorage") (not (empty $modelSpec.pvcStorage)) (kindIs "string" $modelSpec.pvcStorage) (empty $modelSpec.pvcExistingClaimName) -}}
---

Comment thread helm/values.yaml
Comment on lines +97 to +101
# Use an externally-managed PersistentVolumeClaim instead of one created by
# this chart. When set, the chart skips rendering the PVC and mounts the
# named claim directly (useful for GitOps setups where PVCs are managed
# outside the chart). Leave unset to have the chart create the PVC.
# pvcExistingClaimName: "my-existing-claim"

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.

medium

When pvcExistingClaimName is used, the chart's deployment template still requires pvcStorage to be set to a valid string (e.g., "50Gi") to trigger the creation of the volume and volume mounts. If a user unsets pvcStorage or sets it to null (which is a common expectation when using an existing PVC), the volume will not be mounted at all.

Please document this requirement in the comments so users are aware they must keep pvcStorage defined.

    # Use an externally-managed PersistentVolumeClaim instead of one created by
    # this chart. When set, the chart skips rendering the PVC and mounts the
    # named claim directly (useful for GitOps setups where PVCs are managed
    # outside the chart). Leave unset to have the chart create the PVC.
    # Note: pvcStorage must still be set to a valid string (e.g., "50Gi") to trigger
    # the volume and volumeMounts creation in the deployment.
    # pvcExistingClaimName: "my-existing-claim"

{{- else if kindIs "string" $modelSpec.pvcStorage }}
persistentVolumeClaim:
claimName: "{{ .Release.Name }}-{{$modelSpec.name}}-storage-claim"
claimName: {{ $modelSpec.pvcExistingClaimName | default (printf "%s-%s-storage-claim" .Release.Name $modelSpec.name) | quote }}

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.

medium

The persistentVolumeClaim block is nested inside {{- else if kindIs "string" $modelSpec.pvcStorage }} (line 472). This means that if a user sets pvcExistingClaimName but unsets pvcStorage or sets it to a non-string value, the persistentVolumeClaim volume will not be rendered at all.

To make this more robust and avoid silent failures when pvcStorage is omitted, consider updating the outer template guards (such as lines 418, 464, and 472) to also check for pvcExistingClaimName (e.g., or (hasKey $modelSpec "pvcStorage") (hasKey $modelSpec "pvcExistingClaimName")).

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.

feature: Existing Claim for PVC

1 participant