Sample Flask app from documentation's tutorial, deployed on multi-node Kubernetes cluster using Kind.
Link to the Flask app on GitHub: https://github.com/pallets/flask/tree/main/examples/tutorial Link to the Flask app on Flask Documentation: https://flask.palletsprojects.com/en/2.2.x/tutorial/
The Application is being gradually moved from local setup to the container setup and finally, to the Kubernetes cluster.
Stages of improvements:
- Docker (Building docker images manually and deploying using bash scripts).
- Docker-compose (Building and deploying using Docker-compose).
- Kind + Kubernetes (Building and deploying using YAML manifests and kubectl) [current setup].
- Kind + Kubernetes + Helm (Building and deploying using Helm Charts) [current setup].
Application is modified to use external MySQL database instead of in-memory SQLite3.
MySQL database instance is listening on port 3306
(default) and initialized by db/schema.sql
file, which is responsible for creating the database, tables and user, used by Flask application.
Kubernetes cluster consists of two worker nodes and one control-plane node, all running K8s v1.26.0, deployed using Kind.
The config file for Kind Cluster is defined in kind-example-config.yaml
. You can create the cluster running kind create cluster --config kind-example-config.yaml
.
The following addition in the config file:
extraPortMappings:
- containerPort: 30423
hostPort: 30423
listenAddress: "0.0.0.0"
protocol: TCP
Is required if you want to reach the pods via a NodePort service type, which exposes the same port on worker node as defined in hostPort
key-value pair.
The Application does not have a Ingress Controller for managing external HTTP traffic, so it's the recommended way for reaching the service.
Alternatively, you can reach the pods behind a service by using kubectl port-forward svc/<service name> <port on host>:5000
. You can then open the browser and visit localhost:<port on host>
.
The default setup consists of two replicas of Flask application, which state is controlled by Deployment Controller, exposed by a NodePort type service to the user. The Flask communicates with a MySQL instance through headless service, which exposes a Stateful Set, desired to manage the state of MySQL database.
graph LR
subgraph flask-blog namespace
subgraph Flask app
A[Service - App] --> |exposes|B[Deployment]
B --> |controls state|E([Flask Pod])
B --> |controls state|F([Flask Pod])
end
subgraph MySQL
C[Service headless - Mysql] --> |exposes|D[Stateful Set]
D --> |controls state|G[(MySQL Instance)]
E -.-> |headless service DNS|C
F -.-> |headless service DNS|C
end
end
First, a namespace where the resources should be placed has to be created (if it's different from the default namespace):
kubectl create ns <name of namespace>
Then, we can install the blog application using Helm package manager
# In project's root directory
helm install flask-blog --generate-name --atomic --namespace <YOUR_NAMESPACE> --dependency-update
--atomic
flag removes the resources in case of an installation failure.
Helm Chart notes contain important information regarding application, including access, retrieving the IP address and/or ports. It also explain how to create and visualize data source from fluentd logs in Kibana Dashboard.
The Helm Chart notes will be displayed each time a new chart release is being installed or upgraded.
To see the notes at any point, run
helm get notes <YOUR_RELEASE_NAME> -n <YOUR_NAMESPACE>