Kubernetes - Container Orchestration on Azure (Part 1)

Foreword

This series is created from our way of introducing clients to Kubernetes, because in the end  there are no beginner-friendly resources online.

For better accuracy:

  • There are great resources for learning Kubernetes concepts and commands (The Interactive Tutorial) and
  • A myriad of resources for Container technologies.

But there is no introduction that demonstrates Kubernetes and the whole context it is in, and to understand Kubernetes the context, or how I will refer to it "the everything else" is the most difficult part. Let's see what we will build.

 

1.1

Fig.1. Sentiment Analysis Web App

Application Demo

The application has one functionality, it takes one sentence as input and using Text Analysis calculates the emotion of the sentence. See the demo in figure 1, where the web app does Sentiment Analysis, but not type-checking.

From the technical perspective, three parts compose the application where each has a specific functionality (see Fig.2. below):

  • React JS deals with presentation of information to the user and making requests to the Spring Web App.
  • Spring Web App forwards requests to the python flask application. (Spring would contain features like authorizing users, registration, which are ignored for simplicity)
  • Python Flask application that performs the Sentiment Analysis.

The code for all of these applications can be found in this repository. 

Who is this series for?

If you are a:

  • Manager/Product Owner: You will understand if your product needs Kubernetes, or not? (Read article 3)
  • Dev/DevOps inexperienced with Docker: You will learn Docker technologies and Kubernetes (Read articles 2 to 3)
  • Dev/DevOps experienced with Docker: You will learn Container Orchestration with Kubernetes (Read article 3)
  • Dev/DevOps experienced with Kubernetes: You can quickly spin up an environment for testing new features or to introduce others to Kubernetes (Copy and paste commands from article 3).
  • Junior Developer: You want to understand the latest technologies and everything else needed to ship software. (Read all articles)

Architecture

In all the articles, we will refer to the same Base Architecture. I call it “base” because in future articles we will expand it in order to illustrate more complex Kubernetes features.

Three microservices compose the Base Architecture:

  1. SA-Frontend - nginx web server hosting reactjs static files.
  2. SA-WebApp - spring web application for handling user requests.
  3. SA-Logic – flask python application for sentiment analysis.

1.2.gif

Fig. 2. Data flow in the Sentiment Analysis WebApp.

And these microservices don't live in Isolation, they enable Separation of Concerns but they still interact with each other (see Fig. 2.). This interaction is best illustrated by showing how the data flows between them:

  1. Client application requests index.html (which in turn requests bundled scripts of ReactJS application)
  2. ReactJS makes requests to the Spring WebApp.
  3. Spring WebApp forwards the requests for sentiment analysis to the Python app.
  4. Python App returns the response.
  5. Spring app returns the response to the React App. (Which then represents the information to the user)

So where are we: Purpose of the application [Check], Application Architecture [Check], let's get started with the implementation.

Let’s get started with application setup:

 

Setting up React for Local Development

To start up the React application we need to have NodeJS and NPM installed on our computer. After installing those navigate with your Terminal to the directory sa-frontend (clone the repo) and type the following command:

$ npm install

This downloads all the Javascript libraries required by the React Application and places them in the folder node_modules. After everything downloads follow up with the next command:

$ npm start

Starts our application and displays the port to which it is listening. By default, it is localhost:3000. Feel free to make edits to the Front end code and see the effect immediately in your browser.

This works well during development especially because of the Hot Module Replacement functionality that provides immediate feedback, though for production we need to build the application into static files and host them with a WebServer that offers better capabilities.

Building the React Application

To build the React application you need to be in the sa-frontend directory and execute the following command:

$ npm run build

This creates a new folder in your project tree, namely sa-frontend/build, This folder contains all the static files needed for our ReactJS application.

Serving static files with Nginx

Install and Start the Nginx WebServer, and then move the contents of the sa-frontend/build folder to [nginx_installation_dir]/html. 

If in the end the index.html generated by react build step is accessible in [nginx_installation_dir]/html/index.html, then everything was done correctly, as this is the default file that Nginx serves.

If you started Nginx server it is listening to a port (port 80 by default) you can specify the port by updating the file nginx.conf in [nginx_installation_dir]/conf. The port is defined in the listen property located under server.

Open your browser and hit the endpoint localhost:80, see the ReactJS applicaiton appear.

1.3.png

Fig. 3. React app served from Nginx

Typing in the field: “Type your sentence.” and pressing the button Send will fail with a 404 error (You can check it in your browser console). But why that? Let’s inspect the code.

Inspecting the Code

In the file App.js pressing the Send button triggers the analyzeSentence method, The code for this method is shown below, each line that is commented with #Number will be explained under the script:

GIST: https://gist.github.com/rinormaloku/bad0e8c00a0ccfd17d5e72d6d4d8eff3#file-App-js

  1. URL at which a POST call is made (an application should be listening for calls at that URL).
  2. The Request body sent to that application as displayed below:

