Kubernetes - With Mongo & Express App

Kubernetes - With Mongo & Express App

Deploy Express Application using Kubernetes

In this article, we'll see how kubernetes work in practice and will create a demo application using MongoDB and Express.

🎯 Minikube

  • Open source tool

  • One node kubernetes cluster that runs in a virtual box.

  • One node cluster where the master and worker processes both run on one node

  • It has docker container runtime pre-installed.

  • It runs on your machine using a virtual box or some other hypervisor. So minikube will create a virtual box on your laptop and the node will run inside that virtual box.

🎯 Kubectl

  • It provides a way to interact with the cluster, to create a pod or another K8s component.

  • kubectl is a command line tool for the K8s cluster.

🎯 Local Setup

🧩 1. Install hypervisor

Minikube needs virtualization or hypervisor so first install it.

brew install hyperkit

🧩 2. Install Minikube

brew install minikube

minikube has kubectl as a dependency, so the above command will install kubectl as well.

🧩 3. Create and start Cluster

Use the following command to start a K8s cluster

minikube start --vm-driver=hyperkit

Minikube needs to be run inside a virtual box so we need to tell Minikube which hypervisor it should use to start the cluster. Therefore in the start command, we mention the hyperkit hypervisor.

Screenshot 2022-11-28 at 12.11.26 AM.png

🧩 4. Minikube Dashboard

Use the following command to open the minikube dashboard UI in the browser

minikube dashboard

🎯 YAML Configuration File

Every configuration file in K8s has 3 parts:

  • Metadata: The first part contains information about the metadata of that component

    There is one key called kind mentioned in the configuration file which defines what K8s component we are targeting.

  • Status: It will be automatically generated and added by the K8s.

  • Specification: where we put every kind of configuration that we want to apply for that component. Attributes of "spec" are specific to the kind of component that we are creating.

    Inside Specification, there is another section called Template.

Template

  • It has its own "metadata" and "spec" section.

  • The configuration mentioned inside the template is applied to a pod

  • Template specification specifies which image needs to be used, on which port it should run and its name.

The labels & Selectors

  • metadata part contains the label and the specification part contains the selectors.

  • In metadata, we give component labels in key-value pairs.

  • This label is matched by the selector to create a connection. So this way deployment will know which pods belong to it.

🎯 Demo Project

Now that we have enough understanding of the K8s concept, let's deep dive to create a demo project to get a more clear picture.

We will create a demo express application and connect it with the MongoDB database and will see step by step guide on how each K8s component comes into the picture.

🔍 Step 1: Create a MongoDB Deployment

In K8s we do not directly work with the Pods but there is an abstraction layer over a Pod called Deployment with which we will directly work.

In mongo-deployment.yaml file:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongodb-deployment
  labels:
    app: mongodb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongodb
  template:
    metadata:
      labels:
        app: mongodb
    spec:
      containers:
      - name: mongodb
        image: mongo
        ports:
        - containerPort: 27017
        env:
        - name: MONGO_INITDB_ROOT_USERNAME
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-username
        - name: MONGO_INITDB_ROOT_PASSWORD
          valueFrom: 
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-password
  • In the image, we have specified "mongo", so it will fetch the latest mongo image from the docker hub.

  • These require 2 env. variables called MONGO_INITDB_ROOT_USERNAME & MONGO_INITDB_ROOT_PASSWORD . To get these values we will create a Secret from where we will reference that value.

  • secretKeyRef.name : specifies the name of the secret (which we have defined in Step 2)

  • secretKeyRef.key : specifies the key name which we have declared under the data section in Step 2.

  • Please note: Secret must be created before the deployment because this deployment step has dependency over the Secret step.

  • Create a deployment using the following command:

      kubectl apply -f mongo-deployment.yaml
    

    Use the following command to get all the K8s components:

      kubectl get all
    

kubectl get events

🔍 Step 2: Create Secrets

We need credentials (username or password) to connect to the database.

So we're going to create a Secret that contains the credentials.

In mongo-secret.yaml file:

apiVersion: v1
kind: Secret
metadata:
    name: mongodb-secret
type: Opaque
data:
    mongo-root-username: dXNlcm5hbWU=
    mongo-root-password: cGFzc3dvcmQ=
  • Values inside the data are not plain text this should be encrypted in some way. Storing the data in a Secret component doesn't automatically make it secure.

  • We can easily generate the base64 encoded for any plain text using the following command:

      echo -n 'plain text' | base64  
    
      // Output: cGxhaW4gdGV4dA==
    
  • Secret must be created before the deployment. So let's first create a Secret component using the following command:

      kubectl apply -f mongo-secret.yaml
    

  • To get the list of all secrets created:

      kubectl get secret
    

