Git initial commit
This commit is contained in:
commit
126041847e
11
Dockerfile
Executable file
11
Dockerfile
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
FROM python
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
ENTRYPOINT python app.py
|
54
README.md
Executable file
54
README.md
Executable file
@ -0,0 +1,54 @@
|
|||||||
|
# K8sPy
|
||||||
|
|
||||||
|
A simple test how to get a py flask app run on kubernetes.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## 1. For Docker
|
||||||
|
|
||||||
|
### Instructions
|
||||||
|
|
||||||
|
1. docker build -t flaskapp .
|
||||||
|
|
||||||
|
2. docker images -a
|
||||||
|
|
||||||
|
3. docker run -d -p 80:8000 flaskapp
|
||||||
|
|
||||||
|
-> Open Browser: http://localhost
|
||||||
|
|
||||||
|
Endpoints:
|
||||||
|
- /start-thread/<ID>
|
||||||
|
- /start-thread
|
||||||
|
- /stop-thread/<ID>
|
||||||
|
- /stop-thread
|
||||||
|
- /content/<ID>
|
||||||
|
- /content
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## 2. For Kubernetes
|
||||||
|
Here this is just testing with minikube!!!!
|
||||||
|
(Adjust the imagePullPolicy to Never when using Minikube)
|
||||||
|
|
||||||
|
This will create a cluster with 5 nodes and 10 replica pods;
|
||||||
|
On average(!) 2 pods per node, but does not have to be!
|
||||||
|
|
||||||
|
0. $ minikube start --nodes=5
|
||||||
|
|
||||||
|
1. $ minikube nodes list
|
||||||
|
|
||||||
|
2. $ minikube image load flaskapp
|
||||||
|
|
||||||
|
3. $ minikube kubectl -- apply -f deployment.yaml -f service.yaml
|
||||||
|
|
||||||
|
4. $ minikube kubectl -- get pods
|
||||||
|
|
||||||
|
5. $ minikube kubectl -- get pods -o json
|
||||||
|
|
||||||
|
6. $ minikube service list -> open URL in Browser and have fun! :)
|
||||||
|
|
||||||
|
7. $ minikube delete
|
146
app.py
Executable file
146
app.py
Executable file
@ -0,0 +1,146 @@
|
|||||||
|
from flask import Flask, request, abort
|
||||||
|
from tthread import RandomThread
|
||||||
|
from threading import Lock
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
thread_pool = {}
|
||||||
|
thread_id_max = 0
|
||||||
|
sleep_default = 0.5
|
||||||
|
|
||||||
|
mutex = Lock()
|
||||||
|
|
||||||
|
POD_NAME_VAR = os.environ.get("POD_NAME_VAR")
|
||||||
|
NODE_NAME_VAR = os.environ.get("NODE_NAME_VAR")
|
||||||
|
info = f" on Pod '{POD_NAME_VAR}' on Node '{NODE_NAME_VAR}'" if POD_NAME_VAR is not None and NODE_NAME_VAR is not None else ""
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def root_main():
|
||||||
|
welcome = f"Heyho{info} 😜"
|
||||||
|
thread_status = [
|
||||||
|
f"{thread_id}: active? {thread.is_active()}"
|
||||||
|
for thread_id, thread in thread_pool.items()
|
||||||
|
]
|
||||||
|
response = (
|
||||||
|
'<br>'.join(status for status in thread_status)
|
||||||
|
if thread_status
|
||||||
|
else
|
||||||
|
"< no active thread>"
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
f"<h1> Thread Status </h1> {welcome} <br><br> Current thread status: <br>"
|
||||||
|
f"{response}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/start-thread/<threadid>")
|
||||||
|
def start_thread_id(threadid):
|
||||||
|
threadid = str(threadid)
|
||||||
|
if threadid in thread_pool and thread_pool[threadid].is_active():
|
||||||
|
abort(409, "Thread already started.")
|
||||||
|
sleep_time = int(request.args.get('sleep-time') or sleep_default)
|
||||||
|
_start_thread(threadid, sleep_time)
|
||||||
|
return f"Starting thread with id '{threadid}'{info}."
|
||||||
|
|
||||||
|
@app.route("/start-thread")
|
||||||
|
def start_thread():
|
||||||
|
global thread_id_max
|
||||||
|
sleep_time = request.args.get('sleep-time') or sleep_default
|
||||||
|
threadid = request.args.get('thread-id')
|
||||||
|
if threadid is None:
|
||||||
|
mutex.acquire()
|
||||||
|
threadid = str(thread_id_max)
|
||||||
|
thread_pool[threadid] = None
|
||||||
|
thread_id_max += 1
|
||||||
|
mutex.release()
|
||||||
|
if threadid in thread_pool and thread_pool[threadid] is not None and thread_pool[threadid].is_active():
|
||||||
|
abort(409, "Thread already started.")
|
||||||
|
_start_thread(threadid, sleep_time)
|
||||||
|
return f"Starting thread with ID '{threadid}'{info}."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/stop-thread/<threadid>")
|
||||||
|
def stop_thread_id(threadid):
|
||||||
|
if threadid not in thread_pool:
|
||||||
|
abort(404, "Thread ID is unknown.")
|
||||||
|
elif thread_pool[threadid] is None or not thread_pool[threadid].is_active():
|
||||||
|
abort(404, "Thread is not active.")
|
||||||
|
_stop_thread(threadid)
|
||||||
|
return f"Stopping thread with id '{threadid}'{info}."
|
||||||
|
|
||||||
|
@app.route("/stop-thread")
|
||||||
|
def stop_threads():
|
||||||
|
active_threads = [
|
||||||
|
thread
|
||||||
|
for thread in thread_pool.values()
|
||||||
|
if thread is not None and thread.is_active()
|
||||||
|
]
|
||||||
|
if not active_threads:
|
||||||
|
abort(404,"No active thread!")
|
||||||
|
for thread in active_threads:
|
||||||
|
_stop_thread(thread.id())
|
||||||
|
id_list = [f"Thread '{thread.id()}'" for thread in active_threads]
|
||||||
|
response = f"Stopping threads{info}: <br>{'<br>'.join(id_list)}"
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/content/<threadid>")
|
||||||
|
def get_content_id(threadid):
|
||||||
|
if threadid not in thread_pool:
|
||||||
|
abort(404, "Thread ID is unknown.")
|
||||||
|
elif thread_pool[threadid] is None or not thread_pool[threadid].is_active():
|
||||||
|
abort(404, "Thread is not active.")
|
||||||
|
return f"<h1>Thread '{threadid}'{info}</h1><br>Content: '{thread_pool[threadid].get_content()}'"
|
||||||
|
|
||||||
|
@app.route("/content")
|
||||||
|
def get_content():
|
||||||
|
active_threads = [
|
||||||
|
thread
|
||||||
|
for thread in thread_pool.values()
|
||||||
|
if thread is not None and thread.is_active()
|
||||||
|
]
|
||||||
|
if not active_threads:
|
||||||
|
abort(404,"No active thread!")
|
||||||
|
content = [
|
||||||
|
f"Thread '{thread.id()}': {thread.get_content()}"
|
||||||
|
for thread in active_threads
|
||||||
|
]
|
||||||
|
response = (
|
||||||
|
"<h1>Thread Content{info}</h1><br>"
|
||||||
|
f"{'<br>'.join(content)}"
|
||||||
|
)
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _start_thread(threadid, sleep_time):
|
||||||
|
if not threadid in thread_pool or thread_pool[threadid] is None:
|
||||||
|
thread_pool[threadid] = RandomThread(threadid, sleep_time)
|
||||||
|
thread_pool[threadid].start()
|
||||||
|
|
||||||
|
def _stop_thread(threadid, join=False):
|
||||||
|
if not join:
|
||||||
|
thread_pool[threadid].stop()
|
||||||
|
else:
|
||||||
|
thread_pool[threadid].stopjoin()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
#DO NOT RUN IN PROD!!!!!!!!!!!!!!
|
||||||
|
app.run(host="0.0.0.0", port=8000, debug=True)
|
30
deployment.yaml
Executable file
30
deployment.yaml
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: flask-app
|
||||||
|
labels:
|
||||||
|
app: flask-app
|
||||||
|
spec:
|
||||||
|
replicas: 10
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: flask-app
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: flask-app
|
||||||
|
name: flask-app
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: flask-app
|
||||||
|
image: flaskapp
|
||||||
|
imagePullPolicy: Never
|
||||||
|
env:
|
||||||
|
- name: NODE_NAME_VAR
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: spec.nodeName
|
||||||
|
- name: POD_NAME_VAR
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.name
|
1
requirements.txt
Executable file
1
requirements.txt
Executable file
@ -0,0 +1 @@
|
|||||||
|
flask
|
15
service.yaml
Executable file
15
service.yaml
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: flask-app
|
||||||
|
name: flask-app
|
||||||
|
spec:
|
||||||
|
type: NodePort
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 8000
|
||||||
|
nodePort: 30080
|
||||||
|
selector:
|
||||||
|
app: flask-app
|
53
tthread.py
Executable file
53
tthread.py
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
from random import randint
|
||||||
|
from threading import Thread, Event
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
class RandomThread:
|
||||||
|
def executor(event, dynamic_content, sleep_time):
|
||||||
|
while not event.is_set():
|
||||||
|
dynamic_content["random"] = randint(0,10000)
|
||||||
|
sleep(sleep_time)
|
||||||
|
|
||||||
|
def __init__(self, my_id, sleep_time=0.5):
|
||||||
|
self._my_id = my_id
|
||||||
|
self._event = Event()
|
||||||
|
self._content = {"random":None}
|
||||||
|
self._sleep_time = sleep_time
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self._event.clear()
|
||||||
|
self._thread = Thread(
|
||||||
|
target=RandomThread.executor,
|
||||||
|
args=(
|
||||||
|
self._event,
|
||||||
|
self._content,
|
||||||
|
self._sleep_time
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self._thread.start()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self._event.set()
|
||||||
|
|
||||||
|
def stopjoin(self):
|
||||||
|
self.stop()
|
||||||
|
self._thread.join()
|
||||||
|
|
||||||
|
def id(self):
|
||||||
|
return self._my_id
|
||||||
|
|
||||||
|
|
||||||
|
def get_content(self):
|
||||||
|
return self._content['random']
|
||||||
|
|
||||||
|
def is_active(self):
|
||||||
|
return not self._event.is_set()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sleep_time = 0.25
|
||||||
|
tthread = RandomThread(0x32a, sleep_time*2)
|
||||||
|
tthread.start()
|
||||||
|
for i in range(20):
|
||||||
|
print(f"{i+1}: tthread has content {tthread.get_content()}")
|
||||||
|
sleep(sleep_time)
|
||||||
|
tthread.stopjoin()
|
Loading…
Reference in New Issue
Block a user