Dynamic Provisioning in Kubernetes
How Kubernetes creates storage on demand the moment an application asks for it, what StorageClasses, claims and CSI drivers really do, and how to run this safely and cheaply in production, explained from zero.
Imagine you rent a small office in a big business center. In the old days, if you needed a new filing cabinet, you wrote to the office manager, waited a week, and someone ordered a cabinet, carried it up and placed it in your room. If you forgot to ask, your papers piled up on the floor. If the manager bought too many cabinets, they sat empty in a warehouse and cost money.
Now imagine a modern business center with a self-service counter. You fill in a short form saying “I need one cabinet, medium size, fireproof”. Within a minute, a cabinet appears in your room, exactly as described. When you no longer need it, it is taken away. Nobody wrote letters, nobody guessed in advance, and nothing sat unused.
That is dynamic provisioning. In Kubernetes, applications need disks to store their data. Instead of an administrator creating each disk by hand in advance, the cluster creates the disk automatically the moment an application asks for one. In this guide you will learn what dynamic provisioning is, why it replaced manual storage, which parts make it work, how a request travels from the application to a real disk, and how to run it safely in production. Every new word is explained the first time it appears.
1What Is Dynamic Provisioning?
A one-sentence idea with a lot of machinery behind it.
Dynamic provisioning is the ability of Kubernetes to create storage automatically, on demand, when an application requests it. The application says how much space it needs and what kind of storage it wants. Kubernetes talks to the storage system, such as a cloud disk service, asks it to create a disk of that size, and then attaches the new disk to the application.
The opposite is static provisioning, where an administrator creates disks ahead of time and registers each one in Kubernetes by hand, hoping that the disks match what applications will later ask for.
Static provisioning is a library that buys books in advance and hopes readers will want them. Dynamic provisioning is a print-on-demand shop: a reader asks for a title, and the book is printed and handed over a few minutes later. No shelf space is wasted on books nobody wants, and no reader is turned away because the exact book was not in stock.
2The Problem: Why Manual Storage Does Not Scale
To appreciate the solution, first feel the pain of the old way.
Containers are temporary. When a container stops, everything it wrote inside itself disappears. That is perfect for web servers that keep no memory of visitors, but disastrous for databases, uploaded photos, message queues and anything else that must survive restarts. Such applications need persistent storage, which is storage that lives on after the container is gone.
Kubernetes represents this with two objects. A PersistentVolume (PV) is a piece of real storage registered in the cluster, such as a cloud disk. A PersistentVolumeClaim (PVC) is an application’s request for storage, saying how much and what kind. A claim is matched to a volume, and then the Pod uses the claim.
The static way and its pains
Waiting
A developer needs a disk and must ask an administrator, who creates it in the cloud console, then registers it in the cluster. Days pass.
Guessing sizes
Administrators create disks in advance without knowing what applications will need. Sizes rarely match, so claims stay unbound or waste space.
Human error
Wrong region, wrong type, a typo in a volume identifier. Each manual step is a chance for a mistake.
Forgotten leftovers
Disks created for a test are never deleted and keep billing every month.
No self-service
Teams cannot move fast, because every stateful application depends on a person outside the team.
flowchart LR
subgraph ST["Static provisioning"]
direction TB
A1["Developer asks admin"] --> A2["Admin creates disk in cloud"]
A2 --> A3["Admin registers PersistentVolume"]
A3 --> A4["Claim finds a matching volume"]
end
subgraph DY["Dynamic provisioning"]
direction TB
B1["Developer creates claim"] --> B2["Cluster asks storage system for a disk"]
B2 --> B3["Volume object created and bound automatically"]
end
3Foundations: Volumes, Claims and Bindings
The storage vocabulary of Kubernetes, one word at a time.
Volume
A folder that a container can read and write. Some volumes vanish with the Pod, others survive. Persistent ones survive.
PersistentVolume (PV)
The cluster’s record of one real piece of storage, with its size, access rules and where it lives. It belongs to the whole cluster, not to a namespace.
PersistentVolumeClaim (PVC)
An application’s request for storage. It belongs to a namespace. It says: this much space, this access style, this class.
StorageClass
A named recipe describing a kind of storage, such as “fast SSD” or “cheap slow disk”, and which driver creates it.
Binding
The one-to-one connection between a claim and a volume. Once bound, the volume belongs exclusively to that claim.
Provisioner
The program that actually creates the real disk when a claim needs one.
Access modes
An access mode says how many machines may use the storage at once.
| Mode | Short name | Meaning | Typical storage |
|---|---|---|---|
| ReadWriteOnce | RWO | Read and write by one node at a time | Cloud block disks |
| ReadOnlyMany | ROX | Read by many nodes | Shared read-only content |
| ReadWriteMany | RWX | Read and write by many nodes at once | Network file systems |
| ReadWriteOncePod | RWOP | Read and write by exactly one Pod | Drivers that support it, for strict single-writer safety |
The PV is a real storage locker in a warehouse. The PVC is your rental request form: “one locker, medium size, climate controlled”. The StorageClass is the price list that says what kinds of lockers exist and who builds them. Binding is the moment your key is handed over.
4The StorageClass: The Heart of Dynamic Provisioning
Everything dynamic starts with a StorageClass. Without one, there is no recipe to follow.
A StorageClass is a cluster-wide object that describes one kind of storage you offer. Administrators create a small menu of classes, for example “standard”, “fast” and “shared-files”. Developers pick from the menu by name, without needing to know any cloud details.
Fields of a StorageClass
| Field | Meaning | Common values |
|---|---|---|
| provisioner | Which driver creates the storage | A driver name such as the AWS EBS, Google persistent disk or Azure Disk CSI drivers |
| parameters | Driver-specific options | Disk type, speed, encryption, file system format |
| reclaimPolicy | What happens to the disk when the claim is deleted | Delete (default) or Retain |
| volumeBindingMode | When the disk is created and bound | Immediate (default) or WaitForFirstConsumer |
| allowVolumeExpansion | Whether claims may grow later | True or false |
| mountOptions | Extra options used when mounting | Driver and file-system specific |
| allowedTopologies | Which zones or areas the disk may be created in | A list of zone labels |
The default class
One StorageClass can be marked as the cluster’s default, using a special annotation. When a claim does not name any class, Kubernetes assigns the default one. This makes life easy for beginners, since a claim with only a size will just work.
There is a subtle trap here. A claim that sets its class name to an empty text is different from a claim that leaves the field out. An empty class name means “do not use dynamic provisioning; bind me only to an existing volume that has no class”. Leaving the field out means “use the default class, if any”.
Having two default classes confuses the cluster, and new claims may be rejected or picked unpredictably depending on the version. Keep exactly one default.
A StorageClass is a menu item in a restaurant: “Espresso, double shot, ceramic cup”. You order by name. The kitchen knows the recipe. If you just say “coffee”, the waiter brings the house special, which is the default class.
5Architecture and Components
Who does what when a disk is created? Here is the cast of characters.
flowchart TB
DEV["Developer: creates claim"] --> API["API server"]
API --> PVCTL["Volume controllers inside Kubernetes"]
API --> PROV["CSI external provisioner sidecar"]
subgraph CTRL["CSI controller Pod"]
PROV
ATT["External attacher sidecar"]
RES["External resizer sidecar"]
SNAP["External snapshotter sidecar"]
DRV["CSI driver: controller service"]
end
PROV --> DRV
ATT --> DRV
RES --> DRV
SNAP --> DRV
DRV --> CLOUD["Storage system: cloud disk service or storage array"]
subgraph NODE["CSI node Pod on every machine"]
REG["Node driver registrar"]
NDRV["CSI driver: node service"]
end
KL["Kubelet"] --> NDRV
NDRV --> DISK["Mounted disk in the Pod"]
What is CSI?
CSI stands for Container Storage Interface. It is a standard agreement between Kubernetes and storage vendors about how to create, attach, mount, resize and snapshot disks. Before CSI, storage code lived inside Kubernetes itself, so every new storage system meant changing Kubernetes. With CSI, vendors ship a separate driver, and Kubernetes talks to every driver in the same way.
The moving parts
PV controller
Part of Kubernetes itself. It matches claims with volumes and manages the binding and the reclaim step.
External provisioner
A helper container that watches for claims that need a new volume, and asks the driver to create one. It then creates the PV object for the result.
External attacher
Asks the driver to connect a disk to a specific machine, for storage that must be attached before use.
External resizer and snapshotter
Handle growing volumes and taking point-in-time copies called snapshots.
The CSI driver
The vendor’s program. Its controller half talks to the storage system’s programming interface. Its node half runs on every machine and performs formatting and mounting.
The kubelet
The agent on each node. It asks the node half of the driver to prepare the disk and make it visible inside the Pod.
The helper containers are called sidecars because they run beside the driver in the same Pod. They are maintained by the Kubernetes project, so every driver reuses the same well-tested logic for watching objects, and vendors only write the storage-specific part.
6Internal Working: From Claim to Disk
Let us follow one request through every step, from the moment a developer asks for storage.
sequenceDiagram
participant D as Developer
participant A as API server
participant P as External provisioner
participant C as CSI driver
participant S as Storage system
participant V as PV controller
D->>A: Create PVC with size and class
A-->>P: Watch event: new claim needs a volume
P->>C: CreateVolume request
C->>S: Create disk of requested size and type
S-->>C: Disk identifier
C-->>P: Volume created
P->>A: Create PV object for that disk
A-->>V: New PV matches claim
V->>A: Bind PV and PVC
A-->>D: Claim status is Bound
Step by step
The claim is created
The claim is stored in the API server with status Pending. It names a class, or receives the default one automatically.
The provisioner notices
The provisioner sidecar for that class’s driver sees a claim that has no volume yet. It checks that the class names its driver.
The driver creates the disk
The provisioner calls the driver’s create-volume operation with the size and the class parameters. The driver asks the storage system to create the disk and returns its identifier.
The PV object is written
The provisioner creates a PersistentVolume object describing the new disk, including its identifier, size, access modes and, importantly, the zone it lives in.
Binding
The PV controller matches the new volume to the claim, marks both as bound, and the claim’s status changes to Bound.
The Pod is scheduled
The scheduler places the Pod on a machine that can reach the disk, considering the zone recorded in the volume.
Attach, format and mount
For block disks, the attacher connects the disk to the machine. The node half of the driver then formats it with a file system if it is new, and mounts it into the Pod’s container at the path you chose.
A developer fills in a room-booking form (the claim). A booking clerk (the provisioner) reads it, phones the hotel (the driver and the storage system), receives a room number, and writes it on the guest card (the PV). The desk (the PV controller) hands the guest card to the guest. Then the porter (the kubelet) carries the bags to the room and opens the door.
7Binding Modes: Immediate or Wait for the Pod?
One setting in the StorageClass decides whether your disk lands in the right place. It is one of the most important settings in the whole topic.
flowchart TD
subgraph IM["Immediate mode"]
I1["Claim created"] --> I2["Disk created at once in some zone"]
I2 --> I3["Pod scheduled later"]
I3 --> I4["Pod may need another zone: stuck Pending"]
end
subgraph WF["WaitForFirstConsumer mode"]
W1["Claim created and waits"] --> W2["Pod is scheduled first, node and zone chosen"]
W2 --> W3["Disk created in that same zone"]
W3 --> W4["Pod starts normally"]
end
The zone problem
Many cloud disks live in one specific availability zone, which is a separate building within a region. A Pod can only use a zonal disk if it runs on a machine in that same zone. If the disk is created immediately in zone A, but the Pod is later scheduled onto a machine in zone B because that is where free processor time exists, the Pod is stuck: the disk cannot travel.
The solution: wait for the first consumer
With WaitForFirstConsumer, the claim stays unbound until a Pod that uses it is created. The scheduler first picks a node, considering processor, memory, affinity and also storage zones. Then the provisioner creates the disk in the chosen node’s zone. The disk and the Pod always match.
| Aspect | Immediate | WaitForFirstConsumer |
|---|---|---|
| When is the disk created? | As soon as the claim is made | When a Pod using the claim is scheduled |
| Placement chosen by | The storage driver, with little knowledge of the Pod | The scheduler, with full knowledge of the Pod |
| Claim status before use | Bound | Pending, which is normal |
| Best for | Storage reachable from everywhere, such as network file systems | Zonal or local disks |
With the waiting mode, a claim showing Pending before any Pod uses it is expected behavior, not an error. Beginners often think something is broken. It becomes Bound when the first Pod arrives.
Production example: multi-zone database
A team runs three database replicas across three zones. Each replica has its own claim. Using the waiting mode, each disk is created in the zone where its replica was scheduled. Combined with rules that spread replicas over zones, the database survives the loss of any single zone.
8Reclaim Policy: What Happens When You Delete?
Creating storage is easy. Deleting it safely is where careers get tested.
The reclaim policy decides what happens to the real disk and its data when the claim is deleted. Dynamically created volumes take the policy from their StorageClass.
Delete (the default)
- Deleting the claim also deletes the volume object and the real disk.
- No leftover cost and no orphans.
- Perfect for temporary, test and reproducible data.
- Dangerous for data you cannot recreate.
Retain
- Deleting the claim keeps the disk and its data.
- The volume becomes Released and cannot be reused automatically.
- An administrator must clean up or recover it by hand.
- Safer for valuable data, but leftovers can keep billing.
The classic accident
A developer deletes the Kubernetes namespace of a test system, or removes the wrong claim. Under the Delete policy, the underlying cloud disks are erased along with it, and the data is gone for good. Many teams have learned this the hard way.
Protective habits
- Use a separate class with the Retain policy for production databases.
- You can change the reclaim policy of an already created volume to Retain before doing risky work.
- Take snapshots or backups before destructive changes.
- Kubernetes protects claims that are in use by Pods: a claim in use is not removed until the Pod finishes with it.
Delete is a rental locker that is emptied and cleaned the moment you hand back your key. Retain is a locker that is locked and put aside for the manager to inspect. The first is tidy and cheap. The second is safe when the contents matter.
9Data Flow and Lifecycle of a Volume
A dynamically provisioned volume passes through recognizable stages, each with its own status.
Claim Pending
The request exists but has no volume yet. Either the disk is being created, or the class waits for a Pod.
Provisioning
The driver is creating the disk. Cloud disks usually take seconds; some systems take longer.
Bound
The claim and volume are paired. The claim can now be used by Pods.
In use
A Pod mounts the volume. Data is written and read. The volume can be expanded or snapshotted during this stage.
Claim deleted
The application no longer needs the storage. Kubernetes waits until no Pod is still using the claim.
Released, then Deleted or kept
With the Delete policy, the driver removes the disk and the volume object disappears. With Retain, the volume stays as Released for manual handling.
What happens when a Pod moves?
When a Pod using a block disk is rescheduled to another machine in the same zone, Kubernetes detaches the disk from the old machine and attaches it to the new one before starting the Pod. This takes time: often tens of seconds, and sometimes minutes if the old machine failed and the cloud still thinks the disk is attached there. That delay is a real factor in how quickly a stateful application recovers.
The data belongs to the claim, not to the Pod. You can delete and recreate the Pod, even change its container image, and the same data appears again, as long as the new Pod refers to the same claim.
10StatefulSets and Automatic Claims
For databases and similar software, Kubernetes can create one claim per replica automatically.
A StatefulSet is a Kubernetes controller for applications that need a stable identity and their own storage, such as database members. Instead of asking for claims one by one, a StatefulSet carries a template for claims, called volumeClaimTemplates. For each replica it creates a claim from the template, giving each replica its own disk.
flowchart LR
SS["StatefulSet with claim template"] --> R0["Replica 0"]
SS --> R1["Replica 1"]
SS --> R2["Replica 2"]
R0 --> C0["Claim 0"] --> D0["Disk 0"]
R1 --> C1["Claim 1"] --> D1["Disk 1"]
R2 --> C2["Claim 2"] --> D2["Disk 2"]
Important behaviors
- Claim names follow a pattern based on the template name and the replica number, so replica 1 always gets back its own disk.
- If a replica is deleted and recreated, it reattaches to the same claim, keeping its data.
- By default, scaling down does not delete claims. This is a safety feature, but it also means leftover disks that keep billing. Newer Kubernetes versions let you choose a retention policy that deletes claims on scale-down or on deletion of the StatefulSet.
- Deleting a StatefulSet does not by default delete its claims either.
Production example: replicated database
A three-member database runs as a StatefulSet. Each member gets its own fast disk from the “fast” class. When one node fails, the affected member is rescheduled, its disk is reattached elsewhere in the same zone, and the member rejoins the group with all its data. Nobody creates or attaches a disk by hand.
11Expansion, Snapshots and Clones
Provisioning is only the start. Storage also needs to grow, be copied and be backed up.
Volume expansion
If the class allows it, you raise the requested size in the claim and Kubernetes asks the driver to enlarge the disk. Many drivers can also grow the file system while the Pod runs. Shrinking is not supported.
Snapshots
A snapshot is a point-in-time copy of a volume, requested through a VolumeSnapshot object and a matching class. Fast to take and useful for quick recovery.
Restore and cloning
A new claim can declare a snapshot or another claim as its data source, and the new disk starts out with that data. Good for creating test copies of production data.
Expansion rules of thumb
- Expansion must be allowed in the class before it is needed. It is much easier to allow it from the start.
- Only increase the size; the request to decrease is refused.
- Cloud providers may limit how often a disk can be modified, so do not resize in tiny steps repeatedly.
- Not every driver or file system supports online expansion. Check your driver’s notes.
Snapshots are not backups
A snapshot usually lives in the same storage system as the original. If that system fails, or someone deletes the storage account, the snapshots go too. A true backup is stored separately, ideally in another region or account. Use snapshots for speed and backups for safety.
Expansion is asking the storage room for a bigger shelf. A snapshot is taking a photograph of the shelf exactly as it looks now. A clone is building a new shelf that looks just like the photograph. A backup is keeping a second copy of everything in a different building.
12Choosing a Storage Backend
Dynamic provisioning works with many kinds of storage. The right choice depends on what your application needs.
| Kind of storage | Examples | Access | Strengths | Cautions |
|---|---|---|---|---|
| Cloud block disks | AWS EBS, Google persistent disks, Azure Disks | Usually RWO | Fast, simple, well supported | Tied to one zone; attach delay on failover |
| Cloud file systems | AWS EFS, Google Filestore, Azure Files | RWX | Shared by many Pods and nodes; not zone-bound in many designs | Higher latency and often higher cost per GB |
| Software-defined storage | Ceph via Rook, Longhorn, OpenEBS, Portworx | RWO and RWX | Works on any infrastructure, replicates data across nodes | You operate it; performance depends on your hardware |
| Local disks | Local SSDs on the node, a local path provisioner | RWO on one node | Lowest latency, cheap | Data is lost or stranded if the node dies; limited dynamic support |
| Enterprise storage arrays | Vendor arrays with their own CSI drivers | RWO, RWX | Mature features like replication and snapshots | Cost, vendor dependency |
| Object storage | S3-compatible services | Not a disk | Huge and cheap; accessed by the application over the network | Not a file system; not provisioned as a volume in the usual way |
Local development clusters
Small learning clusters, such as minikube and kind, come with a simple built-in provisioner that creates folders on the machine. It is perfect for practice. It offers no replication and no protection against losing the machine, so never treat it as production storage.
Older manifests may name provisioners with a prefix such as kubernetes.io followed by the storage type. Kubernetes has moved these built-in storage plugins to CSI drivers, and many of the old built-in ones have been removed or redirected. If you inherit an old cluster, check the migration status of your storage plugins before upgrading.
13Performance: Choosing Speed With Classes
Not all disks are equal. The StorageClass is where you decide how fast, and how expensive, a disk will be.
Three numbers that describe disk speed
IOPS
Input and output operations per second: how many small reads or writes the disk can do each second. Databases with many tiny operations care most about this.
Throughput
How many megabytes per second can flow. Analytics and backups that move big files care about this.
Latency
How long a single operation takes. Interactive applications feel latency directly.
Designing a small menu of classes
A good platform team offers a few clear classes rather than a dozen confusing ones. Here is a typical menu.
| Class name | Backed by | Use for | Reclaim | Expansion |
|---|---|---|---|---|
| standard | General-purpose disk | Most applications, default choice | Delete | Allowed |
| fast | High-performance SSD with tuned IOPS | Databases, queues | Retain for production | Allowed |
| shared | Network file system | Shared content, uploads read by many Pods | Delete | Allowed |
| archive | Cheap, slower disk | Logs, rarely read data | Delete | Allowed |
| scratch | Local or ephemeral disk | Temporary processing space | Delete | Not needed |
Performance traps
- Size can control speed. On some cloud disk types, larger disks receive more IOPS. A tiny disk may be too slow, even if you need little space.
- Burst credits. Some cheap disk types allow short bursts and then slow down. A test that runs for a minute can look perfect, while a real workload later crawls.
- Per-machine limits. Each virtual machine can attach only a limited number of disks and only so much combined throughput, whatever the disk itself can do.
- Noisy neighbors on shared storage. Network file systems and shared arrays can slow down when other tenants are busy.
- Cross-zone traffic. Mounting network storage across zones adds delay and may add data transfer charges.
Choosing a storage class is like choosing a delivery service. Express is fast and costly, standard is fine for most parcels, and economy is cheap but slow. You do not send birthday cakes by economy, and you do not pay for express on old books.
14Scalability, Availability and Reliability
Storage is where “cattle not pets” stops being true. Data must survive what Pods do not.
A disk is a single copy
A cloud block disk is usually replicated inside its zone by the provider, but it lives in one zone. If the zone is lost, the disk is unavailable. Plan for this with application-level replication or backups in another zone.
Replicate at the application layer
Databases with built-in replication keep copies on several members, each on its own disk in a different zone. This is the standard way to survive a zone outage.
Or replicate at the storage layer
Software-defined storage systems copy blocks across nodes for you, allowing Pods to move without losing data, at the cost of running and tuning that system.
Know the attach limits
Every node can attach only a certain number of volumes. If you pack many stateful Pods onto few machines, Pods stay Pending with a volume-limit message. Drivers report their limits to the scheduler.
Mind the cloud API limits
Creating and attaching disks means calls to the cloud provider. A sudden mass creation, such as recreating hundreds of claims at once, can hit request limits and slow everything down. Stagger big operations.
Failover takes time
When a machine dies, its disks must be detached before they can be attached elsewhere. The timings depend on the cloud and on Kubernetes settings, and can stretch to minutes.
Capacity awareness
Some storage systems have limited free space per node or per pool. Kubernetes can track storage capacity so that the scheduler avoids placing Pods where the volume could not be created.
Replication protects against hardware loss but not against mistakes. If someone deletes data, or an attacker encrypts it, the replicas faithfully copy the damage. Only tested backups, stored separately, protect against that.
15Advantages, Disadvantages and Trade-offs
Dynamic provisioning is the normal way to do storage on Kubernetes, but it has costs worth understanding.
Advantages
- Self-service: developers get storage in seconds without tickets.
- No wasted pre-created disks and no size guessing.
- Standard interface across many storage vendors through CSI.
- Consistent, reviewable configuration through classes.
- Automatic clean-up when claims are deleted.
- Works with expansion, snapshots and cloning.
- Fits StatefulSets so each replica gets its own disk.
Disadvantages
- Accidental deletion can destroy data quickly under the Delete policy.
- Easy to over-provision and forget, so costs creep up.
- Zonal disks tie Pods to zones and slow failover.
- Behavior varies from driver to driver.
- The driver is another piece of software to install, secure and upgrade.
- Bulk creation can hit cloud limits.
- Debugging spans Kubernetes, the driver and the storage system.
The design trade-offs
Freedom versus governance. Letting every team create any size of any class is fast but expensive. Quotas and a short menu of classes keep costs in check, at the price of sometimes saying no.
Delete versus Retain. Delete keeps things tidy and cheap. Retain protects data but leaves manual work and possible orphan bills. Match the policy to how precious the data is.
Immediate versus waiting for the first user. Immediate gives quick “Bound” statuses but can place disks badly. Waiting places disks well but shows Pending until used.
Block versus file storage. Block disks are faster and simpler but usually single-writer and zonal. File systems allow sharing, but are slower and more expensive.
Cloud-managed versus self-run storage. Cloud disks are easy and reliable but tied to a provider. Self-run software-defined storage is portable but demands operations skills.
16Security
Disks hold your most valuable asset: data. Protect them at every layer.
Encrypt at rest
Enable encryption in the class parameters so every new disk is encrypted with a key from your key management service. Make it the default so no one forgets.
Control the keys
Use separate keys for separate environments or sensitive data, restrict who can use them, and keep an audit trail of their use.
Limit who can create claims and classes
Use role-based access control. Developers may create claims in their own namespace; only administrators may create or change StorageClasses and volumes.
Namespace isolation
Claims are per namespace, so a team cannot bind another team’s claim. But volumes are cluster-wide, so guard direct access to volume objects and to Pods that can mount host paths.
Quotas and limits
Resource quotas can cap how much storage and how many claims a namespace may request, even per class. This limits both cost and denial-of-service by greedy or buggy automation.
Safe file ownership
Set the Pod security context so the volume is owned by a non-privileged group, and run containers as a normal user, not as the administrator.
Trust the driver
CSI node components run with high privileges on every machine. Use official drivers, pin versions, keep them patched and give their service accounts only the permissions they need.
Protect snapshots and clones
A snapshot contains all the data of the original. Apply the same encryption and access rules to snapshots, and restrict who can create claims from them.
Wipe on delete
Understand what your storage system does with deleted disks. Some systems guarantee zeroed data before reuse; for sensitive data, encryption with destroyable keys makes deleted data unreadable.
Secure backups separately
Store backups in a different account or region with separate credentials, and consider immutable storage so attackers cannot delete them.
An attacker who reaches your cluster or cloud account may delete claims and disks, and then snapshots as well. Keep at least one backup copy outside the reach of the cluster’s own credentials.
Good storage security is like a bank vault: the door is strong (encryption), only certain staff have keys (access control), every visit is logged (auditing), the vault has a limit on deposits (quotas), and a second copy of the most valuable papers is kept in a different city (backups).
17Monitoring, Logging and Metrics
A full disk at three in the morning is a classic outage. These signals warn you long before it happens.
Claim status
Watch for claims stuck in Pending for longer than expected. Remember that the waiting binding mode makes Pending normal until a Pod appears.
Events on claims and Pods
Provisioning failures, quota errors, zone mismatches and attach or mount errors all appear as events. They are the first place to look.
Volume usage metrics
The kubelet reports capacity, used and available bytes, and the same for file entries called inodes, for every mounted volume. Alert at around 80 percent full, and again at 90 percent.
Driver and sidecar logs
The provisioner, attacher and driver containers log every request to the storage system and its answer. Errors from the cloud, such as limits or permission problems, appear here.
Latency and throughput
Measure read and write latency as seen by the application, and use cloud metrics for the disk itself. Compare them with what the class promises.
Cloud-side view
Use the provider’s tools to look for unattached disks, throttling and errors that Kubernetes cannot see.
Inventory and drift
Regularly list all volumes, and compare them with the claims that use them. Volumes with no claim, or Released volumes, are candidates for cleanup or investigation.
Alarms worth setting
- Claim Pending beyond a set time with no waiting-mode explanation.
- Volume usage above 80 percent, and inode usage above 80 percent.
- Rate of growth predicting a full disk within a few days.
- Pods stuck in container creating because of attach or mount errors.
- Provisioner errors or cloud throttling messages.
- Released or unattached volumes older than a set number of days.
A disk can be “full” because it has run out of file entries, not space, especially when an application creates millions of tiny files. Watch both numbers.
18Cost Control and Governance
When creating disks is this easy, the danger is creating too many. A few guardrails keep the bill under control.
ResourceQuota for storage
Limits the total requested storage and the number of claims in a namespace, and can set separate limits per class, for example a small allowance for the expensive fast class.
LimitRange for claims
Sets minimum and maximum sizes for a single claim, stopping a typo from requesting ten terabytes.
Labels and cost tags
Tag every claim with a team and project label, and pass tags to the cloud through class parameters where drivers support it, so bills can be split by owner.
Right-sizing
Compare requested size with actual use. Start smaller and rely on expansion, rather than over-provisioning up front.
Orphan sweeps
Regularly find and remove volumes that no claim uses, especially Released ones and leftovers from deleted StatefulSets.
Lifecycle for test environments
Give temporary namespaces an automatic expiry, so their claims and disks are removed with them.
Production example: the forgotten disks
A company scales its test environments up and down every day. Each test run creates StatefulSets with large fast disks. After a year, an audit finds hundreds of unattached disks worth a large monthly bill, left behind because scaling down did not delete claims. A nightly cleanup job, an expiry label on test namespaces and a quota on the fast class cut the waste to almost nothing.
19Design Patterns and Anti-patterns
Proven habits and common traps.
Patterns that work
Pattern: A short, well-named menu of classes
Three to five classes with clear names and documented use cases. Developers choose by purpose, not by cloud jargon.
Pattern: Safe defaults
The default class is encrypted, allows expansion and uses the waiting binding mode. Anyone who forgets to choose still gets a sensible result.
Pattern: Separate classes for critical data
A dedicated class with the Retain policy and its own encryption key protects production databases from accidental deletion.
Pattern: Snapshots plus off-cluster backups
Frequent snapshots for quick restore, and periodic backups to a separate account for disaster recovery. Restore drills prove both work.
Pattern: Zone-aware stateful design
The waiting mode, spreading rules and application-level replication together give a database that survives zone loss.
Pattern: Storage as code
Classes, quotas and claim templates are kept in version control and applied automatically, so environments are reproducible.
Traps to avoid
What it looks like
Production databases on a class with the Delete policy and no backups.
Why it hurts
One wrong command removes both the claim and the disk, and the data is gone.
Better approach
Use a Retain class, take snapshots and keep off-cluster backups, and test restores.
What it looks like
Immediate binding for zonal disks in a multi-zone cluster.
Why it hurts
Disks are created in random zones, and Pods get stuck Pending because they cannot reach them.
Better approach
Use the waiting binding mode for any zonal or local storage.
What it looks like
Class without expansion enabled.
Why it hurts
When a disk fills up, the only fix is a risky copy of data to a new bigger disk, often under pressure.
Better approach
Allow expansion from the start, and monitor usage so you grow before it is urgent.
What it looks like
Using local, node-bound storage for data that cannot be rebuilt.
Why it hurts
If the node dies, the data is stranded or lost, and the Pod cannot move.
Better approach
Use replicated storage, or make sure the application replicates its own data across nodes.
What it looks like
Treating a snapshot as the only backup.
Why it hurts
Snapshots usually live with the original disk and share its fate and its credentials.
Better approach
Copy backups to another account or region and protect them from deletion.
20Best Practices and Common Mistakes
A checklist for storage that stays safe, fast and affordable.
Habits that pay off
- Use CSI drivers from your cloud or storage vendor, and keep them updated in step with Kubernetes upgrades.
- Enable expansion and encryption in every class from the start.
- Prefer the waiting binding mode for zonal and local storage.
- Pick the reclaim policy per class and document what each class does on deletion.
- Set quotas and size limits per namespace.
- Monitor usage and growth, including inodes, and alert early.
- Test restores on a schedule. A backup you have never restored is only a hope.
- Use claim templates in StatefulSets rather than hand-made claims.
- Check driver limits such as maximum volumes per node before packing stateful Pods.
- Practice failure: kill a node running a stateful Pod in a test cluster and time the recovery.
Mistakes beginners make
No default class and no class name
The claim stays Pending forever because nothing knows how to create the disk.
Typing the class name wrong
The claim refers to a class that does not exist, so no provisioner picks it up.
Empty class name by accident
Setting the class to an empty text disables dynamic provisioning, and the claim waits for a matching pre-made volume.
Driver not installed
The class names a driver that is missing from the cluster, so nobody responds to the claim.
Missing cloud permissions
The driver cannot create disks because its cloud identity lacks the right to do so. The logs show a permission error.
Using one disk from two nodes
A single-writer block disk requested by Pods on different machines. The second Pod cannot attach it.
Deleting the namespace casually
The claims disappear with it, and under the Delete policy, so does the data.
Confusing StorageClass immutability
Most fields of a class cannot be edited after creation. To change them, create a new class and migrate.
21Real-World and Industry Examples
How real teams use dynamic provisioning every day.
Managed Kubernetes on the big clouds
On the major managed services, a default StorageClass backed by the provider’s block disks is normally present out of the box, so a claim with only a size produces a working disk. Teams add their own classes for fast and shared storage.
Databases as operators
Database operators for PostgreSQL, MySQL, MongoDB, Kafka and others rely on StatefulSets and claim templates. The operator sets the class, size and spreading rules, so a whole database cluster, with a disk per member, appears from a short description.
Shared content with file storage
A publishing company stores uploaded images on a network file system class, so many web Pods on many machines read and write the same folder. Content survives Pod restarts and scaling events.
Self-managed clusters
Organizations running Kubernetes in their own data centers use software-defined storage such as Ceph through Rook, Longhorn or vendor arrays with CSI drivers. They get the same claim-based experience as the cloud, with their own hardware.
Data science and machine learning
Notebook servers give each user a personal disk that follows them across sessions. Training jobs use fast scratch space, and datasets are cloned from snapshots so experiments always start from the same data.
A typical online shop
The shop’s orders database runs as three replicas across three zones, each on its own fast disk with the Retain policy, with hourly snapshots and nightly backups copied to another account. Product images use a shared file class. The web tier uses no persistent storage at all. When traffic grows, the team expands the database disks with a single change, and no downtime is needed.
22Troubleshooting Storage Problems
Follow the request from the claim to the mount, and the fault reveals itself.
flowchart TD
S1["Pod stuck or claim Pending"] --> S2{"Claim status?"}
S2 -->|Pending| S3{"Class exists and driver installed?"}
S3 -->|No| F1["Fix class name or install driver"]
S3 -->|Yes| S4{"Waiting binding mode and no Pod yet?"}
S4 -->|Yes| F2["Normal: create the Pod"]
S4 -->|No| F3["Read provisioner and driver logs: permissions, quota, cloud limits"]
S2 -->|Bound| S5{"Pod status?"}
S5 -->|Pending| F4["Zone mismatch, volume limit per node or affinity conflict"]
S5 -->|Container creating| F5["Attach or mount error: check events and node driver logs"]
S5 -->|Running but failing| F6["Permissions, full disk, file system errors"]
| Symptom | Likely cause | What to check |
|---|---|---|
| Claim Pending, no events | No class and no default class | List classes, check the default marker and the claim’s class name |
| Claim Pending, provisioning failed event | Driver error, quota or permissions | Provisioner and driver logs; cloud identity permissions |
| Claim Pending, “waiting for first consumer” | Waiting binding mode, no Pod yet | Create the Pod that uses the claim |
| Pod Pending with volume node affinity conflict | Disk is in a different zone than available nodes | Node zones, disk zone, Pod placement rules |
| Pod Pending with too many volumes | Node attach limit reached | Driver limits; spread stateful Pods over more nodes |
| Pod stuck in container creating | Attach or mount failing; disk still attached to a dead node | Events; cloud console attachment status |
| Multi-attach error | Single-writer disk requested by a second node | Which Pods use the claim and where they run |
| Expansion not completing | File system resize needs a Pod restart or driver support | Claim conditions and driver notes |
| Application reports no space | Disk or inodes are full | Volume usage metrics; expand the claim |
| Claim stuck Terminating | A Pod still uses it | Find and remove the Pod |
23Frequently Asked Questions
Short answers to the questions people ask most.
24Summary and Key Takeaways
You began with a business center where filing cabinets arrive on request. Now you know how a cluster does the same for disks.
Key Takeaways
- The idea: Dynamic provisioning creates real storage automatically when a claim is made, using a StorageClass recipe and a CSI driver, so no administrator has to prepare disks in advance.
- The flow: A claim is created, the provisioner asks the driver for a disk, a volume object is written and bound, the Pod is scheduled, and the disk is attached, formatted and mounted.
- Two key settings: The binding mode decides where the disk lands, and the waiting mode is best for zonal storage. The reclaim policy decides what happens on deletion, so use Retain for precious data.
- Grow and protect: Enable expansion from the start, use snapshots for speed, and keep real backups outside the cluster’s reach.
- Design for failure: Disks live in one zone, failover takes time, and nodes have attach limits, so replicate at the application or storage layer and spread across zones.
- Secure and govern: Encrypt by default, restrict who can create classes and claims, use quotas and size limits, patch the drivers and watch for orphaned volumes that keep costing money.
- Observe it: Alert on Pending claims, mount errors, volume and inode usage, growth trends and provisioner errors, and rehearse restores and failovers before you need them.