Using HELM Chart to Deploying Longhorn to an Amazon Kubernetes Cluster using Terraform
byEmmanuel COLUSSI
After having been interested in the pure kubernetes storage management part proposed by HPE : HPE Ezmeral Data Fabric (formerly MapR Data Platform) delivered with their large scale containerized application deployment and management tool : HPE Ezmeral Container Platform,as well as has OpenEBS which is a storage solution for Kubernetes , it is a broadly deployed open source storage platform that provides persistent and containerized block storage for DevOps and container environments on Kubernetes. OpenEBS adopts Container Attached Storage (CAS) approach.
I wanted to test another Kubernetes storage solution of the same type as OpenEBS.
Highly available persistent storage for Kubernetes
In the past, ITOps and DevOps have found it hard to add replicated storage to Kubernetes clusters. As a result many non-cloud-hosted Kubernetes clusters don’t support persistent storage. External storage arrays are non-portable and can be extremely expensive.
Longhorn delivers simplified, easy to deploy and upgrade, 100% open source, cloud-native persistent block storage without the cost overhead of open core or proprietary alternatives.
Easy incremental snapshots and backups
Longhorn’s built-in incremental snapshot and backup features keep the volume data safe in or out of the Kubernetes cluster.
Scheduled backups of persistent storage volumes in Kubernetes clusters is simplified with Longhorn’s intuitive, free management UI.
Cross-cluster disaster recovery
External replication solutions will recover from a disk failure by re-replicating the entire data store. This can take days, during which time the cluster performs poorly and has a higher risk of failure.
Using Longhorn, you can control the granularity to the maximum, easily create a disaster recovery volume in another Kubernetes cluster and fail over to it in the event of an emergency.
If your main cluster fails, you can bring up the app in the DR cluster quickly with a defined RPO and RTO.
For more details on the architecture of Longhorn see the following link:
In this post you will see :
How to Provisioning EBS volume with Terraform
How to deploy Longhorn with Terraform
Connect to the Longhorn dashboard
Creating a Storage Class
Provisioning a Persistent Volume Claim
Deploying a MySQL instance on an Longhorn storage
Restore Database
Prerequisites
Before you get started, you’ll need to have these things:
Terraform > 0.13.x
kubectl installed on the compute that hosts terraform
In a production configuration it is recommended to have 3 workers nodes in its kubernetes cluster. In the test configuration we have only 2 workers nodes, I took the configuration deployed in this post: Deploy a Kubernetes cluster using Ansible in AWS
Initial setup
Clone the repository and install the dependencies:
We will have to access the Kubernetes cluster api from our terraform workstation with the public IP address of our master node :
Connect to your master node and run the following commands: (we will add the public ip address of our master node)
–apiserver-cert-extra-sans=ip_private_worker01, ip_private_worker02, ip_public_master01
Get your kubernetes cluster configuration access file /etc/kubernetes1.22/admin.conf and copy it to the local directory: ~/terraform-longhorn-k8s-aws/kubeconfig/config
Test api acces with kubectl command from our terraform workstation.
You should get a similar result :
Copy your ssh key to access your cluster nodes into the ssh-keys directory (~/terraform-longhorn-k8s-aws/ssh-keys)
Install the dependencies:
We are going to add two volumes of type EBS (Elastic Block Store) of 20 Gb to each of our Worker instances .
And we will deploy our Longhorn afterwards which will use these volumes.
Provisioning EBS volume and attaching it to a Terraform EC2 worker instance.
Elastic Block Store are disk volumes which can be attached to EC2 instances.
EBS volumes exist independently, meaning their lifecycle is not dependent on the EC2 instance they are attached to.
Step 1 : get id for each worker instance : run this scripts (or get id in AWS Console) :
Modify the file variables.tf in the directory : addstorage
You should modify the worker_instance_id entry with the id values of your instances and the worker_zone entry with your working zone.
Usage
Create EBS volume and attaching it to worker instance
Tear down the whole Terraform plan with :
In a few seconds your volumes are created
Use the lsblk (on each worker nodes) to view any volumes that were mapped at launch but not formatted and mounted.
we have our two 20 Gb disks (nvme1n1nvme2n1) attached to our instance.
We will create a 20GB partition on each disk and on each worker node.
Run these two commands on each worker node :
Let’s check that our two partitions are created on each worker node:
We should have both partitions : nvme1n1p1 and nvme2n1p1
Since Longhorn doesn’t currently support sharding between the different disks.
It is recommended to use LVM to aggregate all the disks for Longhorn into a single partition, so it can be easily extended in the future.
We will create a Group Volume vgdata with both disks and a logical volume lvdata01 striped on both disks, and this on each node.
The logical volume will be mounted on the Longhorn default directory: /var/lib/longhorn.
It will be formatted in ext4
We execute these operations on each worker node.
so the users need to make sure the alternative path are correctly mounted when the node reboots, e.g. by adding it to fstab.
Custom mkfs.ext4 parameters
Allows setting additional filesystem creation parameters for ext4. For older host kernels it might be necessary to disable the optional ext4 metadata_csum feature by specifying -O ^64bit,^metadata_csum
Now let’s install our distributed storage Longhorn.
Deploy Longhorn:
First set setup Terraform configuration :
Edit the maint.tf file in directory longhorn et change a path of your kubernetes cluster configuration access file (~/terraform-longhorn-k8s-aws/kubeconfig)
and config_context value (the information is in your access file : ~/terraform-longhorn-k8s-aws/kubeconfig/config)
If you use the terraform apply command without parameters the default values will be those defined in the variables.tf file.
This will do the following :
create a namespace
create a deployment object for Longhorn
Tear down the whole Terraform plan with :
Resources can be destroyed using the terraform destroy command, which is similar to terraform apply but it behaves as if all of the resources have been removed from the configuration.
Verifying installation
Verify pods:
Wait for some time to see all the pods in the running state in the longhorn-system namespace
A default storage class is created: :
Connect to dashbord
To access the dashboard, you need to find the IP of the cluster on which the longhorn-frontend service binds :
In our case the ip address is 10.110.79.248.
We are going to connect with ssh on our master and do a port forwarding from port 80 to port 8888 for example (take an available port on your workstation).
Open a SSH tunnel:
Now you can access the dashboard on your computer at http://localhost:8888.
Deploying a Mysql instance
We start by creating our storage class : longhorn-demo
Create a storage class
From our workstation (or if you are connected to the master note run the command: kubectl apply -f https://raw.githubusercontent.com/colussim/terraform-longhorn-k8s-aws/main/longhorn/k8s/storageclass.yaml) run the following commands:
Check that the storage class is created
Create a MySQL Server instance:
We will now deploy our MySQL instance via terraform.
The deployment variables are initialized in the file variables.tf.
Run the following commands:
If you use the terraform apply command without parameters the default values will be those defined in the variables.tf file.
This will do the following :
create a namespace
create of the secret object for the password sa for the MS SQL Server instance
the password is base64 encoded, in this example the password is : Bench123
create a PVC : Persistant Volume Claim
create a deployment object for MySQL Server : create a MySQL Server instance
create a service object for MySQL Server instance:
Tear down the whole Terraform plan with :
Resources can be destroyed using the terraform destroy command, which is similar to terraform apply but it behaves as if all of the resources have been removed from the configuration.
You can also see the PVC created in the UI of Longhorn (or with command kubectl get pvc -n student1) :
Remote control
Check if your MySQL instance works:
To access the MySQL Server Instance :
Now that we are inside the shell, we can populate create a sample database and table.
Step1 : get a sample database
Step2 : copy The Employees database files in POD :
Verified that the files are copied correctly :
Step3 : run the SQL scripts for creating the employee data base and loading the data
Let’s run a few queries on the table.
We have configured the MySQL service in NodePort (we could also have configured it as a LoadBalancer and created an AWS Load Balancer Controller ).
For that you will have to modify the file mysqlpod.tf in the section resource “kubernetes_service” “mysql-deployment-student1” replace type=NodePort by type=LoadBalancer
You need to installed an AWS Load Balancer Controller and assigned the MySQL service you can connect to your instance directly using the external IP address.
Longhorn implements a very complete storage solution for Kubernetes: we have high availability, observability, and integrated backup solutions.
Longhorn is quite simple to set up. Most of its use is done through standard Kubernetes mechanisms, which is nice: these are mainly the PersistentVolume, PersistentVolumeClaim, and VolumeSnapshot objects.
All the ingredients are there to deploy this solution in production, but it is just not quite there yet compared to OpenEBS, Mapr and other competitors.
I like Longhorn a lot but let’s wait to see its evolution and its new features.