141 lines
4.6 KiB
Markdown
141 lines
4.6 KiB
Markdown
# Running a stateful application: `volumes`
|
|
|
|
## Introduction
|
|
|
|
In this section you will learn how to deploy a stateful application, mysql in this example.
|
|
|
|
As you know a `pod` is mortal, meaning it can be destroyed by Kubernetes anytime, and with it it's local data, memory, etc. So it's perfect for stateless applications. Of course, in the real world we need a way to store our data, and we need this data to be persistent in time.
|
|
|
|
So how can we deploy a stateful application with a persistent storage in Kubernetes? Let's deploy a mysql.
|
|
|
|
## Volumes
|
|
|
|
We need to review what a volume is before continuing with the deployment of our mysql. As stated above, the disk of a pod is destroyed with it, so it's lost. For a database it would be nice if we could keep the data between restarts of the pods. Here comes the `volume`.
|
|
|
|
We can see a `pod` as something that requests CPU & RAM. We can see a `volume` as something that requests a storage on disk. Kubernetes handles a lot of different kind of volumes - 26 as this file hands on is written - from local disk storage to s3.
|
|
|
|
Here we will use `PersistentVolumeClaim`, it's an abstraction over the hard drives of the Kubernetes nodes - a fancy name for local hard drive.
|
|
|
|
Let's create the volume where our mysql data will be stored.
|
|
|
|
First we create the `PersistentVolume`. It is a piece of storage in the cluster that has been provisioned by a cluster administrator. It is a resource in the cluster just like a node is a resource of the cluster.
|
|
|
|
```yml
|
|
apiVersion: v1
|
|
kind: PersistentVolume
|
|
metadata:
|
|
name: mysql-pv-volume
|
|
spec:
|
|
capacity:
|
|
storage: 1Gi
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
hostPath:
|
|
path: "/mnt/data"
|
|
```
|
|
|
|
Let's review some parameters:
|
|
|
|
* `capacity`: the capacity of the volume
|
|
* `storage`: the volume size - here `1Gb`
|
|
* `accessModes`: how this volume will be accessed, here `ReadWriteOnce`
|
|
* `ReadWriteOnce`: the volume can be mounted as read-write by a single node
|
|
* `ReadOnlyMany`: the volume can be mounted read-only by many nodes
|
|
* `ReadWriteMany`: the volume can be mounted as read-write by many nodes
|
|
* `hostPath`: where the storage will be stored on the host, here `/mnt/data`
|
|
|
|
Apply it:
|
|
|
|
```sh
|
|
kubectl apply -f 01-simple-mysql-pv.yml
|
|
```
|
|
|
|
Now that we have a storage, we need to claim it, make it available for our pods. So we need a `PersistentVolumeClaim`. It is a request for storage by a user. It is similar to a pod. Pods consume node resources and `PersistentVolumeClaim` consume `PersistentVolume` resources.
|
|
|
|
```yml
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: mysql-pv-claim
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
resources:
|
|
requests:
|
|
storage: 1Gi
|
|
```
|
|
|
|
The manifest is pretty similar to the `PersistentVolume`:
|
|
|
|
```sh
|
|
kubectl apply -f 02-simple-mysql-pvc.yml
|
|
```
|
|
|
|
## Stateful application
|
|
|
|
Now let's create the `deployment` of mysql:
|
|
|
|
```sh
|
|
kubectl apply -f 03-simple-mysql-deployment.yml
|
|
```
|
|
|
|
There is a bunch of parameters we haven't seen yet:
|
|
|
|
* `strategy`: the strategy of updates of the pods
|
|
* `type`: `Recreate`. This instructs Kubernetes to not use rolling updates. Rolling updates will not work, as you cannot have more than one Pod running at a time.
|
|
* `env`: the list of environment variables to pass to the container
|
|
* `name`: the name of the env variable
|
|
* `value`: the value of the env variable
|
|
* `volumeMounts`: the volumes, think directories, to give access to the container
|
|
* `name`: the name of the volume to mount
|
|
* `mountPath`: where in the container to mount the volume
|
|
* `volumes`: the volumes to request access to
|
|
* `name`: the name of the volume, same as `volumeMounts.name`
|
|
* `persistentVolumeClaim`: the `PersistentVolumeClaim` we want
|
|
* `claimName`: the name of the claim
|
|
|
|
Let's finish by creating a `service` to have stable DNS entry inside our cluster.
|
|
|
|
```sh
|
|
kubectl apply -f 04-simple-mysql-service.yml
|
|
```
|
|
|
|
Finally let's access the mysql:
|
|
|
|
```sh
|
|
kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword
|
|
|
|
If you don't see a command prompt, try pressing enter.
|
|
|
|
mysql> show databases;
|
|
+--------------------+
|
|
| Database |
|
|
+--------------------+
|
|
| information_schema |
|
|
| mysql |
|
|
| performance_schema |
|
|
+--------------------+
|
|
3 rows in set (0.02 sec)
|
|
```
|
|
|
|
Create a new database in mysql:
|
|
|
|
```sh
|
|
mysql> CREATE DATABASE testing;
|
|
Query OK, 1 row affected (0.01 sec)
|
|
```
|
|
|
|
Now delete the service and the deployment:
|
|
|
|
```sh
|
|
kubectl delete service,deployment --all
|
|
```
|
|
|
|
Recreate them, reconnect to mysql and see if you still have the database `testing` you created.
|
|
|
|
## Clean up
|
|
|
|
```sh
|
|
kubectl delete service,deployment,pvc,pv,pod --all
|
|
```
|