In the previous lesson, you learned how PersistentVolumeClaims (PVCs) allow data to survive Pod deletions. You created a PVC, connected it to a Pod, manually deleted that Pod, and then manually recreated it to prove the data persisted. This was a great way to understand the concept, but it's not how real Kubernetes systems work. In production, you don't sit around waiting for Pods to crash so you can manually recreate them.
Instead, Kubernetes provides automated controllers that monitor your Pods and replace them when they fail, need updates, or require scaling. In this lesson, we'll introduce Deployments, which automatically manage Pods for you. You'll see that PVCs work seamlessly with Deployment-managed Pods, and you'll simulate a real crash scenario where a Pod disappears and is automatically replaced — all while your data remains safe and accessible.
A Deployment is a Kubernetes resource that manages a set of identical Pods. Instead of creating Pods directly, you define a Deployment that describes what your Pods should look like, and the Deployment controller ensures that the desired number of Pods are always running. If a Pod crashes, gets deleted, or becomes unhealthy, the Deployment immediately creates a replacement. This is exactly what you want in production — automatic recovery without human intervention.
Why does this matter for storage? Because it lets us test more realistic scenarios. When you manually delete a Pod and manually recreate it, you're in control of the timing and you know exactly what's happening. But in real systems, Pods can disappear unexpectedly due to node failures, out-of-memory errors, or application crashes. The Deployment will automatically spin up a new Pod with a completely different name and potentially on a different node. If your storage is truly persistent and decoupled from the Pod lifecycle, it should "just work" even in these automated replacement scenarios. That's what we're going to prove in this lesson.
We won't do a deep dive into all of Deployment's features — that's a topic for a different course. For now, you just need to understand that a Deployment is a wrapper around Pods that provides automatic management and recovery. The key insight for our storage lesson is that the way you connect storage to Pods doesn't change at all. Whether you're creating a standalone Pod or a Deployment-managed Pod, the volume and volumeMounts configuration is identical.
Before we can create a Deployment that uses persistent storage, we need to create the PersistentVolumeClaim itself. This is the same pattern you learned in the previous lesson — the PVC is a separate resource that requests storage independently of how Pods are managed. Here's the complete PVC definition:
This should look familiar. We're requesting 1 gibibyte of storage with the ReadWriteOnce access mode, which means one node can mount it for reading and writing at a time. The metadata.name is persistent-claim, which we'll reference later from our Deployment. Notice that there's nothing in this PVC definition that mentions Deployments or how Pods will be managed — that's by design. The PVC is purely a storage request, and it doesn't care whether it's used by a standalone Pod, a Deployment-managed Pod, or any other type of workload.
Save this YAML to a file called pvc.yaml. We'll apply it in a moment, but first, let's look at the Deployment definition so you can see how everything fits together.
Now let's look at the Deployment that will manage our Pod and connect it to the persistent storage. Here's the complete definition:
Let's break this down section by section. The top-level structure includes apiVersion: apps/v1 and kind: Deployment, which tells Kubernetes this is a Deployment resource. The metadata.name is web-deploy, which is just a name for this Deployment.
The replicas field tells the Deployment how many identical Pods to maintain. We're using 1 here because we're focused on storage persistence, not scaling.
This is a safe choice when using ReadWriteOnce volumes backed by block storage (such as cloud provider disks). By default, Deployments use a "RollingUpdate" strategy where they start a new Pod before shutting down the old one. With block storage backends that enforce single-node attachment, the new Pod may fail to start if it is scheduled on a different node while the old Pod still holds the volume — a "multi-attach" error. The Recreate strategy avoids this by ensuring the old Pod is fully terminated before the new one is created. Whether this is necessary depends on your storage backend; if your storage supports concurrent node access or your cluster reliably schedules replacement Pods on the same node, RollingUpdate may work fine.
Let's start by applying both the PVC and the Deployment. First, create the PVC:
You'll see:
The PVC now exists, and Kubernetes is working on provisioning storage for it. Next, create the Deployment:
You'll see:
The Deployment is now managing a Pod for us. Let's check the status of the Pod:
The -l app=web flag filters Pods by label, showing only the Pods managed by our Deployment. You should see output like this:
Notice the Pod name: web-deploy-7d4f8c9b5d-x7k2m. This name was automatically generated by the Deployment. The first part (web-deploy) comes from the Deployment name, followed by a unique identifier. Your Pod will have a different random suffix. The READY column shows 1/1, meaning the container is running, and the STATUS is Running. Copy this Pod name — you'll need it for the next commands.
Now let's write some data to the persistent storage. We'll create a simple text file that we can check later:
In a real production environment, Pods can crash for many reasons: the application might run out of memory, the node might fail, or there could be a bug that causes the container to exit. To simulate this, we'll manually delete the Pod. The Deployment doesn't know we're doing this on purpose — from its perspective, the Pod just disappeared, and it needs to create a replacement immediately.
Delete the Pod using its name:
Replace the Pod name with your actual Pod name. You'll see:
The Pod is gone. But here's the magic of Deployments — the Deployment controller immediately notices that it's supposed to maintain 1 replica, but now there are 0 Pods with the label app: web. So it automatically creates a new Pod. Let's watch this happen in real time:
The --watch flag keeps the command running and updates the output whenever the Pod status changes. You'll see something like this:
Note that the Pod may spend a few seconds in the ContainerCreating or Pending state while Kubernetes reattaches the PVC. This delay is completely normal — the storage system needs to detach the volume from where it was previously mounted and attach it to wherever the new Pod is scheduled. If you see this brief pause, it's not a misconfiguration; it's just part of how persistent volumes work with ReadWriteOnce access mode.
Notice the Pod name: web-deploy-7d4f8c9b5d-p9n4r. This is a completely different Pod from the one we deleted. It has a different random suffix. The Deployment created this new Pod automatically. You'll see the progress from to as Kubernetes pulls the image and starts the container. Once the status is and shows , press to stop watching.
We now have a brand new Pod with a completely different name running on potentially a different node. If our storage is truly persistent and decoupled from the Pod lifecycle, the data we wrote earlier should still be accessible. Let's check by reading the file from the new Pod:
Replace web-deploy-7d4f8c9b5d-p9n4r with your new Pod name from the previous step. You should see:
The data is still there! This is the proof we were looking for. The original Pod (web-deploy-7d4f8c9b5d-x7k2m) was completely deleted. The Deployment automatically created a new Pod (web-deploy-7d4f8c9b5d-p9n4r) with a different name. That new Pod connected to the same PVC, and because the PVC's storage exists independently of any Pod, the data we wrote earlier is still accessible. This is what we mean by storage lifecycle being independent of Pod lifecycle.
Think about what this means for real applications. If you're running a database in Kubernetes, the database Pod might crash or need to be updated. The Deployment will automatically create a new Pod, and that new Pod will connect to the same persistent storage where all your database files live. Your data doesn't disappear just because the Pod was replaced. Similarly, if you're running a web application where users upload files, those files are stored in a PVC. When you deploy a new version of your application, the old Pods are deleted and new Pods are created, but they all connect to the same PVC, so user uploads remain accessible.
This is the foundation of running stateful applications in Kubernetes. The combination of Deployments (for automatic Pod management) and PVCs (for persistent storage) gives you both resilience and data durability. Your application can survive crashes, updates, and scaling operations without losing data.
We've focused on crash scenarios where Pods are deleted and automatically replaced, but there's another common reason Pods get replaced: application updates. When you need to deploy a new version of your application — perhaps you've fixed a bug, added a feature, or updated a dependency — you modify the Deployment's Pod template (usually by changing the container image), and Kubernetes performs what's called a rolling update.
A rolling update is different from crash recovery in an important way. With crash recovery, the Deployment notices a Pod is missing and creates a replacement using the same Pod template. With a rolling update, you're changing the Pod template itself, so the Deployment creates new Pods based on the new template and terminates the old ones. For example, if you update your Deployment from nginx:1.24 to nginx:1.25, Kubernetes will create new Pods running version 1.25 and gradually shut down the Pods running version 1.24.
From a storage perspective, rolling updates work exactly like crash recovery. The new Pods connect to the same PVC, and all your data remains accessible. This is crucial for production systems — you need to be able to update your application without losing user data, configuration files, or database contents. When you update a web application, user uploads should still be there. When you update a database, the database files should persist across the update.
You can trigger a rolling update by editing your Deployment's YAML file and running kubectl apply again. After you apply the change, you can monitor the rollout progress with:
This command waits until the Deployment has finished creating new Pods and terminating old ones. You'll see output like "deployment 'web-deploy' successfully rolled out" when the update is complete. This is helpful during updates because you want to know when the new version is fully deployed before you start testing or monitoring the updated application.
The key insight is that whether Pods are replaced due to crashes, node failures, or planned updates, your PVC-backed storage remains intact and accessible. This consistency is what makes PersistentVolumeClaims so valuable for production workloads.
In this lesson, you learned that PersistentVolumeClaims work seamlessly with Deployments, which automatically manage and replace Pods. When a Pod crashes or is deleted, the Deployment immediately creates a replacement Pod, and that new Pod connects to the same PVC, preserving all data. This demonstrates that storage lifecycle is truly independent of Pod lifecycle — data persists regardless of whether Pods are manually managed or automatically replaced.
This pattern is fundamental for production systems where applications need to survive failures and updates without data loss. In the upcoming practice exercises, you'll set up your own Deployment with persistent storage, simulate various crash scenarios, and verify that data always persists, giving you hands-on experience with the storage patterns used in real-world Kubernetes applications.
