How to Deploy a Flask Application to Kubernetes

How to Deploy a Flask Application to Kubernetes

Flask is a Python framework that allows developers to easily create web applications. It is a microweb framework meaning that it doesn't require any particular tools or libraries to work. However, it is highly extensible, allowing developers to include application features as though they were implemented in Flask itself.

Flask is easy to learn and a great way of building web applications. This article aims to guide you through the process of deploying a Flask application to Kubernetes. By the end of this guide, you'll have a first-hand understanding of how this process works.

Basic Structure of a Flask Application

Building a Flask application is quite simple. If you already know Python, you'll find it easy to understand. If you don't, don't worry, it has a simple learning curve.

A basic Flask application has the following structure:

flask-app/
    app/
        __init__.py
        views.py
    requirements.txt
    app.py

The following is a brief explanation of the files and directories in the structure:

  • The app directory contains the main application code.

    • The __init__.py file initializes the Flask application.

    • The views.py file contains the routes and views of the application.

  • The requirements.txt file contains the dependencies of the application.

  • The app.py file is the entry point of the application.

The most important file in a Flask app is typically the Python script that serves as the application's entry point. This file is commonly named app.py or something similar. It is the file that is run to start the application.

Below is an example of what the app.py file might look like:

from flask import Flask

app = Flask(__name__)

@app.route('/')

def index():
    return 'Hello, World!'

This file creates a new Flask application and defines a single route that returns the string "Hello, World!".

Note: You would usually have more files and directories in a real-world application, but this is the basic structure of a Flask application.

Project Setup

To deploy this Flask application, you'll need Nginx - a web server that can also be used as a reverse proxy and Gunicorn - a Web Server Gateway Interface (WSGI) application server to serve the Flask application.

To incorporate these tools, you'll deploy an Nginx container which acts as a reverse proxy to the Flask application container. Gunicorn will be deployed in the Flask application container to serve the application.

Once a request is sent to the server, it will be forwarded to the Nginx container which will then forward it to the Gunicorn server running in the Flask application container. The Gunicorn server will then serve the Flask application response back to the Nginx container which will then forward it to the client.

Prerequisites

To save cost, this application will be deployed to a local Kubernetes cluster, therefore, you need Minikube installed and running on your local machine. You also need the following installed:

Application Setup

The application you'll be deploying is a simple Flask application called Flaskex. It is a simple example for rapid prototyping. It contains features such as user authentication, a ready-to-go database system, etc.

The project is open-source, clone the project files using the command below:

git clone https://github.com/anfederico/flaskex.git

Navigate into the project's directory using the command below:

cd Flaskex

View the content of this repository and understand how things work before proceeding.

Step 1 - Start a Virtual Environment

A virtual environment is a self-contained directory that contains a Python interpreter and all the libraries and dependencies needed for a specific project.

It allows you to isolate project dependencies from the system-wide Python installation, which helps in managing different projects with conflicting library requirements.

To create a virtual environment, run the command below:

python3 -m venv venv

Activate the virtual environment using the command below:

source venv/bin/activate

Step 2 - Build the Docker Image

You will need to build two Docker images, one for the Flask application and another for the Nginx server.

Flask Application Image

  • Create a folder called flask in the project's root directory using the command below:

      mkdir flask
    
  • Copy all the content of the repository into the flask directory

  • Create a file called Dockerfile in the flask directory and add the following content:

      # Use an official Python runtime as a parent image
      FROM python:3.8-slim
    
      # Set the working directory in the container
      WORKDIR /app
    
      # Copy the current directory contents into the container at /app
      COPY . /app
    
      # Install any needed dependencies specified in requirements.txt
      RUN pip install --no-cache-dir -r requirements.txt
    
      # Copy the forms.py file from your host machine to the container
      COPY forms.py /app/scripts/forms.py
    
      #Command to run your Flask app using Gunicorn
      CMD ["gunicorn", "app:app", "-b", "0.0.0.0:8000"]
    

    This file creates the Docker image using a Python 3.8-slim base image. The file follows the usual Dockerfile format, with a few additional commands to install the application's dependencies and start the application using Gunicorn.

    One specific thing to note is the COPY command. This line copies a file called forms.py from the host machine to the container. This file contains authentication information needed by the Flask application.

    Make sure to create the forms.py file and include your authentication information in it.

    The forms.py file is shown below:

      # -*- coding: utf-8 -*-
    
      from wtforms import Form, StringField, validators
    
      class LoginForm(Form):
      username = StringField('Username:NAME', validators=[validators.Length(min=1, max=30)])
      password = StringField('Password:PASSWORD', validators=[validators.Length(min=1, max=30)])
      email = StringField('Email:EMAIL@gmail.com', validators=[validators.Length(min=0, max=50)])
    

    Replace the NAME, PASSWORD, and EMAIL@gmail.com with your appropriate information.

