Kubernetes - With Mongo & Express App
Tags: kubernetes, devops, beginners, containerapps
Published: 2023-01-01 20:58:37

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.

```bash
brew install hyperkit
```

#### 🧩 2. Install Minikube

```bash
brew install minikube
```

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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80fd699hdnzpq7a7b6xk.png)

#### 🧩 3. Create and start Cluster

Use the following command to start a K8s cluster

```bash
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.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6wrws34qe16g31vrsps.png)

#### 🧩 4. Minikube Dashboard

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

```bash
minikube dashboard
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fi3fqkinkq07c6ps7f7y.png)


## **🎯** YAML Configuration File

Every configuration file in K8s has 3 parts:

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


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/79zu2bpo4bj1z4i2rt8v.png)
    
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.
    
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3e12potsqs2ehl7pkd1x.png)
    
Inside **Specification,** there is another section called **Template.**
    

**Template**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g83g1u1od75kcg1bq23v.png)

* 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.
    
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ipgd3dzwibk22ggo9crm.png)

* This label is matched by the selector to create a connection. So this way deployment will know which pods belong to it.
    
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2lyhx39mu1cfmihvqwg.png)
    

## **🎯** 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.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jqj7yiynqg8kv2p44qez.png)


#### 🔍 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:

```yaml
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:
    
    ```bash
    kubectl apply -f mongo-deployment.yaml
    ```
    
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lvqv60hircex6ykthszr.png)
    
Use the following command to get all the K8s components:
    
    ```bash
    kubectl get all
    ```
 
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y42dermkynxpax60zok6.png)


```bash
kubectl get events
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/61r2y90gk0he2j80j8r7.png)


#### 🔍 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:

```yaml
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:
    
    ```bash
    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:
    
    ```bash
    kubectl apply -f mongo-secret.yaml
    ```
    

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4z2f4878qw0byrip7wau.png)


* To get the list of all secrets created:
    
    ```bash
    kubectl get secret
    ```
    
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/984wcqijoodpvmf11bqj.png)
    

#### 🔍 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:

```yaml
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

    
    ```bash
    kubectl apply -f mongo-service.yaml
    ```
    
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/crpyj2osv5bitrij9dsa.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vbjdv8iwxcp4mieriiic.png)

#### 🔍 Step 4: Create an Express deployment

In `express-deployment.yaml` file:

```yaml
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.
    
    ```bash
    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:

```yaml
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.
    
    ```bash
    kubectl apply -f express-configmap.yaml
    ```
    

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wddwlk6pb9ms151icz0z.png)

    
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bcpczah98drpbzco5vg2.png)


#### 🔍 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:

```yaml
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.**
        
        ```yaml
        kubectl apply -f express-service.yaml
        ```

        
        ```yaml
        kubectl get services
        ```
        
        
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hts6ke0sbwcuz66jgtnt.png)


        
        ```bash
        minikube service mongo-express-service
        ```
        
* This command will assign public IP address to an external service
            

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xjum820n3a46r7u7m3v7.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jm3nzy48affwzgq8qlx.png)



## **🎯** Kubectl Basic Commands

✏️ **Get Status of K8s Components**

* `kubectl get nodes` : get the status of nodes
    

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3exosjzi9z82mse12432.png)


* `kubectl version`: get the latest version
    
* `kubectl get services`: get a list of all services
    
  
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0mfbdoiqwmmdeubv9uax.png)
    
    
##### ✏️ **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](https://www.linkedin.com/in/anuradha-aggarwal-4a2751107/) [Twitter](https://twitter.com/Anuradh06359394) [Instagram](https://www.instagram.com/blogcode404/)