Complete Application Deployment using Kubernetes
Tags: kubernetes, devops, tutorial, microservices
Published: 2021-06-23 05:11:24

In this post, we will be deploying a complete end to end application using **Kubernetes**. We will see and discuss how the different components of Kubernetes compliment each other and make the application deployment process smooth.

We will be using minikube to deploy our application on our local system. You can refer this link to read more about minikube : https://minikube.sigs.k8s.io/docs/start/

Once you are done with this post, you would be familiar with the below concepts in Kubernetes:

- **Creating Deployment using YAML file.**
- **What is Pod and How to define the pod in YAML config file.**
- **How to to create internal service and make the pod accessible to other component in the cluster.**
- **How to create external service and make the pod accessible outside the cluster.**

Sample application which we will be deploying on the Kubernetes cluster will be as below. We will deploy **mongodb** and **mongo-express** docker image and will access the mongo-express from the browser.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ilz5fnax8spwf8qnkhvf.png)
 
To deploy the above application on Kubernetes we will be following the below steps:

1.First we will create `mongodb secret` which will contain the sensitive information such as the `mongodb username` and `password` in encrypted format.
2. Then create `mongodb deployment and service` which will be responsible to create the mongdb pod and exposing the mongodb to the other internal components.
3. Now we will create `mongodb configmap` to save the `mongodb url` and other configuration.
4. Once config map is created and deployed we will create the `mongo-express deployment` file to create the mongo-express pod.
5. Accessing the application from the browser.

**Before implementing the above steps to deploy the mongodb application on Kubernetes, lets revise the few Kubernetes components which will be used in deploying the application in brief.**

**Pods**: Pods are the `smallest, most basic deployable` objects in Kubernetes. A Pod represents a single instance of a running process in your cluster. Pods contain `one or more containers`, such as Docker containers.

**Secrets**: Secrets let you store and manage `sensitive information`, such as passwords, OAuth tokens, and ssh keys. Storing confidential information in a Secret is safer and more flexible than putting it verbatim in a Pod definition or in a container image

**ConfigMap**: A ConfigMap is an API object used to store `non-confidential data in key-value pairs`. Pods can consume ConfigMaps as environment variables, command-line arguments, or as configuration files in a volume.A **ConfigMap** allows you to decouple environment-specific configuration from your container images, so that your applications are easily portable.

**Deployment**: Deployment is a resource object in Kubernetes that provides `declarative updates` to applications. A deployment allows you to describe an application’s life cycle, such as which images to use for the app, the number of pods there should be, and the way in which they should be updated.

**Services** : Service is a `logical abstraction` for a deployed group of pods in a cluster (which all perform the same function). Since pods are ephemeral, a service enables a group of pods, which provide specific functions (web services, image processing, etc.) to be assigned a name and unique IP address (clusterIP).

> **Note:** ConfigMap does not provide secrecy or encryption. If the data you want to store are confidential, use a Secret rather than a ConfigMap, or use additional (third party) tools to keep your data private.

Now let’s deploy the complete mongodb application by following the steps discussed above. Architecture of our application with different components will be as below :

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oiaegytz7mmzbbf6lyj8.png)


## Step 1: Create Secrets to Save Mongodb username and password .

As our **mongodb** application require username and password to access, as username and password are confidential information, so will be creating the secrets to save them. We have username as “username” and password as “password“. We are saving them by encoding in **base64**.

### mongo-secret.yaml

```yaml
apiVersion: v1
kind: Secret
metadata:
    name: mongodb-secret
type: Opaque
data:
    mongo-root-username: dXNlcm5hbWU=
    mongo-root-password: cGFzc3dvcmQ=
```

**apiVersion** : this is the version of the API used by the cluster.

**kind**: kind define whether it’s a deployment, secret or configMap.

**metadata**: here we can define data about the object we are about to create. In this example, we only provide the name of the pod. But you can provide other details like the namespace.

**type**:  type Opaque means that from kubernetes’s point of view the contents of this Secret is unstructured, it can contain arbitrary key-value pairs.

**data** : data contains the data, you want to save as secrets.

