Creating Pods and Exposing Services with MetalLB on MicroK8s: A Beginner's Guide

Are you new to Kubernetes and looking for a way to create a pod using a custom image and expose it as a service using MetalLB on MicroK8s? In this beginner's guide, we'll show you how to do just that.

Kubernetes is the industry standard for container orchestration, and MicroK8s is a great way to get started with Kubernetes on your local machine. If you're not familiar with Kubernetes terminology, a pod is the smallest deployable unit that can run a container, while a service provides a stable IP address and DNS name for a set of pods.

In previous articles, we covered how to install MicroK8s on an Ubuntu Server and how to create a custom image using Docker and push it to a private container registry in our Kubernetes cluster. In this article, we'll tie those concepts together and use the image in our registry to create a pod and expose the service using MetalLB.

MetalLB is an open-source project that provides a layer-2 load balancer implementation for Kubernetes. When integrated with Kubernetes, it provides a way to expose services externally. MicroK8s is a lightweight, fast, and efficient Kubernetes distribution that runs natively on Linux machines, making it an ideal choice for local development or small-scale production environments.

By following the steps in this guide, you'll learn how to create a pod using a custom image and expose it as a service using MetalLB on MicroK8s. By the end of this article, you'll have a solid understanding of how to create pods and expose services with MetalLB on MicroK8s. So, let's get started!

Prerequisites

