In Kubernetes, the individual nodes of Kubernetes clusters come with a small amount of storage space. When you need additional disk space for your use case, you can add it by using a 'Persistent Volume' and/or 'Persistent Volume Claim'. These allow you to specify the type of storage you want to use, such as block storage, file storage, or object storage. Please note that at this time we only support file storage, which in turn is stored in blocks.
If these are new terms for you, we recommend reading our article on 'Persistent Volumes and Persistent Volume Claims' first. In this tutorial, we will show you how to use block storage on your Kubernetes cluster using a Persistent Volume Claim.
- You can find an overview of the block storages used within your Kubernetes cluster (used and possibly unused) in the TransIP control panel.
- We assume that you are familiar with the basics of how a Kubernetes object is structured. If not, take a look at our guide on 'Creating Kubernetes Objects' where we explain the structure.
Using block storage on your cluster
When you start working with Kubernetes, you will come across many examples both online in .yaml objects and in Helm charts that make use of block storages through the 'kind' PersistentVolume and/or PersistentVolumeClaim.
If you containerize your own application, you will soon come to a point where you want to assign additional disk space to your deployment. In the following steps, we will show you how to assign extra disk space to your applications using a PersistentVolumeClaim, using a simple example.
Step 1
First, create a namespace to include your (test) setup:
kubectl create ns transip-demo
You are free to adjust the namespace name 'transip-demo' to another name. Just make sure to do so in the following steps as well.
Step 2
Create the object that defines your setup:
nano transip-demo.yaml
Give the file the content from the code block below. In this example, we use an Nginx deployment with a load balancer service, a MySQL server, and two block storages to provide extra disk space.
It's always recommened to add a PVC per application in a production environment because every application may have different storage requirements in terms of size, access mode, etc. Splitting PVCs per application also adds to better isolation and security.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
namespace: transip-demo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: transip-fast-storage
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: transip-demo
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25.1
ports:
- containerPort: 80
volumeMounts:
- name: nginx-storage
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-storage
persistentVolumeClaim:
claimName: nginx-pvc
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: transip-demo
spec:
type: LoadBalancer
ports:
- port: 80
selector:
app: nginx
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
namespace: transip-demo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: transip-fast-storage
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
namespace: transip-demo
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: my-secret-pw
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
Save the changes and close the file (ctrl + x > y > enter).
The components of this configuration:
In a nutshell, this configuration consists of the following components:
- A PersistentVolumeClaim for Nginx of 1Gi. This provides Nginx with additional disk space that you can use, for example, to host static files of a website.
- A Deployment for Nginx, running a single replica of the Nginx pod and using the previously created PersistentVolumeClaim for storage.
- A Service for Nginx, exposing the Nginx pod to the internet via a LoadBalancer.
- A PersistentVolumeClaim of 10Gi for MySQL.
- A Deployment for MySQL, running a single replica of the MySQL pod and using the 'mysql-pvc' PersistentVolumeClaim for storage.
Code specific to using Persistent Volume Claims:
A large part of the code in this object will look familiar if you have worked with .yaml objects in Kubernetes before. If not, we recommend checking out our tutorial on creating .yaml objects. However, there are two elements in the PVC block that are not covered in the mentioned article, namely:
- spec.accessModes: The mode in which the volume is mounted, see this page for the available options.
- storageClassName: The type of storage class you can use on a Kubernetes platform, obtainable with 'kubectl get sc'. In this case, it is 'transip-fast-storage' (the default value, using NVMe) and 'transip-big-storage' (HDD).
Note: This is a simple example, and in a production environment, you would not include secret values such as the MySQL password directly in the YAML file, but store them in a Kubernetes Secret. Additionally, you would also use SSL. However, this is beyond the scope of this guide.
Step 3
Apply your configuration to your cluster with the command:
kubectl apply -f transip-demo.yaml
You will see a confirmation message that looks something like this:
transip :~$ kubectl apply -f bsdemo.yaml persistentvolumeclaim/nginx-pvc created deployment.apps/nginx-deployment created service/nginx-service created persistentvolumeclaim/mysql-pvc created deployment.apps/mysql-deployment created
With that, we have reached the end of this tutorial on using block storage via a Persistent Volume Claim. If you followed these steps, don't forget to delete the demo once you're done with:
kubectl delete ns transip-demo