DevOps Essentials

Deploy a Machine learning Application By hatem ben tayeb

Hatem Ben T  yeb

Devops Engineer @ Astrolab-agency Sousse

linkedin.com/in/hatembentayeb/

facebook.com/htayeb2

Opensource Guy, Automation Enthusiast, Archlinux SuperFan

Plan

  1. Introduction
  2. Devops Tools & Concepts
  3. Base Code (Python app)
  4. Setting Up Target Server
  5. Setting Up CI/CD
  6. Test the app
  7. Q/A

Dev

Ops

Introduction

DevOps is the practice of operations and development engineers participating together in the entire service lifecycle, from design through the development process to production support. "The agile admin"

Tools and Concepts

(Basics)

Configuration As Code

Is a set of processes and practices that will save you time, increase your flexibility, and improve your system uptime

Ansible Playbooks

Infrastructure As Code

Is the management of infrastructure (networks, virtual machines, load balancers, and connection topology) in a descriptive model.

GitOps

Requires us to describe and observe systems with declarative specifications that eventually form the basis of continuous everything

Monitoring

Getting a global visibility of your server including :

  1. Running Containers
  2. Containers CPU
  3. Containers RAM 
  4. Containers I/O 

Tools: Prometheus,docker,cAdvisor,Grafana

Code Base

(ML python application)

Application Code

The app is based on flask  that exposes those APIs:

  1. /kmeans : Words groups classification
  2. /ads : based on age and salary, did the custmer buy the product ?
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
from sklearn.metrics import adjusted_rand_score
import json
import os
# Importing the libraries
import numpy as np
import pandas as pd
from flask import Flask,jsonify,request,render_template
app = Flask(__name__)


@app.route('/')
def main_page():
    return render_template('index.html')



@app.route('/kmeans', methods=['POST'])
def kmeans_pred():

    posted_data = request.get_json()
    true_k = posted_data['num_cluster']
    documents = posted_data['data']
    feeds = dict()
    vectorizer = TfidfVectorizer(stop_words='english')
    X = vectorizer.fit_transform(documents.split('.'))

    
    model = KMeans(n_clusters=true_k, init='k-means++', max_iter=100, n_init=1)
    model.fit(X)

    order_centroids = model.cluster_centers_.argsort()[:, ::-1]
    terms = vectorizer.get_feature_names()
    print(terms)
    for i in range(true_k):
        feeds.update({"cluster_"+str(i)+"": [terms[ind] for ind in order_centroids[i, :10]]})

    return jsonify(feeds)

@app.route("/ads", methods=['POST'])
def purshase():

    posted_data = request.get_json()
    age = int(posted_data['age'])
    salary = int(posted_data['salary'])

    new_data = [[age,salary]]

    # Importing the dataset
    dataset = pd.read_csv('Social_Network_Ads.csv')
    X = dataset.iloc[:, [2, 3]].values
    y = dataset.iloc[:, 4].values

    # Splitting the dataset into the Training set and Test set
    from sklearn.model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)

    # Feature Scaling
    from sklearn.preprocessing import StandardScaler
    sc = StandardScaler()
    X_train = sc.fit_transform(X_train)
    X_test = sc.transform(X_test)
    new_data_pred = sc.transform(new_data)

    # Fitting SVM to the Training set
    from sklearn.svm import SVC
    classifier = SVC(kernel = 'linear', random_state = 0)
    classifier.fit(X_train, y_train)

    # Predicting the Test set results
    y_pred = classifier.predict(new_data_pred)

    response = {
        "result" : str(y_pred)
    }

    return jsonify(response)




if __name__ == '__main__':
    app.run(host="0.0.0.0", port=os.environ.get('PORT'))

Main.py

Application Code

The landing page of the application 

It will be used to test the CI workflow

  1. Index.html must be on the templates directory
  2. assets must be on the static directory 