{    sentence: “I like yogobella!”}

  1. The response updates the component state, which triggers a re-render of the component, which gets us back into the render() method and if we received the data (i.e. the json object containing the typed sentence and the polarity) we would display the component polarityComponent because the condition would be fulfilled and we would define the component:

const polarityComponent = this.state.polarity !== undefined ?                  polarity={this.state.polarity}/> :    null;

But it’s not, why? If you guessed that we didn’t set up anything to listen on localhost:8080, then you are correct! We must start our Spring Web application to listen on that port!

1.4.png

Fig. 4. React static files served with Nginx

Setting up the Spring WebApplication

To start up the Spring application we need to have JDK8 and Maven installed (their environment variables need to be set up as well). After installing those we will continue to the next part.

Packaging the Application into a Jar

Navigate in your Terminal to the directory sa-webapp (repo) and type the following command:

$ maven install

This will generate a folder named target, under the directory sa-webapp, there you will find your Java Application named ‘sentiment-analysis-web-0.0.1-SNAPSHOT.jar

Starting our Java Application

Navigate to the target directory and start the application with the command:

$ java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar

Our application fails on startup and our only lead is the exception in the stack trace:

Error creating bean with name 'sentimentController': Injection of autowired

dependencies failed; nested exception is java.lang.IllegalArgumentException:

Could not resolve placeholder 'sa.loigic.api.url' in value "${sa.logic.api.url}"

The vital information here is the placeholder sa.logic.api.url in the SentimentController. Let’s check that out!

Inspecting the Code

GIST: https://gist.github.com/rinormaloku/bf946a4a52d5172312f17450234d4192#file-SentimentController-java

  1. The sentiment controller has a property sa.logic.api.url, when this property get's defined it's value will initialize/be injected into saLogicApiUrl
  2. The object saLogicApiUrl is concatenated with the value "/analyse/sentiment" and together forming the URL to make the request for Sentiment Analysis.

In Spring the default property source is application.properties (located in sa-webapp/src/main/resources) and checking it we see that it's empty. Hmm...! We are left to either add a value in application.properties for the property (don’t forget to rebuild the jar) or we provide it with the earlier command:

$ java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar --sa.logic.api.url=BUT.WHAT.IS.THE.SA.LOGIC.API.URL

“BUT.WHAT.IS.THE.SA.LOGIC.API.URL??” That's a good question and if you guessed that it cannot be anything else but the IP and Port in which our Sentiment Analysis Python application is listening for requests, then you are totally right.

Next question that pops up is “But we still didn’t start the python application up, how can we know the IP and PORT”?

We can decide preliminary on what IP and PORT we will spin up the python/flask application. If we follow our Base Architecture in figure 5 then it will be localhost:5000.

1.5.png

Fig. 5. SA Logic still not started on localhost:5000[/caption]

 So let's let our Spring WebApp forward calls to that url:

$ java -jar sentiment-analysis-web-0.0.1-SNAPSHOT.jar --sa.logic.api.url=http://localhost:5000

Now we got to the point where we have the Nginx Server with our static files running, and the Spring WebApp running, we are left with the Flask app and we are complete. Let's move on to the last part.

 

Setting up the Python Application

To start the Python application we need to have Python3 and Pip installed (their environment variables need to be set up as well).

Installing Dependencies

Navigate in the CMD to the directory sa-logic/sa (repo) and type the following command:

$ python -m pip install -r requirements.txt

$ python -m textblob.download_corpora

Starting the app

Pip installs the dependencies and we are ready to start the application by executing the following command:

$ python sentiment_analysis.py

We are greeted by the following output:

* Running on http://localhost:5000/ (Press CTRL+C to quit)

Which means that our application is running and listening for HTTP Requests at the port 5000 on localhost.

Inspecting the Code

Let's investigate the code to understand what is happening in the SA Logic python application.
GIST: https://gist.github.com/42c152cb0f6de666a4be3981f02a0df9#file-sentiment_analysis-py

  1. Instantiate a Flask object.
  2. Defines the path at which a POST request can be made.
  3. Extract the “sentence” property from the request body.
  4. Instantiate an anonymous TextBlob object and get the polarity from the first sentence. (We have only one).
  5. Return the response with the body containing the sentence and the polarity to the caller.
  6. Run the flask object app to listen for requests on localhost:5000.

The services are set up to communicate with each other, give them a try before continuing on!

1.6.png

Fig. 6. Microservice architecture completed[/caption]

Summary

Let's recapitulate what we did. We saw the application architecture, we build all the different projects and created a container image for each then we started all the microservices to run in in different ports, we configured each to communicate with each other, and this was a tedious process, but it worked, so why Kubernetes you ask? Because our application is not scalable, it's not resilient and neither are they maintainable as the application grows/.

Stay tuned as in the next article, we will go over how to start the services in Docker Containers, as it is a prerequisite to being able to run them in a Kubernetes Cluster.

  • Erstellt am .

Standorte

Region Nord: Hamburg, Emden
Region Mitte: Langenfeld, Offenbach am Main
Region Ost: Leipzig
Region Süd: München, Ulm
Copyright by Orange Networks GmbH