🔍 Step 3: Create an Internal service for MongoDB

First, we created a MongoDB pod and to talk to that pod we will need an internal service, which means no external request to that pod is allowed. Only components inside the same cluster can talk to it.

In mongo-service.yaml file:

apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
spec:
  selector:
    app: mongodb
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017
  • app: mongodb this name should be the same as the label name given in Step 1 to connect to the pod through a label.

  • port: service port

  • targetPort: containerPort of deployment

      kubectl apply -f mongo-service.yaml
    

🔍 Step 4: Create an Express deployment

In express-deployment.yaml file:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-express
  labels:
    app: mongo-express
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo-express
  template:
    metadata:
      labels:
        app: mongo-express
    spec:
      containers:
      - name: mongo-express
        image: mongo-express
        ports:
        - containerPort: 8081
        env:
        - name: ME_CONFIG_MONGODB_ADMINUSERNAME
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-username
        - name: ME_CONFIG_MONGODB_ADMINPASSWORD
          valueFrom: 
            secretKeyRef:
              name: mongodb-secret
              key: mongo-root-password
        - name: ME_CONFIG_MONGODB_SERVER
          valueFrom: 
            configMapKeyRef:
              name: mongodb-configmap
              key: database_url
  • In the image, we have specified "mongo-express", so it will fetch the latest mongo-express image from the docker hub.

  • This image will require a database name to connect for which we will require a MongoDB address or internal service. We will specify the database URL inside config map in Step 5.

  • Next, we need credentials for authentication ME_CONFIG_MONGODB_ADMINUSERNAME & ME_CONFIG_MONGODB_ADMINPASSWORD . These are same secrets which we have created in Step 2.

      kubectl apply -f express-deployment.yaml
    

🔍 Step 5: Create Config Map for Express App

First, we will need the database URL of MongoDB, so that our express app can connect to the database.

In Config Map, we'll specify all the centralised & external configuration.

So we will create Config Map that contains the database URL.

In express-configmap.yaml file:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mongodb-configmap
data:
  database_url: mongodb-service
  • database_url : it is MongoDB internal service name which we have specify in Step 3 above.

  • ConfigMap must already be in the cluster when referencing it in previous step.

      kubectl apply -f express-configmap.yaml
    

🔍 Step 6: Create an External Service for Express App

We need an external service so that it can be accessed through a browser.

In express-service.yaml file:

apiVersion: v1
kind: Service
metadata:
  name: mongo-express-service
spec:
  selector:
    app: mongo-express
  type: LoadBalancer  
  ports:
    - protocol: TCP
      port: 8081
      targetPort: 8081
      nodePort: 30000
  • We have exposed a service port at 8081.

  • TargetPort is where the container port is listening.

  • To make it external service:

    • add type: LoadBalancer

    • define nodePort where the external IP address is open. This nodePort actually has a range between 30000 - 32767.

        kubectl apply -f express-service.yaml
      
        kubectl get services
      

        minikube service mongo-express-service
      
      • This command will assign public IP address to an external service

🎯 Kubectl Basic Commands

✏️ Get Status of K8s Components

  • kubectl get nodes : get the status of nodes

  • kubectl version: get the latest version

  • kubectl get services: get a list of all services

    ✏️ Debugging Pods
  • kubectl logs [POD_NAME]: shows what the application inside the pod logs.

  • kubectl describe pod [POD_NAME]: shows additional information about pods and all the state changes that happen inside the pod.

  • kubectl exec -it [POD_NAME] -- bin/bash : start a shell session for containers running in a K8s cluster. It’s a bit like SSH for Kubernetes.

    ✏️ CRUD Operations
  • kubectl create deployment [DEPLOYMENT_NAME]: to create a deployment

  • kubectl get deployments: to get a list of all deployments

  • kubectl edit deployment [DEPLOYMENT_NAME]: to update the deployment

  • kubectl delete deployment [DEPLOYMENT_NAME]: to delete deployment

    ✏️ Resource Metrics
  • kubectl top pod : Display resource (CPU/memory) usage of pods

  • kubectl top node : Display resource (CPU/memory) usage of nodes

    🎯 Wrap Up!!

    That's all for this article. Thank you for your time!! Let's connect to learn and grow together.

    LinkedIn Twitter Instagram