Deploy the secret config file via `kubectl apply -f mongo-secret.yaml`.


![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ax6x13wo51vcz4rbw54d.png)

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1148j3sbqs8ruek7ca7y.png)

## Step 2 : Create the mongo deployment and Service to create the mongo pod.
  
Now we will create the mongo deployment to create the mongodb pod, mongo db deployment will be fetching the mongodb username and password from the mongo secrets created in Step1.

###mongo.yaml

```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
---
apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
spec:
  selector:
    app: mongodb
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017
```
In the above yaml file we have defined two things :

1.**Deployment** – responsible to create the pod and replicaset of the pod.(here we are creating only one replica).
2.**Service** – to expose the pod to the internal component.

Now Let’s see the each field in deployment in the more details:

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

**apiVersion** : this is the version of the API used by the cluster.

**kind**: kind define whether it’s a deployment, secret or configMap.

**metadata**: here we can define data about the object we are about to create. In this example, we only provide the name of the pod. But you can provide other details like the namespace.

**spec**: in the deployment kind file, we have spectification which is responsible for defining the replica, selector and container template.

**replicas** : define the number of pod to be created for this container.

**selector**: inside selector we define the matching Label.

**template**: template is the actual blue print of the container and pod that will be created.

**template.metadata** : contains the information about pod like label etc.

**template.spec**: blueprint for the container that needs to be created.

**containers** : define the different pod to be created.

**name**: name of container.

**image**: docker image that will be pulled from docker hub.

**ports**: on which this container will be accessible.

**env** : container the environment variables like mongodb username and password in our case.

> Note: Secrets needs to be created first before the applying the deployment as they are being used in the deployment as environment variable.

Let’s see the service in more detail now:

```yaml
apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
spec:
  selector:
    app: mongodb
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017
```

Service yaml has the similar fields as in the deployment, only targetPort field is different, `targetPort` is the port on which other component can access this pod.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hidxavbw03ndbvmfwhns.png)

## Step 3: Create Secrets to Save Mongodb username and password

Now we will create the configMap which will contain the mongodb url.

## mongo-configmap.yaml

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mongodb-configmap
data:
  database_url: mongodb-service
```

ConfigMap file is almost similar to the other yaml file.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9sdudz7h8nbl9onv09m1.png)
 
## Step 4: Create the mongo-express deployment and external service to create the mongo-express pod and expose it to the outside of cluster.

### mongo-express.yaml

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

**mongo-express** deployment config is similar to the **mongodb** deployment config so we will not discuss that here.

We will discuss few of the extra field that we have in the mongo-express external service below: 

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

This service file contains 2 fields extra (type, nodePort )as compared to the service file of mongodb.

**type: LoadBalancer** : makes the service external by assigning the service external ip address.

**nodePort**: port on which this pod can be accessed outside the cluster.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7660tyecihagmfnbp7wo.png)
 
##Step 5: Access the Mongo-Express from the browser.

To access the mongo-express from the browser, we would need to find the IP ADDRESS of the service assigned by the kubernetes.

We will first verify if the service is created and will fetch the service name by the following command

```bash
kubectl get service
```
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uzfkkgcg0k24sa3l7i0u.png)

As we can see our external service with the name mongo-express-service and internal service mongodb-service both have been created.

Now we will run our external service to get the url created for the service to be accessible by using below command.

```bash
minikube service mongo-express-service
```

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x98k4pbrny2bmssqerzp.png)

Now copy paste the url in browser and check whether application is accessible.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fjao7xkdg10igt9y49jb.png)

We can see that we are able to access the application in our browser on port 30000 as given in the external service yaml file.

## Conclusion

So in this way we deployed a complete end to end mongo db application on kubernetes and access it through our browser. We created a mongodb pod and made it accessible to the other component by internal service. We also created one pod for mongo-express to make changes to mongodb and created an external service to make it accessible outside the cluster or external source.

*This is all from this Post, if you have any question or find anything wrong, then please comment below.*

This post was first published on my personal blog. If you find this blog content relevant, you can visit my blog for similar kind of content: https://ishantgaurav.in/