Sunday, 1 October 2017

Microservices architecture with Kubernets

Kubernetes is an open-source platform for automating deployment, scaling, and operations of application containers across clusters of hosts, providing container-centric infrastructure.

Kubernetes enables speed and efficiency to respond to customer demand. Deploy application quickly that is predictable. Scale on the fly, deploy on the fly, zero/near-zero downtime. Optimal server resource utilisation.

More on why Kubernetes - https://kubernetes-v1-4.github.io/docs/whatisk8s/

Kubernetes provides multiple solutions to build, test & deployment locally and on production infrastructure, more.

For the purpose of this post, I'm using a local build & test deployment using Minikube. This is available for OSX & Linux OS. I'm using OSX.

I found Kubernetes interactive documentation is a great way to practice commands side by side while trying to understand & setup Kubernetes cluster & deploying apps - https://kubernetes.io/docs/tutorials/kubernetes-basics/

Install Minikube

Latest release https://github.com/kubernetes/minikube/releases

Install Kubectl

It is a command line interface for running commands against Kubernetes clusters.

Installation steps - https://kubernetes.io/docs/tasks/tools/install-kubectl/

Start & Check status of Minikube



$ minikube start
$ minikube status
minikube: Running cluster: Running kubectl: Correctly Configured: pointing to minikube-vm at 192.168.99.100

Run this command to open the Kubernetes dashboard:
minikube dashboard
Check Kubernetes nodes -

$ kubectl get nodes
NAME       STATUS    AGE       VERSION
minikube   Ready     6d        v1.7.5

Deploying a Containerized App

There are two ways one can do this, by using Minikube/Kubernetes dashboard or using Kubectl CLI interface.

Create a deployment by clicking the + symbol from right top;












Provide details and location of your image from Docker Hub;













If all goes well, you should then see Deployment, Pods, Service created properly. Note, I'm using it as a External Service, in a production setup you may have to expose service in a more controlled and secure manner, more on this in separate post later...hopefully soon.















Here I've deployed a SpringBoot microservice "internalapis" which is consumed by a web app "frontend".

You can get external ports for your local services using-

$ kubectl get service
NAME              CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE
hello-minikube    10.0.0.221   <nodes>       8080:30598/TCP   6d
internalapis      10.0.0.191   <pending>     9000:32342/TCP   4d
kubernetes        10.0.0.1     <none>        443/TCP          6d
newway-frontend   10.0.0.33    <pending>     3000:31247/TCP   2d

And to test services - 

http://192.168.99.100:32342/internalapis/users














Test web app -
http://192.168.99.100:31247/frontend













Hope this helps to get started.

This same can be achieved using Kubectl commands - https://kubernetes.io/docs/tutorials/kubernetes-basics/

Dockerizing Spring Boot microservice application

Assuming you have a Spring Boot app built, tested and ready to be packaged in to a container for deployment.

I am using SpringBoot with Gradle, precisely spring-boot-gradle-plugin:1.5.7.RELEASE.

Well you can create separate app and then build Docker image manually, however when using Gradle there are good plug-ins available and one I am using is Transmode/gradle-docker plug-in https://github.com/Transmode/gradle-docker

Gradle config for Docker using Transmode plug-in


group 'com.mp'
version '1.2.1-SNAPSHOT'

apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'docker'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
}

buildscript {

    ext {
        springBootVersion = '1.5.7.RELEASE'
    }

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.7.RELEASE")
        classpath "se.transmode.gradle:gradle-docker:1.2" // <- Here
    }
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'
    // tag::jetty[]
    compile("org.springframework.boot:spring-boot-starter-web")
    compile 'com.google.code.gson:gson:2.2.4'
}

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.bmuschko:gradle-docker-plugin:2.2'
    }
}

jar {
    baseName = 'internalapis'
    version = '0.1.0'
}

task buildDocker(type: Docker) {
    baseImage = 'develar/java:latest'
    push = project.hasProperty('push')
    tag = 'manmohanpanda/newway-internalapis'
    addFile {
        from jar
        rename {'newway-internalapis.jar'}
    }
    entryPoint(['java', '-Djava.security.egd=file:/dev/./urandom', '-jar', '/newway-internalapis.jar'])
    exposePort(9000)
}

buildDocker.dependsOn(build)
Then simply build your app, this will create Dockerfile under /build with required instruction.

Push Docker image to Docker Hub


./gradlew buildDocker -Ppush=true


Then you can run the image locally or download to Kubernets to deploy.

Dockerizing ReactJS, Node.JS apps

Assuming you already have a basic knowledge of Node.jS and Docker.
If you need support of how to install & get started with Node.JS & Docker then you can check their official documentations.

For Node.JS I've used npm but you can use Yarn which is a quicker way to manage your Node.JS dependencies & packaging.

Likewise for Docker you can get the software & installation steps here for your OS.

This is a very basic dev/local setup to demonstrate how to get your Node.JS app published on Docker Hub and run using basic Docker commands. Will try to cover other areas like Kubernets, automation in a much wider sense in separate post.

For my example I'm using a simple ReactJS web app.


Create RactJS app & test your ReactJS app locally first (though not the focus of this post, but a quick recap);


$ npm install -g create-react-app //install create react app 
$ create-react-app frontend //create your app
$ cd froentend
$ npm start //start & test

Modify/update your web app with whatever functionality that you need to implement.
My app is a simple SPA with a form and lists users by calling a microservice API (simple API call using JQuery). Not very fancy but just to show case/setup. http://localhost:3000/#




Dockerizing

First create a file with name Doclerfile in your ReactJS root directory.

Then open the file in any text editor and add following;

FROM node:boron
# MAINTAINER manmohanpanda

# Prepare app directory
RUN mkdir -p /usr/src/app
ADD . /usr/src/app

# Install dependencies
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json .

RUN npm install

COPY . .

# Build the app
RUN npm build

# Expose the app port
EXPOSE 3000

# Start the app
CMD npm start

Add a .dockerignore file in the same directory as your Dockerfile. I've added following files to be ignored, but you can choose what you want not to package;



.git
.gitignore
.editorconfig
node_modules
*.log
*.md

Building the Docker image

Run following from the project root directory in your shell;

docker build -t <your username>/newway-frontend .

You can check your image by doing the following;

$ docker images

If all well then it should list down


$ docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
manmohanpanda/newway-frontend          latest              961c7c38431b        About an hour ago   793MB

Run & Test the Docker image

Run the image using following;


$ docker run -p 49160:3000 -d <your username>/newway-frontend

If you want to check status docker ps, docker logs

Publish the Docker image to Docker Hub



$ docker push manmohanpanda/newway-frontend

Microservices architecture with Kubernets

Kubernetes is an  open-source platform for automating deployment, scaling, and operations of application containers  across clusters of hos...