Illustrative people-free WIUNIX Academy operations workspace with a board explaining PVC binding, provisioning and CSI attachment stages

WIUNIX ACADEMY

Kubernetes PVC Pending and CSI: diagnose binding, attach and mount

Locate the stalled PVC/CSI stage: expected consumer waiting, provisioning, attachment or mounting, without deleting volumes or forcing writers.

Advanced35 min readUpdated
Make this guide yours

YOUR SYSTEM. YOUR STEPS.

Where are you working?

Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.

Rocky Linux 10Reviewed against official documentation ·

USE YOUR OWN VALUES

Configure this tutorial

Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.

Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.

Set values for my environment9 editable values

THE OUTCOME

What will you have at the end?

Locate the stalled PVC/CSI stage: expected consumer waiting, provisioning, attachment or mounting, without deleting volumes or forcing writers.

Supported operating systems and versions

This observes an existing cluster from a Linux administration host; OS selection does not choose node operating systems. Maintained upstream 1.35–1.37 branches and client skew were reviewed on 2026-11-05; provider/driver capability and support are separate. The form accepts simple names up to 32 characters, a form limit rather than a Kubernetes name limit. For longer/unsupported names prepare these same commands in a trusted editor with exact original names; never truncate or rename objects. No article command ran on a cluster during authoring and no all-OS execution matrix is claimed.

Before you begin

  • An existing authorized cluster/context, trusted identity and compatible kubectl, exact resource names and an incident time window.
  • Read access to the target namespace; node, PV, CSI or metrics visibility may need separately delegated permissions and an owner-assisted branch.
  • The existing change/recovery workflow and a private evidence location; no credentials, raw kubeconfig or sensitive outputs enter the form or public reports.

Find the storage stage that has not finished

A Pending claim, an unscheduled Pod and a bound volume that cannot mount are different failure boundaries. We trace one existing Pod and its actual claim through scheduler choice, binding/provisioning, CSI attachment and node-side mounting. No volume is created, deleted, detached or repaired by this investigation.

A PVC is a namespaced storage request; a PV represents storage available to the cluster. A StorageClass chooses provisioning policy and often a CSI driver. CSI separates the storage controller from the per-node plugin. Those components and the backend have their own compatibility, permissions and health, independent of the OS on your administration laptop.

Use a maintained Kubernetes 1.35–1.37 cluster and its supported existing driver. Managed providers may require a specific driver/sidecar release or expose only part of the control plane. Confirm that support with the storage owner. This guide does not repeat CrashLoop/OOM application debugging or DNS/NetworkPolicy tests, and it does not bootstrap a cluster.

Apply real object names without changing any objects

Open the public-values form and start with the actual namespace, Pod and claim. Discover the class, bound PV and selected node before filling their example fields or using those optional branches. Driver Pod/container names come from the storage owner; there is no universal CSI namespace or label to guess.

Values stay in this tab for the selected environment and language. Apply or Reset before copying; invalid/pending changes block copy. Simple identifiers up to 32 characters are a form limit, not a Kubernetes limit. For dotted/long real names, use a trusted editor with the exact names rather than renaming or truncating resources. Never enter secrets, volume credentials or kubeconfig here.

01

LET’S BUILD

Check this host’s installed client and package channel

The OS selection describes the administration host running kubectl, not a qualification of cluster-node operating systems. Use the existing approved kubectl under the authorized normal user; sudo can select a different kubeconfig and identity. kubectl is a client, not a daemon, and this workflow installs no kubelet or cluster.

Query the base packages and the client build. Missing tooling means prepare an approved compatible client in a planned change through the team’s official workflow before continuing. Do not replace it with an arbitrary latest package, an Arch package on Manjaro or an unapproved repository. The official setup reference also documents pinned binary/checksum verification; this guide deliberately requires an existing approved client.

Use a supported updated minor of this 10/9 family and entitled RHEL or corresponding official Rocky/Alma repositories for base packages. Keep the approved existing kubectl and authentication plugin. Preserve SELinux/firewalld and the host crypto policy; no new inbound port or node service is needed.

bash

Administration host under the authorized normal user

cat /etc/os-release
uname -m
rpm -q ca-certificates bash coreutils
command -v bash kubectl
kubectl version --client --output=yaml
How do I know it worked?

The existing compatible client and base tools are identified; missing prerequisites stop preparation.

02

LET’S BUILD

Keep SELinux and API access separate from cluster diagnosis

Preserve SELinux, firewalld and the administration host’s crypto policy. Resolve plugin/kubeconfig/TLS-trust failures with its owner; do not set permissive mode, recursively relabel paths or open a new public port. These checks report host state, not the cluster nodes’ security configuration.

bash

Administration host; existing state only

if command -v getenforce >/dev/null 2>&1; then getenforce; fi
if command -v firewall-cmd >/dev/null 2>&1; then firewall-cmd --state; fi
How do I know it worked?

Visible host state is recorded; policy errors go to its owner, with protections unchanged.

03

LET’S BUILD

Pin the selected context in this shell

Compare the context name with the authorized target and keep this Bash shell. The k function in subsequent panels pins that context and a request timeout. Reload this step in a new shell; an empty selection must not silently become another target.

At review time the upstream maintained branches are 1.37, 1.36 and 1.35. kubectl must be within one minor of every API server it may reach; an HA control plane during upgrade narrows the range. Distribution/provider and driver support can impose additional limits. A failed or unavailable server version is not permission to proceed on a guess.

bash

Same authorized Bash shell on the administration host

context=$(kubectl config current-context) || exit 1
test -n "$context" || exit 1
printf 'Selected context: %s\n' "$context"
k() {
    test -n "${context:-}" || { printf 'STOP: load the selected context in this shell first.\n' >&2; return 1; }
    kubectl --context "$context" --request-timeout=20s "$@"
}
k version --output=yaml
How do I know it worked?

The authorized context and actual client/server versions are confirmed, and k is loaded in this shell.

04

LET’S BUILD

Check which observations your identity is allowed to make

The namespace owner may read its Pod/PVC but not cluster-scoped PV, StorageClass, Node or VolumeAttachment objects. Query authorization before choosing those branches. Each answer describes this identity, not whether the storage backend is healthy. A no answer is a delegated-owner handoff, not permission to obtain cluster-admin.

Event messages and driver logs can contain internal backend identifiers. Keep them in the approved private incident record. This investigation does not retrieve Kubernetes Secret contents or raw authentication configuration.

bash

Same authorized Bash shell on the administration host

k auth can-i get pods -n 'apps'
k auth can-i get persistentvolumeclaims -n 'apps'
k auth can-i list events -n 'apps'
k auth can-i get storageclasses.storage.k8s.io
k auth can-i get persistentvolumes
k auth can-i list volumeattachments.storage.k8s.io
How do I know it worked?

Required namespace visibility is available; each cluster-scoped branch has an explicitly authorized reader or an identified owner.

Explore all tutorials ↗