Nginx Image

  • Navigate out of the flask directory and create another folder called nginx:

      cd ..
      mkdir nginx
    
  • Create a file called Dockerfile inside the nginx directory and add the following content:

      FROM nginx
    
      RUN rm /etc/nginx/conf.d/default.conf
    
      COPY nginx.conf /etc/nginx/conf.d/
    

    This file uses an nginx base image and removes the default configuration file. It then copies a custom configuration file called nginx.conf to the container.

    Create the nginx.conf file and add the following content:

      upstream flaskapp {
        server flask-app:8000;
      }
    
      server {
      listen 80;
    
          location / {
              proxy_pass http://flaskapp;
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header X-Forwarded-Proto $scheme;
          }
      }
    

    This file defines an upstream block that points to the Flask application container. It also defines a server block that listens on port 80 and forwards requests to the Flask application container.

Build the Docker Images

After writing both Dockerfiles, you'll need to build and push them to a Docker registry - Docker hub.

To build the images, run the commands below:

docker build -t flask ./flask
docker build -t nginx ./nginx

The -t flag is used to tag the image with a name. The ./flask and ./nginx are the paths to the Dockerfiles.

After building the images, you'll need to push them to a Docker registry. To do this, you'll need to create a Docker Hub account and login to the Docker Hub using the command below:

docker login -u "USERNAME" -p "PASSWORD" docker.io

Replace USERNAME and PASSWORD with your Docker Hub username and password.

After logging in, push the images to the Docker Hub using the commands below:

docker tag flask USERNAME/flask:latest
docker push USERNAME/flask:latest
docker tag nginx USERNAME/nginx:latest
docker push USERNAME/nginx:latest

Replace USERNAME with your Docker Hub username.

Step 3 - Deploy the Application to Kubernetes

After building and pushing the images to the Docker Hub, you'll deploy the application to a Kubernetes cluster. To do this, you'll need to create a Kubernetes deployment and service for the Flask application and the Nginx server.

Create a Deployment and Service for the Flask Application

Create a file called flask-app-deployment.yaml and add the following content:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flask-app
  labels:
    app: flask-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flask-app
  template:
    metadata:
      labels:
        app: flask-app
    spec:
      containers:
        - name: flask-app
          image: USERNAME/flask:latest
          ports:
            - containerPort: 8000

This file creates a deployment with a single replica for the Flask application. It uses the USERNAME/flask-app image that was pushed to the Docker Hub.

Create a file called flask-app-service.yaml and add the following content:

apiVersion: v1
kind: Service
metadata:
  name: flask-app
spec:
  selector:
    app: flask-app
  ports:
    - protocol: TCP
      port: 8000
      targetPort: 8000
  type: NodePort

This file creates a service for the Flask application. The service listens on port 8000 and forwards requests to the Flask application container.

Create a Deployment and Service for the Nginx Server

Create a file called nginx-deployment.yaml and add the following content:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: USERNAME/nginx:latest
          ports:
            - containerPort: 80

This file creates a deployment with a single replica for the Nginx server. It uses the USERNAME/nginx image that was pushed to the Docker Hub.

Create a file called nginx-service.yaml and add the following content:

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: NodePort

After creating the manifest files, apply them to the Kubernetes cluster using the commands below:

kubectl apply -f flask-app-deployment.yaml
kubectl apply -f flask-app-service.yaml
kubectl apply -f nginx-deployment.yaml
kubectl apply -f nginx-service.yaml

After applying the manifest files, you can view the services and deployments using the commands below:

kubectl get services
kubectl get deployments

Step 4 - Access the Application

Since you're using a local Kubernetes cluster, you'll access the application using the curl command.

To achieve this, you'll run the command below:

minikube service flask-app --url

This command will return the URL of the Flask application. You can access the application using the URL returned.

The output of the command will look something like this:

http://<IP>:<PORT>

Replace <IP> and <PORT> with the IP address and port returned by the minikube service command.

Curl the URL returned by the minikube service command to access the application:

curl http://<IP>:<PORT>

Conclusion

In this guide, you learned how to deploy a Flask application to Kubernetes. You created a Docker image for the Flask application and Nginx server, pushed the images to the Docker Hub, and deployed the application to a Kubernetes cluster.

You can now deploy your own Flask applications to Kubernetes using the knowledge you've gained from this guide. Happy coding!