Before we get started, there are a few things that you will need in order to follow along with this tutorial:

  • An Ubuntu 22.04 LTS server with MicroK8s installed (if you don't have MicroK8s installed yet, you can follow our guide to get it set up).
  • A custom Docker image pushed to a private container registry (if you haven't done this yet, you can follow our guide to create and push an image).

If you have all of these prerequisites in place, then you're ready to move on to the next section and start creating your pod!

Checking custom images in our Private Registry

Before creating the pod, let’s verify which images we have in our private registry (Note that these steps are for the registry created in our previous articles). To list all the repositories you can browse to the following url “ http://<microk8s ip or hostname>:32000/v2/_catalog” or you can retrieve the json response using curl in the cli using the following command:

curl http://<microk8s ip or hostname>/v2/_catalog

You will see an answer like the following:

{"repositories":["custom-ubuntu"]}

Here you can see that there is one repository called “ custom-ubuntu” that we created in the previous article, now we can see which tags do we have inside the repository, and for that you can browse to the url “ http://<microk8s ip or hostname>:32000/v2/custom-ubuntu.tags/list” or from the cli using the command:

curl http://<microk8s ip or hostname>/v2/custom-ubuntu/tags/list

And you will see an answer like the following

{"name":"custom-ubuntu","tags":["latest"]}

At this point we know that the image is “ repository:tag” so in our case it will be “ custom-ubuntu:latest

How to create a Persistent Volume Claim

A Persistent Volume Claim (PVC) is a request for storage by a user in a Kubernetes cluster. It is used to dynamically provision a Persistent Volume (PV) for a pod. A PVC specifies the amount of storage requested, the access mode required (e.g. ReadWriteOnce, ReadWriteMany), and the storage class to be used.

The structure of a PVC YAML file is similar to that of a pod YAML file. It includes the kind, metadata, and spec sections. The spec section includes the accessModes, resources, and storageClassName fields.

Here is an example YAML file for a PVC:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
   name: my-pvc
spec:
   accessModes:
     - ReadWriteOnce
   resources:
     requests:
       storage: 1Gi

In this example, the PVC is requesting 1 gigabyte of storage using the local-storage storage class. The access mode is set to ReadWriteOnce, meaning that the volume can be mounted as read-write by a single node at a time.

To create the PVC resource in Kubernetes, you can run the following command:

microk8s kubectl apply -f my-pvc.yaml

This will create the PVC resource in your Kubernetes cluster and make it available to use by other resources, such as pods.

How to create a Kubernetes pod

In Kubernetes, a Pod is the smallest deployable unit that you can create and manage. A Pod represents a single instance of a running process in your cluster, which could be a container, a group of containers, or multiple processes on a node. You can define a Pod using a YAML file that specifies the Pod's metadata, its container specifications, and any associated configuration data.

The structure of a Pod YAML file consists of two sections: metadata and specification. The metadata section contains the name, namespace, and labels for the Pod. The specification section defines the Pod's container specifications, such as the image name, command, and volume mounts.

Here's an example of a simple Pod YAML file that specifies a single container:

apiVersion: v1
kind: Pod
metadata:
   name: my-pod
   namespace: my-namespace
spec:
   containers:
   - name: my-container
     image: my-custom-image:latest
     command: ["my-custom-command"]
     volumeMounts:
     - name: my-volume
       mountPath: /data
   volumes:
   - name: my-volume
     persistentVolumeClaim:
       claimName: my-pvc

You can find more info about how to define a pod  in the Kubernetes documentation, here.

Let's break down each section of this YAML file:

  • apiVersion : The version of the Kubernetes API used by this object.
  • kind : The type of object, which in this case is a Pod.
  • metadata : The metadata section contains the name, namespace, and any labels associated with the Pod.
  • spec : The spec section contains the Pod's configuration, including the containers, volumes, and other settings.

In the containers section, we define a single container called “ my-container”. We specify the image to use for the container, and we provide a custom command to run in the container using the command field.

In the volumes section, we define a single volume called “ my-volume”. We specify that this volume should be backed by a persistent volume claim (PVC) called “ my-pvc”.

Finally, in the “ volumeMounts” section of the container, we mount the “ my-volume” volume to the container's “ /data” directory.

To create a Pod using this YAML file, you can use the kubectl apply command:

microk8s kubectl apply -f pod.yaml

This will create a Pod called “ my-pod” in the “ my-namespace” namespace, using the configuration specified in the YAML file.

How to expose a service using MetalLB

A Kubernetes service is an abstraction layer that provides a stable endpoint for accessing a set of pods. The service decouples the pods from their consumers, allowing for better scalability and reliability. Services can be exposed internally within a cluster, or externally to the internet using an external load balancer, such as MetalLB.

To create a service, you need to create a YAML file that defines the service's properties, including the selector that matches the pods that the service targets. The service is identified by a unique name and a service type, which specifies how the service is exposed. The most common service types are ClusterIP, NodePort, and LoadBalancer.

Based on the previous pod YAML file, let's create a service YAML file to expose the pod using MetalLB in a specific IP address. Here's an example:

apiVersion: v1
kind: Service
metadata:
   name: my-service
spec:
   selector:
     app: my-app
   ports:
     - name: http
       port: 80
       targetPort: 8080
   type: LoadBalancer

In this example, we have created a service called “ my-service” in the “ my-namespace” namespace. The service targets pods with the label “ app: my-app”. The service type is “ LoadBalancer”, which means that it will be exposed externally using MetalLB. We have specified the IP address we want to use for the load balancer by setting the “ loadBalancerIP” field to “ 192.168.1.100”.

We have also defined a port called “ http” that maps to port “ 8080” on the pods. This means that when traffic is directed to port “ 80” on the service, it will be forwarded to port “ 8080” on the pods.

To create the service as in creating the pod, you can use the “ kubectl” apply command with the YAML file:

microk8s kubectl apply –f service.yaml

This will create the service in your cluster, and MetalLB will allocate an external IP address for the service. You can use the “ kubectl get services” command to check the status of the service and retrieve the external IP address:

microk8s kubectl get services my-service -n my-namespace

This will display information about the service, including its type, cluster IP, and external IP address. You can use the external IP address to access the service from outside the cluster.

Tying everything together

Configuring MetalLB Address Pool

Before creating the Pod we will configure MetalLB, for this, you will need to create a ConfigMap in your Kubernetes cluster. The ConfigMap should contain the IP address range that MetalLB can use to allocate IP addresses for your services. like this:

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: custom-addresspool
  namespace: metallb-system
spec:
  addresses:
    - <start ip>-<end ip>

And apply it with:

microk8s kubectl apply -f ipaddresspool.yaml

You can verify that the configuration was successful by retrieving the configuration with the command:

microk8s kubectl get ipaddresspools.metallb.io -n metallb-system -o yaml

Creating a namespace

In Kubernetes, a namespace is a virtual cluster inside a physical cluster. It provides a way to partition and isolate resources within the cluster, allowing multiple teams or projects to use the same physical cluster without interfering with each other.

The benefits of using namespaces include:

  1. Isolation : Namespaces provide a way to isolate resources within the same cluster, preventing conflicts between different teams or projects.
  2. Resource Management : Namespaces help manage resources such as CPU, memory, and storage more efficiently by allowing them to be shared among different services and applications.
  3. Access Control : Namespaces enable fine-grained access control, allowing administrators to grant specific users or groups access to resources in a particular namespace.

To create a namespace in MicroK8s, you can use the kubectl create namespace command followed by the name of the namespace you want to create. We are going to create a namespace called “ dev”, you can use the following command:

microk8s kubectl create namespace dev

Creating a L2 Advertisement

After you created the address pool, you need to configure the L2Advertisement this will allow that the ip addresses of the pool answer to ARP requests, because the ip addresses are not associated to any interface, to do this use the following yaml file:

apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
   name: example
   namespace: metallb-system

And apply it with:

microk8s kubectl apply -f advertisement.yaml

Creating Persistent Volume Claim

Now it is the time to create the Persistent Volume Claim with the following file:

apiVersion: v1
  kind: PersistentVolumeClaim
  metadata:
   name: my-pvc
   namespace: dev
  spec:
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 10Gi

And apply it with:

microk8s kubectl apply -f my-pvc.yaml

Creating the Pod

We can create the pod now using the persistent volume claim created before, to do that you can create the following yaml:

apiVersion: v1
kind: Pod
metadata:
    name: dev-podun
    namespace: dev
    labels:
      app: dev-app
spec:
    containers:
    - name: dev-container
      image: <microk8s ip or hostname>:32000/custom-ubuntu:latest
      ports:
        - name: ssh
          containerPort: 22
      command: ["/usr/sbin/sshd", "-D"]
      volumeMounts:
      - name: dev-volume
        mountPath: /mnt/data
    volumes:
    - name: dev-volume
      persistentVolumeClaim:
        claimName: my-pvc

and apply the configuration with:

microk8s kubectl apply -f my-pod.yaml

Exposing the service with MetalLB

To expose the service you will need to create the following yaml file, that will tie together the container with the ip address of the load balancer:

apiVersion: v1
kind: Service
metadata:
   name: dev-service
   namespace: dev
   annotations:
     metallb.universe.tf/address-pool: <name of the pool>
spec:
   selector:
     app: dev-app
   ports:
     - name: ssh
       port: 22
       targetPort: 22
   type: LoadBalancer
   loadBalancerIP: <ip address from the pool>

And apply it with:

microk8s kubectl apply –f service.yaml

 Note: That the label “app” in the pod must match the selector section of the service configuration, with this the Load Balancer will know that the container to match is the one created by your pod configuration.

Test the deployment

In a previous article, we created a custom image of an Ubuntu container with SSH service exposed. Now, we deployed the image to our microk8s cluster by creating a pod and a persistent volume with a size of 10 GB. Additionally, we created a load balancer service that is exposing port 22 (SSH) to the outside world and bridge it to the container. Once these resources are deployed, we will have an Ubuntu server installed and ready to be accessed via SSH using the IP address specified in the load balancer service definition. Note that only port 22 (SSH) is exposed, so pinging the IP address exposed by the load balancer service will not be successful.

The ultimate test is that you can connect to the container using SSH.

Monitor the deployment

Monitoring your deployed applications and infrastructure is a crucial aspect of maintaining their health and availability. Kubernetes provides several tools and techniques for monitoring, including built-in metrics and logging. In this section, we'll explore how to monitor the application we just deployed using the Kubernetes dashboard and command-line tools. We'll cover how to access the Kubernetes dashboard, view logs, and check the status of our application using the “microk8s kubectl” command-line tool.

Using the CLI

To monitor the deployment created in the previous steps, you can use the following command in the MicroK8s CLI:

microk8s kubectl get pods –namespace=dev

This command will display the list of pods running in the specified namespace, including the pod that was created using the custom image and exposed using MetalLB.

To monitor the service exposed with MetalLB, you can use the following command:

microk8s kubectl get services –namespace=dev

This command will display the list of services running in the specified namespace, including the service that was exposed using MetalLB.

You can also use the following command to get more detailed information about a specific pod or service:

microk8s kubectl describe <pod-or-service-name-from-previous-commands> –namespace=dev

This command will display detailed information about the specified pod or service, including its status, configuration, and any events related to it, while to check the logs for a pod, you can use the “microk8s kubectl logs” command followed by the name of the pod:

microk8s kubectl logs <pod-name> –namespace=dev

Using the Dashboard

To use the dashboard like in previous articles the first step is to generate the token to authenticate us, to do this, use the command:

microk8s kubectl create token default

Copy the token and go to the dashboard page “https://<microk8s ip or hostname>/” and you will see the following authentication page:

microk8s-dashboard-login Creating Pods and Exposing Services with MetalLB on MicroK8s: A Beginner's Guide

Paste the token and click “ Sign In”, you will be presented with the dashboard page:

microk8s-dashboard Creating Pods and Exposing Services with MetalLB on MicroK8s: A Beginner's Guide

Select the “ dev” namespace to limit the resources and searches to that namespace, and as soon as you do that you will start seeing the different pods and workloads status.

microk8s-dashboard-namespace-services Creating Pods and Exposing Services with MetalLB on MicroK8s: A Beginner's Guide

Clicking in the pod “ dev-pod” you can see all the information about the pod like in the screen capture below.

microk8s-dashboard-namespace-pod Creating Pods and Exposing Services with MetalLB on MicroK8s: A Beginner's Guide

Here you can see all the information of the pod, including the persistent volumes (that you can click on it to get more info), status of the pod, internal ip address and memory and cpu usage, to see the load balancer and the connection with the pod, on the left panel click in “ Services” inside the “ Service” section, and you will be presented with the following screen.

microk8s-dashboard-namespace-services Creating Pods and Exposing Services with MetalLB on MicroK8s: A Beginner's Guide

Click on the “ dev-service” service to get more information, but in this screen you can have a nice summary of the service, like the external ip address and port, the internal ip address and port, the type of service, etc… If you get more info by clicking in the service you will be presented with the following screen.

microk8s-dashboard-namespace-service-detail Creating Pods and Exposing Services with MetalLB on MicroK8s: A Beginner's Guide

Where you will see the pod “ dev-pod” attached to the service and more information related to the service.

Conclusion

In conclusion, Kubernetes is a powerful tool for managing containerized applications and microservices. Microk8s is an excellent way to run a lightweight, single-node Kubernetes cluster on your local machine, enabling developers to create, deploy, and manage applications quickly and efficiently. In this article, we have covered the basics of deploying a custom image to a pod, exposing it with a service, and configuring it to use a persistent volume using PVC. We have also explored how to use the Metallb addon to expose services to external IP addresses and how to monitor and troubleshoot using various CLI tools and the Microk8s dashboard. With these fundamental concepts, developers can easily create and deploy complex microservices applications using Microk8s.

Bokeh Solutions

Focused Results!


Empowering Businesses with Comprehensive Security Solutions!

Contact Us