{"id":56,"date":"2020-06-17T19:39:39","date_gmt":"2020-06-17T18:39:39","guid":{"rendered":"https:\/\/www.slowergram.com\/?p=56"},"modified":"2020-08-19T19:41:09","modified_gmt":"2020-08-19T18:41:09","slug":"kubernetes-cluster-on-a-rpi-part-2","status":"publish","type":"post","link":"https:\/\/www.slowergram.com\/index.php\/2020\/06\/17\/kubernetes-cluster-on-a-rpi-part-2\/","title":{"rendered":"Kubernetes cluster on a RPi (Part 2)"},"content":{"rendered":"\n<p>In the previous part of this post I stood up a basic 2 node k8s cluster using&nbsp;<a href=\"https:\/\/opensource.com\/article\/20\/6\/kubernetes-raspberry-pi\" target=\"_blank\" rel=\"noreferrer noopener\">this excellent tutorial<\/a>. I now need to learn how to use k8s and decide what I want and can use it for.<\/p>\n\n\n\n<p>The last part of the tutorial is around validation of the cluster, and a good starting point to follow. As expected I followed the instructions and had 3 pods up and running in no time at all.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/06\/image.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>I then created a service to access, which created fine, however I hit an issue as I could not curl the ClusterIP from the main \u201cmaster\u201d node, but Ii could from the worker node that the pod was running on. After several rebuilds and troubleshooting later I discovered that I needed to run the command on all nodes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo iptables -P FORWARD ACCEPT<\/code><\/pre>\n\n\n\n<p>With this I could then curl the ClusterIP and retrieve the web page from any node in the k8s cluster.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Persistent Volumes<\/h4>\n\n\n\n<p>I think the thing that has always alluded me apart from networking in k8s is how persistent storage is handled. Obviously containers are designed to be ephemeral, but coming from a sysadmin background I want storage and configuration files to be there. This is handled with persistent volumes in k8s.<\/p>\n\n\n\n<p>For my k8s cluster I added a higher end flash drive to my k8s main node, one which is rated for both read and write, rather than just read. This hopefully will be temporary until I can invest in an M.2 NVMe caddy\/card.<\/p>\n\n\n\n<p>I created a basic NFS server on the main node, exporting the entire flash drive as an NFS mount. I then followed&nbsp;<a href=\"https:\/\/opensource.com\/article\/20\/6\/kubernetes-nfs-client-provisioning\" target=\"_blank\" rel=\"noreferrer noopener\">these<\/a>&nbsp;instructions on how to deploy and use an NFS-client provisioner within my k8s setup.<\/p>\n\n\n\n<p>To test this out I wanted to create a persistent volume on my NFS storage, and then use a persistent volume claim within the deploy script to mount this as a filesystem within the container. I thought the best way to try this would be to mount the NFS share into \/usr\/share\/nginx\/html on the containers and share webpages from there.<\/p>\n\n\n\n<p>First I will create the persistent volume claim:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kind: PersistentVolumeClaim\napiVersion: v1\nmetadata:\n  name: nginx-webpage\n  namespace: kube-verify\n  annotations:\n    volume.beta.kubernetes.io\/storage-class: \"managed-nfs-storage\"\nspec:\n  accessModes:\n    - ReadWriteMany\n  resources:\n    requests:\n      storage: 1Mi\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/06\/image-2.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Next I want to edit my deploy file to use the PVC and mount it inside the container at the specified mountpoint:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1\nkind: Pod\nmetadata:\n  name: kube-verify\n  namespace: kube-verify\n  labels:\n    app: kube-verify\nspec:\n  volumes:\n    - name: task-pv-storage\n      persistentVolumeClaim:\n        claimName: nginx-webpage\n  containers:\n    - name: task-pv-container\n      image: quay.io\/clcollins\/kube-verify:01\n      ports:\n        - containerPort: 8080\n          name: \"http-server\"\n      volumeMounts:\n        - mountPath: \"\/usr\/share\/nginx\/html\"\n          name: task-pv-storage\n<\/code><\/pre>\n\n\n\n<p>The pod starts up:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/06\/image-3.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>We create a service for the pod using the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1\nkind: Service\nmetadata:\n  name: kube-verify\n  namespace: kube-verify\nspec:\n  selector:\n    app: kube-verify\n  ports:\n    - protocol: TCP\n      port: 80\n      targetPort: 8080<\/code><\/pre>\n\n\n\n<p>And we can connect to the ClusterIP and see the index.html webpage which has been created on the NFS exported flash drive:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/06\/image-4.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Just to prove a point, I installed firefox on the main k8s node and ran it over a X11 session and can browse the webpage:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/06\/image-5.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>I can then edit the index.html file directly on the mounted flashdrive<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/06\/image-6.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>and the change is reflected through the webpage on an nginx pod on my k8s cluster running on my worker node.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/06\/image-7.png\" alt=\"\"\/><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/www.slowergram.com\/wp-content\/uploads\/2020\/06\/image-8.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>In the next part I will expose this with an ingress controller.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous part of this post I stood up a basic 2 node k8s cluster using&nbsp;this excellent tutorial. I now need to learn how to use k8s and decide what I want and can use it for. The last part of the tutorial is around validation of the cluster, <a href=\"https:\/\/www.slowergram.com\/index.php\/2020\/06\/17\/kubernetes-cluster-on-a-rpi-part-2\/\" class=\"btn btn-link continue-link\">Continue Reading<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[1],"tags":[10,9,6],"class_list":["post-56","post","type-post","status-publish","format-standard","hentry","category-uncategorised","tag-homelab","tag-k8s","tag-raspberry-pi"],"_links":{"self":[{"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/posts\/56","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/comments?post=56"}],"version-history":[{"count":0,"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/posts\/56\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/media?parent=56"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/categories?post=56"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.slowergram.com\/index.php\/wp-json\/wp\/v2\/tags?post=56"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}