<!DOCTYPE html>
<html>
<title>EPI DSC</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Raleway">
<style>
body,h1 {font-family: "Raleway", sans-serif}
body, html {height: 100%}
.bgimg {
  background-image: url('/static/img.jpg');
  min-height: 100%;
  background-position: center;
  background-size: cover;
}
</style>
<body>

<div class="bgimg w3-display-container w3-animate-opacity w3-text-white">
  <div class="w3-display-topleft w3-padding-large w3-xlarge">
    #YUP
  </div>
  <div class="w3-display-middle">
    <h1 class="w3-jumbo w3-animate-top">Hello EPI  :D</h1>
    <hr class="w3-border-grey" style="margin:auto;width:40%">
    <p class="w3-large w3-center"> DSC EPI Cloud Engineering Track 2020</p>
  </div>

</div>

</body>
</html>

Index.html

Ship the app

It's time to ship the app into an isolated container to be shippable on any Server ! 

FROM frolvlad/alpine-python-machinelearning
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
EXPOSE 3000
ENV ENVIRONMENT dev
COPY . /app
CMD python main.py

Dockerfile

Code Repository

https://gitlab.com/hatemBT/REST-API-KMEANS
  
# Clone the project 
git clone https://gitlab.com/hatemBT/REST-API-KMEANS

# Run it locally 
pip install -r requirements.txt

# Run the code 
python main.py

#To build the docker image (change the  port=os.environ.get('PORT') => port=5000 (you can choose yor custom port))
docker build -t kmeans_app . 

#Run with docker 
docker run -p 5000:5000 kmeans_app

Server Setup

(Heroku)

Heroku

Heroku is a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud.

We need just 2 things :

  1. App name
  2. API key

Credentials

We need the .netrc file to hold our credentials (login,password) for the :

  • api.heroku.com
  • git.heroku.com
machine api.heroku.com
  login <mail>
  password <apiKey>
machine git.heroku.com
  login <mail>
  password <apiKey>

Wrap Up

  • AppName: hello-devops-eniso
  • Url: http://hello-devops-eniso.herokuapp.com/
  • APIKey: <private>

Pipeline Setup

(Gitlab)

Secrets

We need to put the apiKey and the registry url in gitlab as secrets.

go to : settings->CI/CD->variables

RegistryUrl format: registry.heroku.com/{app_name}/{container_name}

It matches:                registry.heroku.com/hello-devops-eniso/web

Pipeline code

The pipeline has a single stage "development" that will deploy the container to the "hello-devops-eniso" app 

image : docker:latest

services:
  - docker:dind

variables:
    DOCKER_DRIVER: overlay

stages:
    - devloppement

devloppement:
    stage : devloppement
    script:
         - echo -e " Start Building Docker image from Docker file ..  "
         - docker build -t $HEROKU_APP .
         - echo -e "\n build complete\n\n Start pushing image to registry.heroku.com ..."
         - docker login --username=_ -p $HEROKU_TOKEN registry.heroku.com
         - docker push $HEROKU_APP
         - echo -e " push complete ."
         - echo -e " Start pushing the app to the developpement server .. "
         - docker run  --rm  -e HEROKU_API_KEY=$HEROKU_TOKEN wingrunr21/alpine-heroku-cli container:release web --app hello-devops-eniso
         - echo -e " complete"
    

Steps:

  • Build the container
  • login to heroku registry
  • Push the container
  • Release the container

Push The Code

Wait until Green :D

Test The App

(Curl)

From The Browser

From The Terminal

Test the /kmeans route

Test the /ads route

curl -X POST -H "Content-Type: application/json" "http://hello-devops-eniso.herokuapp.com/kmeans" -d @data.json | jq "."
curl -X POST -H "Content-Type: application/json" "http://hello-devops-eniso.herokuapp.com/ads" -d "{\"age\":36,\"salary\":140000}" | jq "."

For More

Check my 

Q/A

Devops Essentials

By hatem ben tayeb

Devops Essentials

[devops] Let's deploy a simple ML app on heroku with gitlab

  • 1,168
Loading comments...

More from hatem ben tayeb