Docker Kubernetes Series: Part2 - MongoDB

View this thread on: d.buzz | hive.blog | peakd.com | ecency.com
·@clutteredcode·
0.000 HBD
Docker Kubernetes Series: Part2 - MongoDB
* [Previous Post](https://steemit.com/programming/@clutteredcode/docker-kubernetes-series-high-scale-applications)
* [Source Code](https://github.com/cluttered-steemit/db-config/tree/part-2)

## TLDR;
setting up kubernetes Allows you to horizontally scale your application by adding multiple small servers instead of bigger more costly ones. It keeps your internal modules, called pods, safe from external interactions unless enabled. It has it's own dns so module connections can be made through service names instead of IP addresses.  It makes scaling pods ridiculously simple. It also keeps the specified number of pods running so you have 100% up times, with rolling updates and new instances of pods created when they fail.

In this section, we'll setup a [MongoDB](https://www.mongodb.com/) database. You need a place to store data for your application! There are many magnificent SQL and NoSQL databases available.  They all have their unique set of advantages and disadvantages.  MongoDB is a NoSQL [Document Oriented Database](https://en.wikipedia.org/wiki/Document-oriented_database).

The main reason I'm choosing MongoDB is that it is schemaless.  This simply means that you don't have to make changes to the database itself when modifying the format of objects being stored in the database, making it great for prototyping.  Don't sell it short though, it has many other great features that we won't get into here.  One of the other reasons it is perfect for high scale web applications is [sharding](https://docs.mongodb.com/manual/reference/glossary/#term-sharding) which allows the database to horizontally scale growing with your project.

*When you build your own application this might not be the right database. You might even need different databases to store different types of data efficiently.*

Kubernetes ideas covered in this post:
* Persistent Volume
* Deployment
* Internal Service

*We won't cover database credentials in this post. They can be enabled in MongoDB, but they aren't by default.  Anything that is run in production should require credentials. That being said, the database will only be exposed to the internal kubernetes environment and shouldn't be accessible outside of it.*

Now let's get your database installed...

## kubectl
We'll begin using kubectl, installed in the [previous post](https://steemit.com/programming/@clutteredcode/docker-kubernetes-series-high-scale-applications), to deploy things to kubernetes. I'm not going to get into the details of all the commands it can execute, so here are some useful resources:
* [kubectl Cheatsheet](https://kubernetes.io/docs/user-guide/kubectl-cheatsheet/)
* [kubectl Guide](https://kubernetes.io/docs/user-guide/kubectl/)

## Start Minikube
```bash
minikube start && eval $(minikube docker-env)
```

## Open Minikube Dashboard
```bash
minikube dashboard
```

## Persistent Volume
When you deploy a docker container everything is self-contained. That way it's easy to spin up a new one.  This is useful if the old one dies or gets corrupted,  it is also very convenient for updating.  You simply stop and remove the old one and redeploy a new one.  **The down side is that anything that was saved inside the container is lost**. You don't want to lose all the data in your database when you perform an update. To avoid this we create a persistent volume so the database data remains intact during  drops, system restarts, and container updates.  To accomplish this we'll use a kubernetes [Persistent Volume Claim](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) configuration file:

[mongo-volume-claim.yml](https://github.com/cluttered-steemit/db-config/blob/part-2/mongo-volume-claim.yml)
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mongo-data
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
```
Most of this is boilerplate for a persistent volume but the important parts are
* **name: mongo-data** - Name to reference this persistent volume
* **storage: 5Gi** - size of the storage volume

Save that to file "mongo-volume-claim.yml" and then execute the following command:
```bash
kubectl apply -f mongo-volume-claim.yml
```

**Persistent Volume Claim**
![persistent-volume-claim.png](https://steemitimages.com/DQmRTVzjXXe5DXeWhzn3ggdCHrA7CxPK3wYSvyTAezVmiqu/persistent-volume-claim.png)

**Persistent Volume (Bound to Claim)**
![persistent-volume.png](https://steemitimages.com/DQmTaktMAPVmkmXLktqiAiKsj8FoVRcyfHPs9mAFR4YvQst/persistent-volume.png)

## Deployment
Let's get an actual instance of the database running using a kuberntes [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) configuration file.

[mongo-deployment.yml](https://github.com/cluttered-steemit/db-config/blob/part-2/mongo-deployment.yml)
```yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: mongo
spec:
  replicas: 1
  template:
    metadata:
      labels:
         app: mongo
    spec:
      containers:
      - name: mongo
        image: clutteredcode/mongo-alpine:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: mongodata
          mountPath: /data/db
      volumes:
      - name: mongodata
        persistentVolumeClaim:
          claimName: mongo-data
```
This one requires a bit more explaining (feel free to post comments if more clarification is required)

* **replicas: 1** - allows us to easily scale stateless deployment. This is stateful keep it at 1.
* **app: mongo** - reference for this deployment
* **image: clutteredcode/mongo-alpine:latest** The [docker image](https://hub.docker.com/r/clutteredcode/mongo-alpine/) deployed.
* **imagePullPolicy: Always** - always grab the latest image when (re)deploying.
* **containerPort: 27017** - exposes container's port 27017 (port used by MongoDB)
* **volumeMounts** - links the volume named in 'volumes' to the *mountPath* inside the docker container to persist database info.
* **volumes** - links the persistent volume to the specified name for use in the container

Save that to file "mongo-deployment.yml" and then execute the following command:
```bash
kubectl apply -f mongo-deployment.yml
```

**Deployment, Replica Set, and Pod**
![deployment.png](https://steemitimages.com/DQmX2SL1qDY4oqfCrbN28VNNXGtvv4QQ7aRoPjbRgPAU7nK/deployment.png)

**Test Database deployment**
```bash
kubectl get pods

NAME                     READY     STATUS    RESTARTS   AGE
mongo-2313037573-2z120   1/1       Running   0          24m
```
---
Use pod name listed by the previous command
```bash
kubectl exec -it mongo-2313037573-2z120 -- mongo

MongoDB shell version v3.4.4
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.4
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
	http://docs.mongodb.org/
Questions? Try the support group
	http://groups.google.com/group/mongodb-user
...
```
---
```bash
use admin
db.system.version.find()

{ "_id" : "featureCompatibilityVersion", "version" : "3.4" }
```
**Ctrl+C to exit**

## Internal Service
We were able to access our database through kubectl and shell commands but that doesn't allow other internal pods to access the database.  We don't want anyone to have access to this database externally, keeping it more secure.  The last step is to make it accessible internally to other pods in our kubernetes environment but not available outside the environment. kuberntes [Service](https://kubernetes.io/docs/concepts/services-networking/service/) configuration file.

[mongo-service.yml](https://github.com/cluttered-steemit/db-config/blob/part-2/mongo-service.yml)
```yaml
apiVersion: v1
kind: Service
metadata:
  name: mongo
  labels:
    app: mongo
spec:
  selector:
    app: mongo
  ports:
  - port: 27017
    targetPort: 27017
```

* **name:mongo** reference name
* **selector** determines the kubernetes pods this service will route traffic to.
* **ports** maps the traffic from the port in kubernetes to the targetPort of the pod.

Save that to file "mongo-service.yml" and then execute the following command:
```bash
kubectl apply -f mongo-service.yml
```

**Service**
![service.png](https://steemitimages.com/DQmf8tCdTg129AQuPriLwTncUeeTgTMENwP71GaRYUbYPzw/service.png)

**you now have a database up and running that will be reachable from inside the kubernetes environment!**

To completely remove the Deployment and service you can issue the following command:
```bash
kubectl delete deploy,svc -l app=mongo
```
The Deployment, Replica Set, Pod, and Service will all be removed.

In this blog, I split the three sections each into their own yaml file. Kubernetes actually allows you to put multiple configurations into a single file for ease of deployment and update.  the example of all three of these together can be found in [mongo-controller.yml](https://github.com/cluttered-steemit/db-config/blob/part-2/mongo-controller.yml) when the controller run, it will setup everything we have discussed.

Save that to file "mongo-controller.yml" and then execute the following command:
```bash
kubectl apply -f mongo-controller.yml
```

## Next Post

In the next post, we'll set up a [REST interface](https://en.wikipedia.org/wiki/Representational_state_transfer) and start storing and retrieving data to/from the database we just setup. The REST api will be built using [Node.js](https://nodejs.org/en/) a very good javascript framework for backend implementatios. We'll talk about Replica Sets and horizontal scaling. As well as perform a Rolling update so that our REST api never has an interruption in service to customers, even when updating.

Questions and comments are welcome.
👍 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,