Skip to content

ybce/PalindromeChecker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Note

The app is not deployed anymore but could still be run locally, this project was a technical assesment assigned to me by a potential employer.

Palindrome Checker

Hello! This is a simple REST API using Flask+Python deployed in a kubernetes cluster! This is my second time using Flask and Kubernetes.

This file should show how the API was roughly created and eventually deployed.

This checker will check alphanumeric strings under 100 characters only.

Schema

For the backend database, I used SQLite3 to store and retrieve the data. I opted for something more lightweight for this challenge for the quick prototyping benefit. I have 1 table in my schema and it was created as follows:

Messages:

CREATE TABLE "messages" ( 
`message_id` INTEGER PRIMARY KEY AUTOINCREMENT, 
`message` TEXT NOT NULL, 
`palindrome` INTEGER DEFAULT -1 
);

Endpoints:

There is a total of 4 endpoints for this API:

GET /

This endpoint serves the main homepage of the application.

POST /check/

Checks if the given message is a palindrome. Example of a request json.

{
    "message_id": 1
}

If the request is successful the call will the message_id along with a palindrome boolean {“status”: “Your new shop has been added”}

POST /add/

Adds a message to the table. It accepts a JSON in the body of the request. An example of a valid request body:

{
    "message": "HelloWorld"
}

If the request is successful the call will return {“status”: “Your message has been added”} .

DELETE /delete/

Deletes a message from the list. It accepts a JSON in the body of the request. An example of a valid request body:

{
 "message_id": 

}

Deploying To Kubernetes

The app was containerized using Docker and deployed to a Kubernetes cluster on GKE. It is currently exposed on the IP Address http://35.185.97.219:31788. This was my second time using Kubernetes it was pretty challenging to understand all the networking involved the first time around but I managed to research and get the image deployed and expose it to the internet. I was mainly following this tutorial for guidance.

Creating and Pushing a docker image

First of all, I created a Dockerfile that dictates how the image will be built:

FROM ubuntu:16.04

MAINTAINER Youssef El Khalili "elkhalili.youssef@outlook.com"

RUN apt-get update -y && \
    apt-get install -y python-pip python-dev

# We copy just the requirements.txt first to leverage Docker cache
COPY ./requirements.txt /qlik/requirements.txt

WORKDIR /qlik

RUN pip install -r requirements.txt

COPY . /qlik

EXPOSE 5000

CMD ["python", "run.py"]

I then ran:

docker build -t gcr.io/${PROJECT_ID}/qlik-app:v1 .

to build the the docker container where PROJECT_ID is the ID for google cloud project. After the image has been created I had to push it to the container registry using:

docker push gcr.io/${PROJECT_ID}/qlik-app:v1

I then verified that my app can run locally using this command:

docker run --rm -p 8080:5000 gcr.io/${PROJECT_ID}/qlik-app:v1

which allows me to run curl http://localhost:8080 and check the respose. The -p flag was very important because it allows you to expose the port on which the application is running and forward it to your preferred port on the host machine.

Creating a cluster on GCE

Now I had to create a container cluster so I can run the container image that I tested in the previous test. This was done using a simple gcloud command:

gcloud container clusters create hello-cluster --num-nodes=3

We can then run this command to check that the VMs have been instantiated

gcloud compute instances list

which returns:

NAME                                          ZONE        MACHINE_TYPE   PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP     STATUS
gke-flask-cluster-default-pool-c414426b-1cnf  us-east1-b  n1-standard-1               10.142.0.4   x.x.x.x         RUNNING
gke-flask-cluster-default-pool-c414426b-m541  us-east1-b  n1-standard-1               10.142.0.2   x.x.x.x         RUNNING
gke-flask-cluster-default-pool-c414426b-t5jp  us-east1-b  n1-standard-1               10.142.0.3   x.x.x.x         RUNNING

Deploying and exposing the application to the internet

To deploy and manage applications on a GKE cluster, I had to do this by using the kubectl command-line tool. To create a deployment, I had to run this command:

kubectl run flask-web --labels="run=flask-web" --image=gcr.io/${PROJECT_ID}/qlik-app:v1 --port=5000

again the port option is crucial to make sure the pod was exposing port 5000 which the application is running on.

The next and final step was to expose the deployment to the internet:

kubectl expose deployment flask-web --type=NodePort --name=qlik-app

The type flag is important becuase it dictates what type of application will be deployed the other option was to use LoadBlancer but I decided that NodePort would be more suitable for a demo application. I read this article to understand the differences, pros and cons and finally decided to use NodePort

GCE Config

Since the service is running in a GCE cluster, the last step was to allow a TCP connection to the port where the app is exposed on in the deployment which happens to be 31788 in my case. I got this value by running kubectl describe services flask-app which returns

Name:                     flask-app
Namespace:                default
Labels:                   run=flask-web
Annotations:              <none>
Selector:                 run=flask-web
Type:                     NodePort
IP:                       x.x.x.x
Port:                     <unset>  5000/TCP
TargetPort:               5000/TCP
NodePort:                 <unset>  31788/TCP
Endpoints:                x.x.x.x
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

and using the NodePort value. This can be achieved by adding a firewall rule in the google cloud console.

After all this setup, I was able to query application by using any external ip address of one the VMs in the cluster with the port http://35.185.97.219:31788 and got a successful response.

Usage

It is recommended to use Postman to test this API for its ease of use. Alternatively, one can use curl or any other preferred method.

The app is available on this IP address: http://35.185.97.219:31788

How to run this app locally

  1. Clone the git repo.
  2. Install the requirements using pip install -r requirements.txt
  3. From the top level directory, execute python run.py. Check http://localhost:5000 for the homepage.

Deploy a new version

Edit the file deploy.sh to increment the version number in all 3 commands and then run the file to build, push and set a new image. Please check this to learn about the commands and how to setup your environment.

Running tests

There are 6 unit tests in the repo. Run them by executing nose2 from the top level directory. More unit tests could be added to increase code coverage.

Note

This API was created for demo purposes only and is not representative of a development grade deployment. The API could use more features such as API token headers for authorization.

About

Web App that checks if a string is a palindrome

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published