Building Scalable APIs with Flask and Kubernetes: A Step-by-Step Guide
Introduction: A powerful combination for building and deploying such APIs is Flask, a lightweight Python web framework, and Kubernetes, a container orchestration platform. In this blog post, we will walk you through the steps of creating an API with Flask and deploying it on Kubernetes, ensuring scalability and reliability for your applications.
Prerequisites: Before diving into the tutorial, make sure you have the following prerequisites in place:
- Basic knowledge of Python and Flask.
- Docker installed on your development machine.
- A Kubernetes cluster set up. You can use a local solution like Minikube for testing, or a cloud-based platform like Google Kubernetes Engine (GKE) or Amazon Elastic Kubernetes Service (EKS) for production.
Step 1: Create a Flask API Let’s start by creating a simple Flask API. Here’s a basic example of an API that returns a “Hello, World!” message:
from flask import Flask
app = Flask(__name)
@app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run()
Save this code in a Python file, for example, app.py
. You can create more complex APIs according to your application’s requirements.
Step 2: Dockerize Your Flask App
To deploy your Flask API on Kubernetes, you need to package it in a Docker container. Create a Dockerfile
in your project directory with the following content:
# Use the official Python image as a parent image
FROM python:3.8-slim
# Set the working directory
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "app.py"]
Step 3: Build and Push the Docker Image
In your terminal, navigate to the project directory and run the following commands to build and push your Docker image. Replace <your-image-name>
with a unique name for your image.
docker build -t <your-image-name> .
docker push <your-image-name>
Step 4: Deploy on Kubernetes Now that you have your Docker image ready, it’s time to deploy it on Kubernetes.
- Create a Kubernetes Deployment YAML file, e.g.,
deployment.yaml
, with the following content:
apiVersion: apps/v1
kind: Deployment
metadata:
name: flask-api
spec:
replicas: 3
selector:
matchLabels:
app: flask-api
template:
metadata:
labels:
app: flask-api
spec:
containers:
- name: flask-api
image: <your-image-name>
ports:
- containerPort: 80
- Apply the deployment to your Kubernetes cluster:
kubectl apply -f deployment.yaml
- Expose the Flask API to the internet using a Kubernetes Service. Create a
service.yaml
file with the following content:
apiVersion: v1
kind: Service
metadata:
name: flask-api-service
spec:
selector:
app: flask-api
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
- Apply the service:
kubectl apply -f service.yaml
Step 5: Access Your API After a few moments, your Flask API should be up and running on your Kubernetes cluster. To access it, you can get the external IP by running:
kubectl get service flask-api-service
Open a web browser and navigate to the external IP. You should see your “Hello, World!” message.
Now, let’s create a couple of simple API endpoints using Flask and then test calling them using curl
. We’ll expand on the “Hello, World!” example from the previous blog post.
First, we need to update our Flask application to include these endpoints:
from flask import Flask, jsonify, request
app = Flask(__name)
# Endpoint 1: Return a "Hello, World!" message
@app.route('/')
def hello_world():
return 'Hello, World!'
# Endpoint 2: Return a JSON response
@app.route('/api/data', methods=['GET'])
def get_data():
data = {'message': 'This is some JSON data.'}
return jsonify(data)
# Endpoint 3: Accept POST requests and return the received data
@app.route('/api/post', methods=['POST'])
def post_data():
received_data = request.get_json()
return jsonify(received_data), 201
In this updated code, we’ve added two new endpoints:
/api/data
returns a JSON response./api/post
accepts POST requests and returns the received JSON data.
Now, let’s test these endpoints using curl
.
Testing Endpoint 1: Hello World
Open your terminal and run:
curl http://your-api-ip/
Replace your-api-ip
with the external IP address of your Kubernetes service. You should see the “Hello, World!” message.
Testing Endpoint 2: JSON Data
Run:
curl http://your-api-ip/api/data
You should receive a JSON response like:
{"message": "This is some JSON data."}
Testing Endpoint 3: POST Request
For this test, we will use curl
to send a POST request with JSON data to the /api/post
endpoint. You can use the following command:
curl -X POST -H "Content-Type: application/json" -d '{"name":"John","age":30}' http://your-api-ip/api/post
Replace your-api-ip
with the actual IP.
You should receive a response with the JSON data you posted:
{"name": "John", "age": 30}
That’s it! You’ve created API endpoints in Flask and tested them using curl
. These are just basic examples, and you can expand on this foundation to create more complex APIs to suit your specific application needs.
Now, Let’s add some basic CRUD (Create, Read, Update, Delete) operations to the Flask API using SQLAlchemy, which is a popular Object-Relational Mapping (ORM) library for Python. In this example, we’ll use SQLite as the database for simplicity. Make sure you have SQLAlchemy installed (pip install sqlalchemy
).
1. Import the required libraries:
First, you need to import the necessary libraries, including SQLAlchemy:
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
2. Configure your Flask app and set up the database:
Initialize your Flask app and configure the SQLAlchemy database:
app = Flask(__name)
# Configure the SQLite database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mydatabase.db'
db = SQLAlchemy(app)
3. Define a Model:
Define a model for your data. In this example, we’ll create a simple Task
model with an id
and a description
:
class Task(db.Model):
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(255), nullable=False)
4. Create the database:
In the terminal, run the following commands to create the SQLite database:
python
from your_app import db
db.create_all()
exit()
5. Implement the CRUD operations:
Now, you can create basic CRUD operations using SQLAlchemy for your Flask API:
- Create (POST):
@app.route('/api/task', methods=['POST'])
def create_task():
data = request.get_json()
description = data.get('description')
if description:
new_task = Task(description=description)
db.session.add(new_task)
db.session.commit()
return jsonify({'message': 'Task created successfully'}), 201
else:
return jsonify({'error': 'Description is required'}), 400
- Read (GET):
@app.route('/api/tasks', methods=['GET'])
def get_tasks():
tasks = Task.query.all()
task_list = [{'id': task.id, 'description': task.description} for task in tasks]
return jsonify({'tasks': task_list})
- Update (PUT):
@app.route('/api/task/<int:id>', methods=['PUT'])
def update_task(id):
data = request.get_json()
description = data.get('description')
task = Task.query.get(id)
if task:
if description:
task.description = description
db.session.commit()
return jsonify({'message': 'Task updated successfully'})
else:
return jsonify({'error': 'Description is required'}), 400
else:
return jsonify({'error': 'Task not found'}), 404
- Delete (DELETE):
@app.route('/api/task/<int:id>', methods=['DELETE'])
def delete_task(id):
task = Task.query.get(id)
if task:
db.session.delete(task)
db.session.commit()
return jsonify({'message': 'Task deleted successfully'})
else:
return jsonify({'error': 'Task not found'}), 404
6. Test the CRUD operations:
You can use curl
or a tool like httpie
to test the CRUD operations. Here are some examples for testing:
- Create (POST):
curl -X POST -H "Content-Type: application/json" -d '{"description":"Buy groceries"}' http://your-api-ip/api/task
- Read (GET):
curl http://your-api-ip/api/tasks
- Update (PUT):
curl -X PUT -H "Content-Type: application/json" -d '{"description":"Buy more groceries"}' http://your-api-ip/api/task/1
- Delete (DELETE):
curl -X DELETE http://your-api-ip/api/task/1
This example shows how to create a basic Flask API with SQLAlchemy for database operations. You can further customize and expand these operations to fit your application’s specific needs.