I would like to create a client / server framework in Kubernetes so that each client can process a part of the task, and use the server infrequently for synchronization. I am using Python to create my server and clients, with FastAPI for the server.
As a very small example, the server looks like this. from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
with the following dockerfile
FROM python
COPY server.py /
COPY requirements.txt /
RUN pip install -r requirements.txt
CMD [ "fastapi", "run", "server.py", "--port", "8000"]
The client looks like this.
import requests
try:
f = requests.get("http://0.0.0.0:8000")
print(f.text)
except Exception as e:
print(e)
exit(5)
With the following dockerfile:
FROM python
COPY client.py /
COPY requirements.txt /
RUN pip install -r requirements.txt
CMD [ "python", "client.py" ]
and the kubernetes yaml looks like this
apiVersion: v1
kind: Deployment
metadata:
name: server
spec:
selector:
matchLabels:
app: server
replicas: 1
template:
metadata:
labels:
app: server
spec:
containers:
- name: server
image: server
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8000
---
apiVersion: v1
kind: Deployment
metadata:
name: client
spec:
selector:
matchLabels:
app: client
replicas: 1
template:
metadata:
labels:
app: client
spec:
containers:
- name: client
image: client
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8000
After building the containers (docker build -t ...
), loading them (kind load docker-image ...
) and applying the yaml (kubectl apply -f app.yaml
) I can view the logs and see that the server is running, but the client get a connection refused
error.
I assume that I am supposed to use something to expose the ports beyond what I already did, but I cannot figure out what.
As @MO mentioned in the comments, you need to use the DNS name of the service instead of the IP address in your setup. So change the IP http://0.0.0.0 with the service name to something like http://<my-svc>.<my-namespace>
.
In kubernetes you need to use the service to expose the pod within the cluster. K8s services act as a layer of abstraction that allows you to access the pods in a cluster in a structured way. So you need to create a service to expose the pod(server) and provide a stable DNS name that the client can use. Once the creation of service is done you can update the DNS name in the script and make the client use that DNS to access the server(pod).
You can define a service as follows below:
apiVersion: v1
kind: Service
metadata:
name: server-service
spec:
selector:
app: server
ports:
- protocol: TCP
port: 80
targetPort: 8000
Use this service in client script something like this
import requests
try:
f = requests.get("http://server-service")
print(f.text)
except Exception as e:
print(e)
exit(5)
This will help the client to access the server infrequently for synchronization.