Continuing this short series of writing a simple echo service web API along with the docker and k8s requirements, we’re now going to turn our attention to a Python implementation.
Implementation
I’m using JetBrains PyCharm for this project, so I created a project named echo_service.
Next, add the file app.py with the following code
from flask import Flask, request
app = Flask(__name__)
@app.route('/echo')
def echo():
text = request.args.get('text', '')
return f"Python Echo: {text}", 200
@app.route('/livez')
def livez():
return "OK", 200
@app.route('/readyz')
def readyz():
return "Ready", 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
Add a requirements.txt file with the following
flask gunicorn
Don’t forget to install the packages via the IDE.
Dockerfile
Next up we need to create our Dockerfile
# Use a lightweight Python base FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY app.py . CMD ["gunicorn", "-w", "2", "-b", "0.0.0.0:8080", "app:app"]
Note: we’ll be using gunicorn instead of the development server.
Note: In Linux port 80 might be locked down, hence we use port 8080 by default.
To build this, run
docker build -t putridparrot.echo_service:v1 .
Don’t forget to change the name to your preferred name.
and to test this, run
docker run -p 8080:8080 putridparrot.echo_service:v1
Kubernetes
If all wen well we’ve not tested our application and see it working from a docker image, so now we need to create the deployment etc. for Kubernete’s. Let’s assume you’ve pushed you image to Docker or another container registry such as Azure – I’m call my container registry putridparrotreg.
I’m also not going to use helm at this point as I just want a (relatively) simple yaml file to run from kubectl, so create a deployment.yaml file, we’ll store all the configurations, deployment, service and ingress in this one file jus for simplicity.
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo
namespace: dev
labels:
app: echo
spec:
replicas: 1
selector:
matchLabels:
app: echo
template:
metadata:
labels:
app: echo
spec:
containers:
- name: echo
image: putridparrotreg/putridparrot.echo_service:v1
ports:
- containerPort: 8080
resources:
requests:
memory: "100Mi"
cpu: "100m"
limits:
memory: "200Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /livez
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: echo_service
namespace: dev
labels:
app: echo
spec:
type: ClusterIP
selector:
app: echo
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echo-ingress
namespace: dev
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: mydomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: echo_service
port:
number: 80
Don’t forget to change the “host” and image to suit, also this assume you created a namespace “dev” for your app. See Creating a local container registry for information on setting up your own container registry.