{"id":79850,"date":"2026-11-12T06:01:19","date_gmt":"2026-11-12T06:01:19","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=79850"},"modified":"2026-11-12T06:01:22","modified_gmt":"2026-11-12T06:01:22","slug":"kubernetes-storageclass-using-openebs-local-pv-hostpath-complete-step-by-step-kubernetes-tutorial","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/kubernetes-storageclass-using-openebs-local-pv-hostpath-complete-step-by-step-kubernetes-tutorial\/","title":{"rendered":"Kubernetes storageclass\u00a0using OpenEBS Local PV HostPath \u2014 Complete Step-by-Step Kubernetes Tutorial"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>Dynamic storage provisioner:<\/strong>&nbsp;<code>openebs.io\/local<\/code><br><strong>Lab platform:<\/strong>&nbsp;Self-managed Kubernetes v1.35.10 on Ubuntu Linux (kubeadm or other manual installation)<br><strong>OpenEBS release referenced:<\/strong>&nbsp;OpenEBS 4.6.2 (HostPath engine v4.6.0), current as checked on November 12, 2026<br><strong>Lab target:<\/strong>&nbsp;Three StatefulSet replicas, each with its own dynamically provisioned 1Gi Local PV backed by a directory on a worker node<br><strong>Difficulty:<\/strong>&nbsp;Beginner to intermediate<br><strong>Scope:<\/strong>&nbsp;A lightweight&nbsp;<strong>OpenEBS Local PV HostPath-only<\/strong>&nbsp;installation; no EKS, AKS, GKE, Ceph, LVM, ZFS, or Mayastor required.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Important:<\/strong>&nbsp;All commands are examples to run against&nbsp;<strong>your cluster<\/strong>, not commands already executed. Verify your&nbsp;<code>kubectl<\/code>&nbsp;context and node status before applying anything. A 1Gi PVC represents a requested size; without filesystem quotas it&nbsp;<strong>does not impose a 1Gi disk-use limit<\/strong>. The backing storage is node-local, not replicated or highly available.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Table of contents<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#1-learning-objectives\">Learning objectives<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#2-architecture-and-terminology\">Architecture and terminology<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#3-openebs-vs-rancher-vs-kubernetes-no-provisioner\">OpenEBS vs Rancher vs Kubernetes no-provisioner<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#4-prerequisites-and-safety-checks\">Prerequisites and safety checks<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#5-install-helm-if-needed\">Install Helm if needed<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#6-install-openebs-hostpath-only-using-helm\">Install OpenEBS HostPath-only using Helm<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#7-check-the-default-openebs-storageclass\">Check the default OpenEBS StorageClass<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#8-create-a-custom-hostpath-storageclass\">Create a custom HostPath StorageClass<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#9-create-a-statefulset-with-automatic-pvcs\">Create a StatefulSet with automatic PVCs<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#10-apply-resources-and-verify-dynamic-provisioning\">Apply resources and verify dynamic provisioning<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#11-find-the-real-data-directory-on-the-worker-node\">Find the real data directory on the worker node<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#12-test-persistence-after-pod-recreation\">Test persistence after Pod recreation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#13-test-storage-isolation-across-replicas\">Test storage isolation across replicas<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#14-optional-headless-service-for-stable-dns\">Optional: Headless Service for stable DNS<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#15-advanced-configuration\">Advanced configuration<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#16-troubleshooting-common-errors\">Troubleshooting common errors<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#17-storage-lifecycle-retention-and-cleanup\">Storage lifecycle, retention, and cleanup<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#18-operational-considerations-and-limitations\">Operational considerations and limitations<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#19-frequently-asked-questions\">Frequently asked questions<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#20-command-cheat-sheet\">Command cheat sheet<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#21-official-references\">Official references<\/a><\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1. Learning objectives<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">At the end of this lab, you will be able to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Install the OpenEBS Local PV HostPath dynamic provisioner on a self-managed Ubuntu cluster.<\/li>\n\n\n\n<li>Understand\u00a0<code>openebs.io\/local<\/code>\u00a0and\u00a0<code>WaitForFirstConsumer<\/code>.<\/li>\n\n\n\n<li>Create\u00a0<strong>only a StorageClass and StatefulSet as application manifests<\/strong>. OpenEBS and the StatefulSet will create PVs and PVCs automatically.<\/li>\n\n\n\n<li>Provision three independent 1Gi volumes for three StatefulSet Pods.<\/li>\n\n\n\n<li>Locate and inspect the directories on the underlying worker node.<\/li>\n\n\n\n<li>Confirm that files survive Pod deletion and recreation on the\u00a0<strong>same node<\/strong>.<\/li>\n\n\n\n<li>Troubleshoot\u00a0<code>Pending<\/code>\u00a0PVCs, taints, provisioning problems, and permission failures.<\/li>\n\n\n\n<li>Clean up safely without accidentally deleting other storage workloads.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2. Architecture and terminology<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">2.1 What is OpenEBS Local PV HostPath?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">OpenEBS is a Kubernetes storage project. The&nbsp;<strong>Local PV HostPath<\/strong>&nbsp;engine dynamically provisions persistent volumes from directories on a Kubernetes node&#8217;s filesystem. The local disk may be the OS disk or another disk already mounted on the node.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Provisioning flow:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> <code> StorageClass: openebs-hostpath-lab\n       provisioner: openebs.io\/local\n       volumeBindingMode: WaitForFirstConsumer\n                        |\n                        v\n               StatefulSet (3 Pods)\n                        |\n       +----------------+----------------+\n       |                |                |\n       v                v                v\n   Pod ...-0         Pod ...-1         Pod ...-2\n       |                |                |\n    PVC ...-0         PVC ...-1         PVC ...-2\n       |                |                |\n       v                v                v\n  OpenEBS provisions three local PVs dynamically\n       |                |                |\n       v                v                v\n \/var\/openebs\/local\/&lt;PV-0&gt;  ...\/&lt;PV-1&gt;  ...\/&lt;PV-2&gt;\n (on the node where the corresponding Pod runs)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">There is&nbsp;<strong>no shared network volume<\/strong>&nbsp;in this model. The three backing directories may be on the same worker or on different workers, depending on scheduling.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2.2 Key terms<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Term<\/th><th class=\"has-text-align-left\" data-align=\"left\">Meaning<\/th><\/tr><\/thead><tbody><tr><td>StorageClass (SC)<\/td><td>Defines&nbsp;<em>how<\/em>&nbsp;storage should be provisioned.<\/td><\/tr><tr><td>PersistentVolumeClaim (PVC)<\/td><td>Application request for storage. A StatefulSet&#8217;s&nbsp;<code>volumeClaimTemplates<\/code>&nbsp;generates these automatically.<\/td><\/tr><tr><td>PersistentVolume (PV)<\/td><td>Cluster storage object bound to a claim; OpenEBS creates it dynamically.<\/td><\/tr><tr><td>HostPath base path<\/td><td>Directory on the host, e.g.&nbsp;<code>\/var\/openebs\/local<\/code>, under which PV directories are created.<\/td><\/tr><tr><td>Local PV<\/td><td>Kubernetes PV referring to a filesystem path on a specific node, with node affinity.<\/td><\/tr><tr><td>OpenEBS provisioner<\/td><td>Controller that creates\/deletes PV objects and manages backing directories.<\/td><\/tr><tr><td><code>WaitForFirstConsumer<\/code><\/td><td>Allows the scheduler to choose the Pod&#8217;s node before local volume creation.<\/td><\/tr><tr><td><code>ReadWriteOnce<\/code>&nbsp;(RWO)<\/td><td>Supported access mode for OpenEBS Local PV HostPath; not a shared RWX network filesystem.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">2.3 Critical distinction: HostPath-backed does not mean&nbsp;<code>spec.hostPath<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>OpenEBS Local PV HostPath normally creates a PV with&nbsp;<code>spec.local.path<\/code>, not&nbsp;<code>spec.hostPath.path<\/code>.<\/strong>&nbsp;Its data still lives in a host filesystem directory. This is intentional: the&nbsp;<code>local<\/code>&nbsp;PV API includes node affinity, making scheduling more reliable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To inspect a provisioned PV, query&nbsp;<strong><code>.spec.local.path<\/code><\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">kubectl get pv <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">YOUR_PV_NAME<\/span>&gt;<\/span> -o jsonpath='{.spec.local.path}{\"\\n\"}'\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Do not use&nbsp;<code>kubectl get pv ... -o jsonpath='{.spec.hostPath.path}'<\/code>&nbsp;for this OpenEBS engine; it will usually be empty.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3. OpenEBS vs Rancher vs Kubernetes no-provisioner<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">StorageClass provisioner<\/th><th class=\"has-text-align-left\" data-align=\"left\">Dynamic PV creation?<\/th><th class=\"has-text-align-left\" data-align=\"left\">Host-local directory backing?<\/th><th class=\"has-text-align-left\" data-align=\"left\">Separate controller installation?<\/th><\/tr><\/thead><tbody><tr><td><code>kubernetes.io\/no-provisioner<\/code><\/td><td><strong>No<\/strong><\/td><td>Yes, with manually created local PVs<\/td><td>No<\/td><\/tr><tr><td><code>rancher.io\/local-path<\/code><\/td><td><strong>Yes<\/strong><\/td><td>Yes<\/td><td>Yes: Rancher Local Path Provisioner<\/td><\/tr><tr><td><code>openebs.io\/local<\/code><\/td><td><strong>Yes<\/strong><\/td><td>Yes<\/td><td>Yes: OpenEBS Local PV HostPath<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Why your old StorageClass stayed Pending:<\/strong><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTTP\" data-shcb-language-slug=\"http\"><span><code class=\"hljs language-http\"><span class=\"hljs-attribute\">provisioner<\/span>: kubernetes.io\/no-provisioner\n<span class=\"hljs-attribute\">volumeBindingMode<\/span>: WaitForFirstConsumer\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTTP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">http<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This supports&nbsp;<em>static<\/em>&nbsp;provisioning only. A matching PV must already exist. OpenEBS changes that: the controller creates PVs for qualifying PVC requests.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Merely changing a StorageClass&#8217;s&nbsp;<code>provisioner<\/code>&nbsp;to&nbsp;<code>openebs.io\/local<\/code>&nbsp;without installing the OpenEBS controller&nbsp;<strong>will not work<\/strong>.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4. Prerequisites and safety checks<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This tutorial assumes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A functioning Kubernetes API server, scheduler, controller manager, networking, kubelet, and container runtime.<\/li>\n\n\n\n<li><code>kubectl<\/code>\u00a0configured to administer the cluster.<\/li>\n\n\n\n<li>At least one\u00a0<strong>Ready and schedulable worker node<\/strong>; control-plane-only nodes may have a\u00a0<code>NoSchedule<\/code>\u00a0taint.<\/li>\n\n\n\n<li>Disk space available on the node filesystem containing\u00a0<code>\/var\/openebs\/local<\/code>\u00a0(at least several GiB for a small lab).<\/li>\n\n\n\n<li>Helm 3 installed (if not, see the next section).<\/li>\n\n\n\n<li>Cluster-wide rights to install CRDs, deployments, RBAC, and StorageClasses.<\/li>\n\n\n\n<li>Outbound access to Helm repositories and container registries from the appropriate client\/nodes, unless using a preconfigured internal mirror.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4.1 Confirm cluster access<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl config current-context\nkubectl version\nkubectl cluster-info\nkubectl <span class=\"hljs-keyword\">get<\/span> nodes -o wide\nkubectl <span class=\"hljs-keyword\">get<\/span> sc\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Review&nbsp;<code>current-context<\/code>&nbsp;carefully before installing.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4.2 Identify node taints<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> nodes -o custom-columns=NAME:.metadata.name,READY:.status.conditions&#91;-1].type,TAINTS:.spec.taints\nkubectl describe nodes | grep -A 3 'Taints:'\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Your earlier output showed two nodes, with&nbsp;<strong>one node rejected because of an untolerated taint<\/strong>. That can be normal for a control-plane node. The remaining worker must be Ready and have adequate resources. You do not need to remove the control-plane taint for this lab.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4.3 Check free disk space&nbsp;<strong>on the worker<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">SSH or access the&nbsp;<em>worker node<\/em>&nbsp;(not just the administrative host):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">df -h \/<span class=\"hljs-keyword\">var<\/span>\nlsblk -f\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">If&nbsp;<code>\/var\/openebs\/local<\/code>&nbsp;does not exist yet, OpenEBS can create it during provisioning. For a dedicated disk, mount that disk at a suitable&nbsp;<code>BasePath<\/code>&nbsp;<strong>before<\/strong>&nbsp;provisioning.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4.4 Protect existing storage<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> pv\nkubectl <span class=\"hljs-keyword\">get<\/span> pvc -A\nkubectl <span class=\"hljs-keyword\">get<\/span> sc\nhelm list -A\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Do&nbsp;<strong>not<\/strong>&nbsp;delete your existing&nbsp;<code>manual<\/code>&nbsp;StorageClass, PVs, PVCs, or Rancher provisioner. This tutorial uses&nbsp;<strong>new resource names<\/strong>&nbsp;to coexist with them.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5. Install Helm if needed<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Check whether Helm is available:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">helm version\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">If Helm is already installed, skip this step.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For Ubuntu, follow the official Helm installation instructions at&nbsp;<a href=\"https:\/\/helm.sh\/docs\/intro\/install\/\">https:\/\/helm.sh\/docs\/intro\/install\/<\/a>. One documented installation method is:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">curl -fsSL https:<span class=\"hljs-comment\">\/\/raw.githubusercontent.com\/helm\/helm\/main\/scripts\/get-helm-3 | bash<\/span>\nhelm version\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Security note:<\/strong>&nbsp;Review the script or use your organization&#8217;s approved package-management process before executing remote scripts.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">6. Install OpenEBS HostPath-only using Helm<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The unified OpenEBS Helm chart installs several engines by default. A small Ubuntu lab needs&nbsp;<strong>only Local PV HostPath<\/strong>, so disable Mayastor, LVM, and ZFS. The commands below also disable optional Loki\/Alloy observability components to conserve resources.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.1 Add the official OpenEBS chart repository<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">helm repo add openebs https:<span class=\"hljs-comment\">\/\/openebs.github.io\/openebs<\/span>\nhelm repo update\nhelm search repo openebs\/openebs --versions | head\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">6.2 Inspect the chart before installation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">As of this tutorial, the checked OpenEBS chart release is&nbsp;<strong>4.6.2<\/strong>. Verify it is present in the repository:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">helm show chart openebs\/openebs --version 4.6.2\nhelm show values openebs\/openebs --version 4.6.2 &gt; openebs-chart-defaults.yaml\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Review&nbsp;<code>openebs-chart-defaults.yaml<\/code>&nbsp;if your environment uses custom policies or registry mirrors.&nbsp;<strong>Pinning the chart version<\/strong>&nbsp;makes the lab more reproducible. If your chart repository exposes a different version, inspect it before adjusting the commands.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.3 Install only Local PV HostPath<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">helm upgrade --install openebs openebs\/openebs \\\n  --namespace openebs \\\n  --create-namespace \\\n  --version <span class=\"hljs-number\">4.6<\/span><span class=\"hljs-number\">.2<\/span> \\\n  --<span class=\"hljs-keyword\">set<\/span> engines.replicated.mayastor.enabled=false \\\n  --<span class=\"hljs-keyword\">set<\/span> engines.local.lvm.enabled=false \\\n  --<span class=\"hljs-keyword\">set<\/span> engines.local.zfs.enabled=false \\\n  --<span class=\"hljs-keyword\">set<\/span> engines.local.rawfile.enabled=false \\\n  --<span class=\"hljs-keyword\">set<\/span> loki.enabled=false \\\n  --<span class=\"hljs-keyword\">set<\/span> alloy.enabled=false\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Why disable the other components?<\/strong>&nbsp;You are testing only local directory provisioning; you do not need distributed replicas, LVM volumes, ZFS pools, or a complete OpenEBS observability stack.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.4 Verify the Helm release and controller<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">helm status openebs -n openebs\nhelm list -n openebs\nkubectl <span class=\"hljs-keyword\">get<\/span> pods -n openebs -o wide\nkubectl <span class=\"hljs-keyword\">get<\/span> deployments -n openebs\nkubectl <span class=\"hljs-keyword\">get<\/span> storageclass\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Look for a deployment with a name similar to&nbsp;<code>openebs-localpv-provisioner<\/code>&nbsp;in the&nbsp;<code>openebs<\/code>&nbsp;namespace. When present, verify its rollout:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">kubectl rollout status deployment\/openebs-localpv-provisioner \\\n  -n openebs --timeout=180s\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The provisioner Pod should become&nbsp;<code>Running<\/code>&nbsp;and Ready. If not, review&nbsp;<a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#16-troubleshooting-common-errors\">troubleshooting<\/a>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">7. Check the default OpenEBS StorageClass<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">OpenEBS ordinarily creates a default-named HostPath StorageClass:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> sc openebs-hostpath\nkubectl describe sc openebs-hostpath\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Expected key properties:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">NAME               PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE\nopenebs-hostpath   openebs.io\/local  Delete          WaitForFirstConsumer\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The usual base directory is&nbsp;<code>\/var\/openebs\/local<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fastest possible test:<\/strong>&nbsp;Set&nbsp;<code>storageClassName: openebs-hostpath<\/code>&nbsp;in your StatefulSet and skip creating your own StorageClass. However, the next step creates a&nbsp;<strong>custom StorageClass<\/strong>, so you can learn exactly how its annotations work.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">8. Create a custom HostPath StorageClass<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Save this file as&nbsp;<strong><code>sc.yaml<\/code><\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">apiVersion: storage.k8s.io\/v1\n<span class=\"hljs-attr\">kind<\/span>: StorageClass\n<span class=\"hljs-attr\">metadata<\/span>:\n  name: openebs-hostpath-lab\n  <span class=\"hljs-attr\">annotations<\/span>:\n    openebs.io\/cas-type: local\n    cas.openebs.io\/config: |\n      - name: StorageType\n        <span class=\"hljs-attr\">value<\/span>: <span class=\"hljs-string\">\"hostpath\"<\/span>\n      - name: BasePath\n        <span class=\"hljs-attr\">value<\/span>: <span class=\"hljs-string\">\"\/var\/openebs\/local\"<\/span>\n<span class=\"hljs-attr\">provisioner<\/span>: openebs.io\/local\n<span class=\"hljs-attr\">reclaimPolicy<\/span>: Delete\n<span class=\"hljs-attr\">volumeBindingMode<\/span>: WaitForFirstConsumer\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Create and inspect it:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl apply -f sc.yaml\nkubectl <span class=\"hljs-keyword\">get<\/span> sc openebs-hostpath-lab\nkubectl describe sc openebs-hostpath-lab\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Understanding the fields<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Field<\/th><th class=\"has-text-align-left\" data-align=\"left\">Purpose<\/th><\/tr><\/thead><tbody><tr><td><code>metadata.name<\/code><\/td><td>Name referenced in the PVC \/ StatefulSet.<\/td><\/tr><tr><td><code>openebs.io\/cas-type: local<\/code><\/td><td>Tells OpenEBS this is a local storage class.<\/td><\/tr><tr><td><code>cas.openebs.io\/config<\/code><\/td><td>OpenEBS-specific configuration, written as an embedded YAML list.<\/td><\/tr><tr><td><code>StorageType: hostpath<\/code><\/td><td>A directory underneath a node&#8217;s filesystem path is the backing storage.<\/td><\/tr><tr><td><code>BasePath<\/code><\/td><td>Parent directory for dynamically created PV directories.<\/td><\/tr><tr><td><code>provisioner: openebs.io\/local<\/code><\/td><td>Asks the installed OpenEBS controller to provision volumes.<\/td><\/tr><tr><td><code>reclaimPolicy: Delete<\/code><\/td><td>When a PVC and PV are removed normally, OpenEBS deletes the backing directory\/data.<\/td><\/tr><tr><td><code>WaitForFirstConsumer<\/code><\/td><td>Defers provision until the scheduler picks a node for a consuming Pod.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Do not change&nbsp;<code>volumeBindingMode<\/code>&nbsp;to&nbsp;<code>Immediate<\/code>.<\/strong>&nbsp;OpenEBS HostPath requires&nbsp;<code>WaitForFirstConsumer<\/code>&nbsp;because provisioning depends on the chosen node.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">9. Create a StatefulSet with automatic PVCs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Save this file as&nbsp;<strong><code>sfs.yaml<\/code><\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">apiVersion: apps\/v1\n<span class=\"hljs-attr\">kind<\/span>: StatefulSet\n<span class=\"hljs-attr\">metadata<\/span>:\n  name: openebs-local-test\n<span class=\"hljs-attr\">spec<\/span>:\n  serviceName: openebs-local-service\n  <span class=\"hljs-attr\">replicas<\/span>: <span class=\"hljs-number\">3<\/span>\n  <span class=\"hljs-attr\">selector<\/span>:\n    matchLabels:\n      app: openebs-local-test\n  <span class=\"hljs-attr\">template<\/span>:\n    metadata:\n      labels:\n        app: openebs-local-test\n    <span class=\"hljs-attr\">spec<\/span>:\n      containers:\n        - name: test-container\n          <span class=\"hljs-attr\">image<\/span>: busybox:<span class=\"hljs-number\">1.36<\/span>\n          <span class=\"hljs-attr\">command<\/span>:\n            - <span class=\"hljs-regexp\">\/bin\/<\/span>sh\n            - -c\n            - sleep <span class=\"hljs-number\">100000<\/span>\n          <span class=\"hljs-attr\">volumeMounts<\/span>:\n            - name: local-vol\n              <span class=\"hljs-attr\">mountPath<\/span>: <span class=\"hljs-regexp\">\/usr\/<\/span>test-pod\n  <span class=\"hljs-attr\">volumeClaimTemplates<\/span>:\n    - metadata:\n        name: local-vol\n        <span class=\"hljs-attr\">labels<\/span>:\n          app: openebs-local-test\n      <span class=\"hljs-attr\">spec<\/span>:\n        accessModes:\n          - ReadWriteOnce\n        <span class=\"hljs-attr\">storageClassName<\/span>: openebs-hostpath-lab\n        <span class=\"hljs-attr\">resources<\/span>:\n          requests:\n            storage: <span class=\"hljs-number\">1<\/span>Gi\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">What it creates<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Kubernetes creates the PVCs from&nbsp;<code>volumeClaimTemplates<\/code>, and OpenEBS creates matching PVs on demand:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">StatefulSet Pod<\/th><th class=\"has-text-align-left\" data-align=\"left\">Generated PVC<\/th><th class=\"has-text-align-left\" data-align=\"left\">Provisioned PV<\/th><\/tr><\/thead><tbody><tr><td><code>openebs-local-test-0<\/code><\/td><td><code>local-vol-openebs-local-test-0<\/code><\/td><td>New PV created by OpenEBS<\/td><\/tr><tr><td><code>openebs-local-test-1<\/code><\/td><td><code>local-vol-openebs-local-test-1<\/code><\/td><td>New PV created by OpenEBS<\/td><\/tr><tr><td><code>openebs-local-test-2<\/code><\/td><td><code>local-vol-openebs-local-test-2<\/code><\/td><td>New PV created by OpenEBS<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Each claims&nbsp;<strong>1Gi<\/strong>, for&nbsp;<strong>3Gi requested<\/strong>&nbsp;in total, not necessarily 3Gi actually consumed. Each has its&nbsp;<strong>own directory<\/strong>, and no handwritten PV or PVC manifest is required.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why only Pod&nbsp;<code>-0<\/code>&nbsp;may appear at first<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">StatefulSets default to&nbsp;<code>OrderedReady<\/code>. Kubernetes waits for&nbsp;<code>openebs-local-test-0<\/code>&nbsp;to become Ready before proceeding to&nbsp;<code>-1<\/code>&nbsp;and&nbsp;<code>-2<\/code>. That behavior is expected.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">About the&nbsp;<code>serviceName<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>openebs-local-service<\/code>&nbsp;refers to the recommended&nbsp;<strong>headless Service<\/strong>&nbsp;for stable network identity. The storage lab can demonstrate volume creation without this Service, but create it if you need stable per-Pod DNS; see&nbsp;<a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/OpenEBS_HostPath_Dynamic_Provisioning_Complete_Tutorial.md#14-optional-headless-service-for-stable-dns\">section 14<\/a>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">10. Apply resources and verify dynamic provisioning<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">10.1 Apply both manifests<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">kubectl<\/span> <span class=\"hljs-selector-tag\">apply<\/span> <span class=\"hljs-selector-tag\">-f<\/span> <span class=\"hljs-selector-tag\">sc<\/span><span class=\"hljs-selector-class\">.yaml<\/span>\n<span class=\"hljs-selector-tag\">kubectl<\/span> <span class=\"hljs-selector-tag\">apply<\/span> <span class=\"hljs-selector-tag\">-f<\/span> <span class=\"hljs-selector-tag\">sfs<\/span><span class=\"hljs-selector-class\">.yaml<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">10.2 Watch rollout and PVC\/PV binding<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> pods -l app=openebs-local-test -w\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In another terminal:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> pvc -l app=openebs-local-test\nkubectl <span class=\"hljs-keyword\">get<\/span> pv\nkubectl <span class=\"hljs-keyword\">get<\/span> sc\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Once everything is ready, expect something like:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">NAME                   READY   STATUS    RESTARTS\nopenebs-local-test-0   1\/1     Running   0\nopenebs-local-test-1   1\/1     Running   0\nopenebs-local-test-2   1\/1     Running   0\n<\/code><\/span><\/pre>\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">NAME                             STATUS   CAPACITY   ACCESS MODES   STORAGECLASS\nlocal-vol-openebs-local-test-0    Bound    1Gi        RWO            openebs-hostpath-lab\nlocal-vol-openebs-local-test-1    Bound    1Gi        RWO            openebs-hostpath-lab\nlocal-vol-openebs-local-test-2    Bound    1Gi        RWO            openebs-hostpath-lab\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The PV names are automatically assigned, usually beginning with&nbsp;<code>pvc-<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">10.3 Inspect one PVC<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">kubectl describe pvc local-vol-openebs-local-test-0\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Expected attributes include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>Status: Bound<\/code><\/li>\n\n\n\n<li><code>StorageClass: openebs-hostpath-lab<\/code><\/li>\n\n\n\n<li><code>Capacity: 1Gi<\/code><\/li>\n\n\n\n<li><code>Access Modes: RWO<\/code><\/li>\n\n\n\n<li>A corresponding volume name (<code>pvc-...<\/code>)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">10.4 Check which nodes run your Pods<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> pods -l app=openebs-local-test -o wide\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">On your&nbsp;<strong>two-node cluster<\/strong>, there may be only one schedulable worker. In that case all three Pods can be placed on the same worker if sufficient resources are available.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">11. Find the real data directory on the worker node<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is the most important verification that your dynamically provisioned volume is&nbsp;<strong>host-local<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">11.1 Read the PV name bound to the first PVC<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">PV0=$(kubectl get pvc local-vol-openebs-local-test<span class=\"hljs-number\">-0<\/span> \\\n  -o jsonpath=<span class=\"hljs-string\">'{.spec.volumeName}'<\/span>)\n<span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"$PV0\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">11.2 Inspect its local path and node affinity<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">kubectl get pv <span class=\"hljs-string\">\"$PV0\"<\/span> -o yaml\nkubectl get pv <span class=\"hljs-string\">\"$PV0\"<\/span> -o jsonpath=<span class=\"hljs-string\">'{.spec.local.path}{\"\\n\"}'<\/span>\nkubectl get pv <span class=\"hljs-string\">\"$PV0\"<\/span> -o jsonpath=<span class=\"hljs-string\">'{.spec.nodeAffinity.required.nodeSelectorTerms&#91;0].matchExpressions&#91;0].values&#91;0]}{\"\\n\"}'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Expected conceptual PV fragment:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">spec:\n  storageClassName: openebs-hostpath-lab\n  <span class=\"hljs-attr\">capacity<\/span>:\n    storage: <span class=\"hljs-number\">1<\/span>Gi\n  <span class=\"hljs-attr\">local<\/span>:\n    path: <span class=\"hljs-regexp\">\/var\/<\/span>openebs\/local\/pvc-example-id\n  <span class=\"hljs-attr\">nodeAffinity<\/span>:\n    required:\n      nodeSelectorTerms:\n        - matchExpressions:\n            - key: kubernetes.io\/hostname\n              <span class=\"hljs-attr\">operator<\/span>: In\n              <span class=\"hljs-attr\">values<\/span>:\n                - your-worker-node\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><code>spec.local.path<\/code>&nbsp;is the filesystem directory.&nbsp;<code>nodeAffinity<\/code>&nbsp;pins that PV to the node with the data.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">11.3 Verify on the correct worker<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Find which node runs the Pod:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> pod openebs-local-test-0 -o wide\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Connect to that node (SSH, SSM, console, etc.) and run:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">sudo ls -lah \/<span class=\"hljs-keyword\">var<\/span>\/openebs\/local\/\ndf -h \/<span class=\"hljs-keyword\">var<\/span>\/openebs\/local\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Do not manually delete or move the PV directory while its volume is in use.<\/strong>&nbsp;The PV path may not exist on the control-plane node or on other workers.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">12. Test persistence after Pod recreation<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">12.1 Write a file inside the mounted PVC<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl exec openebs-local-test<span class=\"hljs-number\">-0<\/span> -- sh -c \\\n  <span class=\"hljs-string\">'echo \"Hello from OpenEBS HostPath\" &gt; \/usr\/test-pod\/hello.txt'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">12.2 Read the file<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">kubectl exec openebs-local-test-0 -- cat \/usr\/test-pod\/hello.txt\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">Hello <span class=\"hljs-keyword\">from<\/span> OpenEBS HostPath\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">12.3 Delete only the Pod (not the PVC)<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">delete<\/span> pod openebs-local-test<span class=\"hljs-number\">-0<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The StatefulSet controller recreates it. Check readiness:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl rollout status statefulset\/openebs-local-test --timeout=<span class=\"hljs-number\">180<\/span>s\nkubectl <span class=\"hljs-keyword\">get<\/span> pods -l app=openebs-local-test -o wide\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">12.4 Read the original file after restart<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">kubectl exec openebs-local-test-0 -- cat \/usr\/test-pod\/hello.txt\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">Hello <span class=\"hljs-keyword\">from<\/span> OpenEBS HostPath\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>What this proves:<\/strong>&nbsp;the file survives Pod replacement because the PVC remains bound to the existing PV. Kubernetes schedules the replacement to the node containing the local volume. It does&nbsp;<strong>not<\/strong>&nbsp;prove recovery from node\/disk loss.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">13. Test storage isolation across replicas<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Each Pod receives its own PVC; writing to one volume must not write to the others.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">13.1 Write a unique value in each Pod<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-29\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">for<\/span> i <span class=\"hljs-keyword\">in<\/span> <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">1<\/span> <span class=\"hljs-number\">2<\/span>; <span class=\"hljs-keyword\">do<\/span>\n  kubectl exec <span class=\"hljs-string\">\"openebs-local-test-$i\"<\/span> -- sh -c \\\n    <span class=\"hljs-string\">\"echo data-from-pod-$i &gt; \/usr\/test-pod\/identity.txt\"<\/span>\ndone\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-29\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">13.2 Read from each Pod<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-30\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">for<\/span> i in <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">1<\/span> <span class=\"hljs-number\">2<\/span>; <span class=\"hljs-keyword\">do<\/span>\n  <span class=\"hljs-keyword\">echo<\/span> <span class=\"hljs-string\">\"Pod $i:\"<\/span>\n  kubectl exec <span class=\"hljs-string\">\"openebs-local-test-$i\"<\/span> -- \\\n    cat \/usr\/test-pod\/identity.txt\ndone\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-30\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">Pod <span class=\"hljs-number\">0<\/span>:\ndata-<span class=\"hljs-keyword\">from<\/span>-pod<span class=\"hljs-number\">-0<\/span>\nPod <span class=\"hljs-number\">1<\/span>:\ndata-<span class=\"hljs-keyword\">from<\/span>-pod<span class=\"hljs-number\">-1<\/span>\nPod <span class=\"hljs-number\">2<\/span>:\ndata-<span class=\"hljs-keyword\">from<\/span>-pod<span class=\"hljs-number\">-2<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-31\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This demonstrates one claim and one separate storage directory per replica.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">14. Optional: Headless Service for stable DNS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The lab&#8217;s storage creation does not depend on a Service. However, a StatefulSet normally uses a&nbsp;<strong>headless Service<\/strong>&nbsp;to provide stable Pod network identities.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want full StatefulSet DNS behavior, create&nbsp;<strong><code>service.yaml<\/code><\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">apiVersion: v1\nkind: Service\nmetadata:\n  name: openebs-local-service\nspec:\n  clusterIP: None\n  selector:\n    app: openebs-local-test\n  ports:\n    - name: http\n      port: 80\n      targetPort: 80\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Apply:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-32\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl apply -f service.yaml\nkubectl <span class=\"hljs-keyword\">get<\/span> svc openebs-local-service\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-32\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This sample Service&#8217;s port is for&nbsp;<strong>DNS\/identity demonstration only<\/strong>. The BusyBox container does not listen on port 80; no HTTP request will succeed until you run a server. If your only aim is testing storage and you insist on just two manifest types,&nbsp;<strong>skip this optional Service<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">15. Advanced configuration<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">15.1 Change the host storage directory<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For a dedicated mounted data disk, change the&nbsp;<code>BasePath<\/code>&nbsp;in a&nbsp;<strong>new<\/strong>&nbsp;StorageClass:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-33\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">apiVersion: storage.k8s.io\/v1\n<span class=\"hljs-attr\">kind<\/span>: StorageClass\n<span class=\"hljs-attr\">metadata<\/span>:\n  name: openebs-hostpath-data-disk\n  <span class=\"hljs-attr\">annotations<\/span>:\n    openebs.io\/cas-type: local\n    cas.openebs.io\/config: |\n      - name: StorageType\n        <span class=\"hljs-attr\">value<\/span>: <span class=\"hljs-string\">\"hostpath\"<\/span>\n      - name: BasePath\n        <span class=\"hljs-attr\">value<\/span>: <span class=\"hljs-string\">\"\/mnt\/openebs-data\"<\/span>\n<span class=\"hljs-attr\">provisioner<\/span>: openebs.io\/local\n<span class=\"hljs-attr\">reclaimPolicy<\/span>: Delete\n<span class=\"hljs-attr\">volumeBindingMode<\/span>: WaitForFirstConsumer\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-33\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Make sure&nbsp;<code>\/mnt\/openebs-data<\/code>&nbsp;is a real mounted filesystem on any node eligible for these workloads. Provisioning to an unmounted directory can unexpectedly fill the OS disk.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.2 Restrict provisioning to specified nodes<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use&nbsp;<code>allowedTopologies<\/code>&nbsp;in the StorageClass to permit only particular worker hostnames:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">allowedTopologies:\n  - matchLabelExpressions:\n      - key: kubernetes.io\/hostname\n        values:\n          - YOUR-WORKER-NODE-NAME\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Insert this at the StorageClass top level alongside&nbsp;<code>volumeBindingMode<\/code>; replace the hostname. This influences both provisioning and scheduling. Avoid hard-coding Pod&nbsp;<code>nodeName<\/code>&nbsp;when using&nbsp;<code>WaitForFirstConsumer<\/code>, because bypassing the scheduler can leave the claim Pending.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.3 Set directory permissions<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">OpenEBS HostPath&#8217;s default newly created directory mode is usually&nbsp;<strong>0777<\/strong>. For tighter access, add a&nbsp;<code>FilePermissions<\/code>&nbsp;entry to the&nbsp;<code>cas.openebs.io\/config<\/code>&nbsp;annotation:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"> <code>     - name: FilePermissions\n        data:\n          mode: \"0770\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For example, a full custom StorageClass with permissions:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-34\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">apiVersion: storage.k8s.io\/v1\n<span class=\"hljs-attr\">kind<\/span>: StorageClass\n<span class=\"hljs-attr\">metadata<\/span>:\n  name: openebs-hostpath-restricted\n  <span class=\"hljs-attr\">annotations<\/span>:\n    openebs.io\/cas-type: local\n    cas.openebs.io\/config: |\n      - name: StorageType\n        <span class=\"hljs-attr\">value<\/span>: <span class=\"hljs-string\">\"hostpath\"<\/span>\n      - name: BasePath\n        <span class=\"hljs-attr\">value<\/span>: <span class=\"hljs-string\">\"\/var\/openebs\/restricted\"<\/span>\n      - name: FilePermissions\n        <span class=\"hljs-attr\">data<\/span>:\n          mode: <span class=\"hljs-string\">\"0770\"<\/span>\n<span class=\"hljs-attr\">provisioner<\/span>: openebs.io\/local\n<span class=\"hljs-attr\">reclaimPolicy<\/span>: Delete\n<span class=\"hljs-attr\">volumeBindingMode<\/span>: WaitForFirstConsumer\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-34\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Confirm your application UID\/GID can access the volume before tightening permissions. These settings affect new directories, not existing ones.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.4 Set&nbsp;<code>Retain<\/code>&nbsp;instead of&nbsp;<code>Delete<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-35\" data-shcb-language-name=\"HTTP\" data-shcb-language-slug=\"http\"><span><code class=\"hljs language-http\"><span class=\"hljs-attribute\">reclaimPolicy<\/span>: Retain\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-35\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTTP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">http<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">With&nbsp;<code>Retain<\/code>, Kubernetes does not automatically remove the volume&#8217;s data when its PVC is deleted. This protects against automatic cleanup but also requires&nbsp;<strong>manual recovery and management<\/strong>&nbsp;of the retained volume.&nbsp;<code>Retain<\/code>&nbsp;is not a backup strategy.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">15.5 Optional quotas (advanced, not needed for the lab)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">By default,&nbsp;<code>storage: 1Gi<\/code>&nbsp;is&nbsp;<strong>not a filesystem quota<\/strong>. OpenEBS 4.6 documents optional&nbsp;<code>XFSQuota<\/code>&nbsp;and&nbsp;<code>EXT4Quota<\/code>, but these require correct filesystem features and project quota mount configuration. Do&nbsp;<strong>not<\/strong>&nbsp;copy quota settings into the beginner lab without configuring the node filesystem first.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Official guides:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/openebs.io\/docs\/main\/user-guides\/local-storage-user-guide\/local-pv-hostpath\/configuration\/hostpath-storageclass-parameters\">https:\/\/openebs.io\/docs\/main\/user-guides\/local-storage-user-guide\/local-pv-hostpath\/configuration\/hostpath-storageclass-parameters<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/openebs.io\/docs\/main\/user-guides\/local-storage-user-guide\/local-pv-hostpath\/advanced-operations\/ext4-quota\/enable-ext4-quota\">https:\/\/openebs.io\/docs\/main\/user-guides\/local-storage-user-guide\/local-pv-hostpath\/advanced-operations\/ext4-quota\/enable-ext4-quota<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">15.6 Install from a consolidated Helm values file (optional)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For repeatable configuration, create&nbsp;<strong><code>openebs-values.yaml<\/code><\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-36\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">engines:\n  local:\n    lvm:\n      enabled: <span class=\"hljs-literal\">false<\/span>\n    <span class=\"hljs-attr\">zfs<\/span>:\n      enabled: <span class=\"hljs-literal\">false<\/span>\n    <span class=\"hljs-attr\">rawfile<\/span>:\n      enabled: <span class=\"hljs-literal\">false<\/span>\n  <span class=\"hljs-attr\">replicated<\/span>:\n    mayastor:\n      enabled: <span class=\"hljs-literal\">false<\/span>\n<span class=\"hljs-attr\">loki<\/span>:\n  enabled: <span class=\"hljs-literal\">false<\/span>\n<span class=\"hljs-attr\">alloy<\/span>:\n  enabled: <span class=\"hljs-literal\">false<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-36\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Then use this&nbsp;<strong>instead of<\/strong>&nbsp;the&nbsp;<code>--set<\/code>&nbsp;form in step 6:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">helm upgrade --install openebs openebs\/openebs \\\n  -n openebs --create-namespace \\\n  --version 4.6.2 \\\n  -f openebs-values.yaml\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Validate chart keys with&nbsp;<code>helm show values<\/code>&nbsp;before applying future chart releases.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">16. Troubleshooting common errors<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">16.1 PVC stuck in&nbsp;<code>Pending<\/code>:&nbsp;<code>WaitForFirstConsumer<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-37\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl describe pvc local-vol-openebs-local-test<span class=\"hljs-number\">-0<\/span>\nkubectl describe pod openebs-local-test<span class=\"hljs-number\">-0<\/span>\nkubectl <span class=\"hljs-keyword\">get<\/span> pods -n openebs\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-37\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">A claim can show&nbsp;<code>WaitForFirstConsumer<\/code>&nbsp;briefly. It is not automatically a failure. Look for the&nbsp;<em>scheduler&#8217;s<\/em>&nbsp;error event and ensure a Pod consumes the PVC.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the Pod shows&nbsp;<code>FailedScheduling<\/code>, continue below.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.2&nbsp;<code>0\/2 nodes are available ... untolerated taint(s)<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Your earlier cluster logs had this pattern. Check:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-38\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> nodes -o wide\nkubectl <span class=\"hljs-keyword\">get<\/span> nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints\nkubectl describe pod openebs-local-test-0\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-38\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">A control-plane taint is normal. Make sure at least one Ready worker is available.&nbsp;<strong>Do not remove a control-plane taint simply to get this lab running<\/strong>&nbsp;unless it is an intentionally single-node training cluster and you understand the implications.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.3 PVC Pending because provisioner is missing or broken<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-39\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> pods -n openebs -o wide\nkubectl <span class=\"hljs-keyword\">get<\/span> deployments -n openebs\nkubectl logs -n openebs deployment\/openebs-localpv-provisioner --tail=150\nkubectl describe pvc local-vol-openebs-local-test-0\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-39\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Check for image pull issues, CRD\/RBAC failures, unhealthy controller Pods, or incorrect StorageClass&nbsp;<code>provisioner<\/code>&nbsp;values.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.4 Wrong StorageClass<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-40\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> sc\nkubectl <span class=\"hljs-keyword\">get<\/span> pvc local-vol-openebs-local-test-0 -o yaml\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-40\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">For this tutorial the claim&#8217;s&nbsp;<code>storageClassName<\/code>&nbsp;must be&nbsp;<code>openebs-hostpath-lab<\/code>&nbsp;and that StorageClass&#8217;s provisioner must be&nbsp;<code>openebs.io\/local<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the claim still requests your old&nbsp;<code>local-storage<\/code>&nbsp;(<code>kubernetes.io\/no-provisioner<\/code>) class, you are running the old manifest or an old StatefulSet\/PVC. For a disposable lab, recreate those resources after confirming there is no data to preserve. Do&nbsp;<strong>not<\/strong>&nbsp;delete persistent claims containing valuable data.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.5&nbsp;<code>Immediate<\/code>&nbsp;mode prevents local provisioning<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">OpenEBS HostPath needs:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-41\" data-shcb-language-name=\"HTTP\" data-shcb-language-slug=\"http\"><span><code class=\"hljs language-http\"><span class=\"hljs-attribute\">volumeBindingMode<\/span>: WaitForFirstConsumer\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-41\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTTP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">http<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">If you created a StorageClass with&nbsp;<code>Immediate<\/code>, create a corrected one with a&nbsp;<strong>new name<\/strong>&nbsp;and update a newly created application\/PVC to use it. StorageClass binding\/provisioner behavior cannot be reliably changed in place.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.6 Using&nbsp;<code>nodeName<\/code>&nbsp;with&nbsp;<code>WaitForFirstConsumer<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Do&nbsp;<strong>not<\/strong>&nbsp;set:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">spec:\n  template:\n    spec:\n      nodeName: some-worker\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This bypasses normal scheduler selection and can prevent local provisioning. Use a&nbsp;<code>nodeSelector<\/code>, node affinity, or the StorageClass&#8217;s&nbsp;<code>allowedTopologies<\/code>&nbsp;if placement restrictions are needed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.7 Permission denied in the mounted path<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-42\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl exec openebs-local-test<span class=\"hljs-number\">-0<\/span> -- sh -c \\\n  <span class=\"hljs-string\">'id; ls -ld \/usr\/test-pod; touch \/usr\/test-pod\/write-test'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-42\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Check the volume directory mode and the container&#8217;s UID\/GID. With a non-root workload, set appropriate file permissions \/&nbsp;<code>fsGroup<\/code>&nbsp;where supported, rather than blindly making all directories world-writable.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.8 Pod stays Pending after PV is Bound<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-43\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl describe pod openebs-local-test<span class=\"hljs-number\">-0<\/span>\nkubectl <span class=\"hljs-keyword\">get<\/span> pv \"$PV0\" -o yaml\nkubectl <span class=\"hljs-keyword\">get<\/span> nodes -o wide\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-43\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">A local PV has&nbsp;<code>nodeAffinity<\/code>. The Pod must be able to run on that specific node. Node unavailability, taints, or conflicting node selectors can block it. Data does not automatically move to another node.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.9 Pod&nbsp;<code>ImagePullBackOff<\/code><\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-44\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl describe pod openebs-local-test<span class=\"hljs-number\">-0<\/span>\nkubectl <span class=\"hljs-keyword\">get<\/span> events --sort-by=.lastTimestamp | tail -30\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-44\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The test image is&nbsp;<code>busybox:1.36<\/code>, not the retired&nbsp;<code>k8s.gcr.io\/busybox<\/code>&nbsp;reference. Verify node egress to the image registry or use an approved mirror.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.10 Disk-full or capacity concerns<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">On the actual worker:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-45\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">df -h \/<span class=\"hljs-keyword\">var<\/span>\/openebs\/local\nsudo du -sh \/<span class=\"hljs-keyword\">var<\/span>\/openebs\/local<span class=\"hljs-comment\">\/* 2&gt;\/dev\/null\n<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-45\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">OpenEBS HostPath is directory-backed. Without project quotas, applications can use&nbsp;<strong>more than the PVC request<\/strong>&nbsp;and may fill the node&#8217;s filesystem. Plan free space and disk-pressure alerts.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">16.11 Directory exists but data appears missing<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Check Pod-to-node placement, the PV&#8217;s&nbsp;<code>spec.local.path<\/code>, and the mount inside the Pod. Do not assume all cluster nodes have identical data at&nbsp;<code>\/var\/openebs\/local<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-46\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">kubectl get pod openebs-local-test<span class=\"hljs-number\">-0<\/span> -o wide\nkubectl get pvc local-vol-openebs-local-test<span class=\"hljs-number\">-0<\/span>\nkubectl get pv <span class=\"hljs-string\">\"$PV0\"<\/span> -o jsonpath=<span class=\"hljs-string\">'{.spec.local.path}{\"\\n\"}'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-46\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">16.12 Common issue checklist<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-47\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> nodes -o wide\nkubectl <span class=\"hljs-keyword\">get<\/span> sc\nkubectl <span class=\"hljs-keyword\">get<\/span> pods -n openebs -o wide\nkubectl <span class=\"hljs-keyword\">get<\/span> sts,pods,pvc -l app=openebs-local-test\nkubectl <span class=\"hljs-keyword\">get<\/span> pvc local-vol-openebs-local-test-0 -o yaml\nkubectl describe pod openebs-local-test-0\nkubectl <span class=\"hljs-keyword\">get<\/span> events -A --sort-by=.lastTimestamp | tail -40\nhelm status openebs -n openebs\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-47\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">17. Storage lifecycle, retention, and cleanup<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">17.1 Understand what gets deleted<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Deleting a StatefulSet&nbsp;<strong>does not normally delete its PVCs<\/strong>. The PVCs may remain to preserve data. Deleting a PVC backed by a PV with&nbsp;<code>reclaimPolicy: Delete<\/code>&nbsp;generally triggers deletion of that PV and its backing directory. The exact cleanup depends on the controller operating correctly and access to the node where the directory resides.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>WARNING \u2014 destructive:<\/strong>&nbsp;The cleanup commands below intentionally remove the test PVCs and their stored data. Only run them on disposable lab resources and after backing up anything important.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">17.2 Remove the application first<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-48\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">delete<\/span> statefulset openebs-local-test\nkubectl <span class=\"hljs-keyword\">get<\/span> pvc -l app=openebs-local-test\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-48\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">17.3 Remove only this lab&#8217;s claims<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-49\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">delete<\/span> pvc \\\n  local-vol-openebs-local-test<span class=\"hljs-number\">-0<\/span> \\\n  local-vol-openebs-local-test<span class=\"hljs-number\">-1<\/span> \\\n  local-vol-openebs-local-test<span class=\"hljs-number\">-2<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-49\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Confirm the corresponding PVs are gone:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-50\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> pv\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-50\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Do not delete unrelated manually provisioned PVs such as your earlier&nbsp;<code>hostpath<\/code>,&nbsp;<code>hostpath2<\/code>, or&nbsp;<code>deehostpath<\/code>&nbsp;volumes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">17.4 Delete the custom StorageClass<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-51\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">delete<\/span> storageclass openebs-hostpath-lab\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-51\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">If you created the optional headless Service:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-52\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">delete<\/span> service openebs-local-service\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-52\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">17.5 Optionally uninstall OpenEBS (ONLY if no workloads use it)<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">helm uninstall openebs -n openebs\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Before uninstalling, check whether any PVCs\/PVs across the cluster still use&nbsp;<code>openebs.io\/local<\/code>.&nbsp;<strong>Do not uninstall a provisioner while important PVs rely on it<\/strong>, because reclaim and operational actions can fail afterward.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-53\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">kubectl <span class=\"hljs-keyword\">get<\/span> sc\nkubectl <span class=\"hljs-keyword\">get<\/span> pv -o custom-columns=NAME:.metadata.name,SC:.spec.storageClassName,STATUS:.status.phase\nkubectl <span class=\"hljs-keyword\">get<\/span> pvc -A\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-53\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Namespace deletion and CRD removal may affect other OpenEBS workloads and should&nbsp;<strong>not<\/strong>&nbsp;be treated as routine lab cleanup.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">18. Operational considerations and limitations<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th class=\"has-text-align-left\" data-align=\"left\">Concern<\/th><th class=\"has-text-align-left\" data-align=\"left\">OpenEBS Local PV HostPath behavior<\/th><\/tr><\/thead><tbody><tr><td>Dynamic PV\/PVC provisioning<\/td><td>Yes.<\/td><\/tr><tr><td>Cloud provider needed<\/td><td>No.<\/td><\/tr><tr><td>Dedicated raw block device needed<\/td><td>No; directory on an existing mounted filesystem is sufficient.<\/td><\/tr><tr><td>Data available from all nodes<\/td><td>No, data lives on one node.<\/td><\/tr><tr><td>Transparent node-failure recovery<\/td><td><strong>No.<\/strong>&nbsp;A failed\/lost node means the local volume is inaccessible.<\/td><\/tr><tr><td>Replication<\/td><td>No.<\/td><\/tr><tr><td>Access mode<\/td><td><code>ReadWriteOnce<\/code>; not a shared&nbsp;<code>ReadWriteMany<\/code>&nbsp;filesystem.<\/td><\/tr><tr><td>Scheduling<\/td><td>Uses&nbsp;<code>WaitForFirstConsumer<\/code>&nbsp;and local PV node affinity.<\/td><\/tr><tr><td>Hard 1Gi quota by default<\/td><td><strong>No.<\/strong>&nbsp;Optional project quotas require explicit filesystem configuration.<\/td><\/tr><tr><td>Backups<\/td><td>Your responsibility (e.g. application-aware backups or compatible backup tooling).<\/td><\/tr><tr><td>Common use cases<\/td><td>Learning, CI labs, caches, disposable development databases, single-node\/local workloads.<\/td><\/tr><tr><td>Production suitability<\/td><td>Only if you explicitly accept node-local failure characteristics and implement backups and monitoring.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Security:<\/strong>&nbsp;directory-backed node volumes should be considered powerful local storage access. Restrict who may create StorageClasses, Pods with host mounts, and privileged workloads. Avoid storing sensitive data without appropriate host filesystem permissions and backup controls.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">18.1 When not to use OpenEBS Local PV HostPath<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For a multi-node database requiring automatic failover with replicated storage, use a storage system designed for replication, such as Longhorn or OpenEBS Mayastor (subject to prerequisites), rather than expecting local hostpath volumes to follow Pods between nodes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">18.2&nbsp;<code>1Gi<\/code>&nbsp;is a request, not a reservation guarantee<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The requested capacity shows in Kubernetes API objects, but the backing filesystem is shared with other directories. Monitor&nbsp;<strong>node free space<\/strong>; do not infer that three&nbsp;<code>1Gi<\/code>&nbsp;PVCs are physically isolated 1Gi partitions.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">19. Frequently asked questions<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q1. Can&nbsp;<code>kubernetes.io\/no-provisioner<\/code>&nbsp;dynamically create local PVs?<\/strong><br>No. It explicitly means no dynamic provisioner. Use OpenEBS or another installed dynamic provisioner.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q2. Do I need to create PersistentVolumes manually?<\/strong><br>No. Once OpenEBS is running and a suitable PVC is requested, it creates the PV dynamically.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q3. Do I need a standalone PVC YAML?<\/strong><br>No, because&nbsp;<code>volumeClaimTemplates<\/code>&nbsp;in the StatefulSet automatically creates one PVC per Pod replica.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q4. Can I use only StorageClass + StatefulSet YAML?<\/strong><br>Yes&nbsp;<strong>for the application storage demonstration<\/strong>. OpenEBS itself must already be installed, and the optional headless Service is for StatefulSet DNS, not for volume provisioning.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q5. Does&nbsp;<code>openebs.io\/local<\/code>&nbsp;mean Kubernetes PV&nbsp;<code>spec.hostPath<\/code>?<\/strong><br>No. OpenEBS HostPath normally uses&nbsp;<code>spec.local.path<\/code>&nbsp;with node affinity; the actual data is stored in a host filesystem directory.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q6. What happens if I delete a Pod?<\/strong><br>The StatefulSet recreates it and reuses the existing PVC\/PV. Data should persist if the same underlying node\/disk remains available.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q7. What happens if the worker node disappears permanently?<\/strong><br>The volume is not automatically replicated or migrated. Recovery depends on restoring that node\/disk or recovering from backups.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q8. Can three replicas share the same PVC?<\/strong><br>Not in this design.&nbsp;<code>volumeClaimTemplates<\/code>&nbsp;gives each replica its own PVC, which is the right model for independent local storage.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q9. Can I use my old&nbsp;<code>local-storage<\/code>&nbsp;StorageClass name?<\/strong><br>Only after planning migration\/removal of the existing StorageClass with&nbsp;<code>kubernetes.io\/no-provisioner<\/code>&nbsp;and any dependent resources. The&nbsp;<code>provisioner<\/code>&nbsp;field is immutable. This tutorial uses&nbsp;<code>openebs-hostpath-lab<\/code>&nbsp;so you do&nbsp;<strong>not<\/strong>&nbsp;disturb existing workloads.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q10. Is&nbsp;<code>1Gi<\/code>&nbsp;strictly enforced?<\/strong><br>Not by default. OpenEBS documents optional filesystem project quotas for supported XFS\/ext4 setups.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q11. Do I need to untaint the control plane?<\/strong><br>Usually no. An ordinary worker node is sufficient for the example.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Q12. Does the default&nbsp;<code>openebs-hostpath<\/code>&nbsp;StorageClass already work?<\/strong><br>Yes, after a successful OpenEBS HostPath installation. Your custom class is useful for learning and customizing the base path.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">20. Command cheat sheet<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-54\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span># PRECHECK<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nkubectl config current-context\nkubectl get nodes -o wide\nkubectl get sc\nkubectl get pvc -A\nhelm version\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span># HELM REPOSITORY<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nhelm repo add openebs https:\/\/openebs.github.io\/openebs\nhelm repo update\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span># HOSTPATH-ONLY INSTALL<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nhelm upgrade --install openebs openebs\/openebs \\\n  -n openebs --create-namespace --version 4.6.2 \\\n  --set engines.replicated.mayastor.enabled=false \\\n  --set engines.local.lvm.enabled=false \\\n  --set engines.local.zfs.enabled=false \\\n  --set engines.local.rawfile.enabled=false \\\n  --set loki.enabled=false \\\n  --set alloy.enabled=false\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span># VERIFY PROVISIONER<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nhelm status openebs -n openebs\nkubectl get pods -n openebs\nkubectl get sc openebs-hostpath\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span># CREATE LAB SC + STATEFULSET<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nkubectl apply -f sc.yaml\nkubectl apply -f sfs.yaml\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span># CHECK DYNAMIC STORAGE<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nkubectl get pods -l app=openebs-local-test -o wide\nkubectl get pvc -l app=openebs-local-test\nkubectl get pv\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span># FIND HOST-LOCAL DIRECTORY<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nPV0=$(kubectl get pvc local-vol-openebs-local-test-0 -o jsonpath='{.spec.volumeName}')\nkubectl get pv \"$PV0\" -o jsonpath='{.spec.local.path}{\"\\n\"}'\nkubectl get pv \"$PV0\" -o yaml\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span># PERSISTENCE TEST<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nkubectl exec openebs-local-test-0 -- sh -c \\\n  'echo \"Hello from OpenEBS\" &gt; \/usr\/test-pod\/hello.txt'\nkubectl delete pod openebs-local-test-0\nkubectl rollout status statefulset\/openebs-local-test --timeout=180s\nkubectl exec openebs-local-test-0 -- cat \/usr\/test-pod\/hello.txt\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span># TROUBLESHOOT<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nkubectl describe pod openebs-local-test-0\nkubectl describe pvc local-vol-openebs-local-test-0\nkubectl logs -n openebs deployment\/openebs-localpv-provisioner --tail=150\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span># CLEANUP (DELETES THIS LAB'S DATA)<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\nkubectl delete statefulset openebs-local-test\nkubectl delete pvc local-vol-openebs-local-test-{0,1,2}\nkubectl delete sc openebs-hostpath-lab\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-54\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">21. Official references<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The examples and behaviors were checked against these primary sources:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>OpenEBS 4.6 installation guide<\/strong>\u00a0\u2014\u00a0<a href=\"https:\/\/openebs.io\/docs\/quickstart-guide\/installation\">https:\/\/openebs.io\/docs\/quickstart-guide\/installation<\/a><\/li>\n\n\n\n<li><strong>OpenEBS Local PV HostPath overview<\/strong>\u00a0\u2014\u00a0<a href=\"https:\/\/openebs.io\/docs\/user-guides\/localpv-hostpath\">https:\/\/openebs.io\/docs\/user-guides\/localpv-hostpath<\/a><\/li>\n\n\n\n<li><strong>Create HostPath StorageClasses<\/strong>\u00a0\u2014\u00a0<a href=\"https:\/\/openebs.io\/docs\/user-guides\/local-storage-user-guide\/local-pv-hostpath\/configuration\/hostpath-create-storageclass\">https:\/\/openebs.io\/docs\/user-guides\/local-storage-user-guide\/local-pv-hostpath\/configuration\/hostpath-create-storageclass<\/a><\/li>\n\n\n\n<li><strong>HostPath StorageClass parameters<\/strong>\u00a0\u2014\u00a0<a href=\"https:\/\/openebs.io\/docs\/main\/user-guides\/local-storage-user-guide\/local-pv-hostpath\/configuration\/hostpath-storageclass-parameters\">https:\/\/openebs.io\/docs\/main\/user-guides\/local-storage-user-guide\/local-pv-hostpath\/configuration\/hostpath-storageclass-parameters<\/a><\/li>\n\n\n\n<li><strong>HostPath deployment example<\/strong>\u00a0\u2014\u00a0<a href=\"https:\/\/openebs.io\/docs\/quickstart-guide\/deployment\">https:\/\/openebs.io\/docs\/quickstart-guide\/deployment<\/a><\/li>\n\n\n\n<li><strong>Local storage troubleshooting<\/strong>\u00a0\u2014\u00a0<a href=\"https:\/\/openebs.io\/docs\/troubleshooting\">https:\/\/openebs.io\/docs\/troubleshooting<\/a><\/li>\n\n\n\n<li><strong>OpenEBS releases<\/strong>\u00a0\u2014\u00a0<a href=\"https:\/\/github.com\/openebs\/openebs\/releases\">https:\/\/github.com\/openebs\/openebs\/releases<\/a><\/li>\n\n\n\n<li><strong>Official OpenEBS Helm chart repository<\/strong>\u00a0\u2014\u00a0<a href=\"https:\/\/openebs.github.io\/openebs\/\">https:\/\/openebs.github.io\/openebs\/<\/a><\/li>\n\n\n\n<li><strong>Helm installation documentation<\/strong>\u00a0\u2014\u00a0<a href=\"https:\/\/helm.sh\/docs\/intro\/install\/\">https:\/\/helm.sh\/docs\/intro\/install\/<\/a><\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Tutorial result:<\/strong>&nbsp;On a self-managed Ubuntu Kubernetes cluster, OpenEBS&nbsp;<code>openebs.io\/local<\/code>&nbsp;dynamically creates separate host-local PersistentVolumes for StatefulSet PVCs. Your&nbsp;<strong>application configuration requires only a StorageClass and a StatefulSet<\/strong>&nbsp;(plus an optional headless Service for normal StatefulSet DNS), while the OpenEBS controller must be installed and healthy in the cluster.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dynamic storage provisioner:&nbsp;openebs.io\/localLab platform:&nbsp;Self-managed Kubernetes v1.35.10 on Ubuntu Linux (kubeadm or other manual installation)OpenEBS release referenced:&nbsp;OpenEBS 4.6.2 (HostPath engine v4.6.0), current as checked on November 12, 2026Lab&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[11138],"tags":[],"class_list":["post-79850","post","type-post","status-publish","format-standard","hentry","category-best-tools"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/79850","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=79850"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/79850\/revisions"}],"predecessor-version":[{"id":79851,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/79850\/revisions\/79851"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=79850"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=79850"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=79850"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}