Search code examples
pythondockerkubernetesfastapi

Kubernetes with server and clients communicating within the cluster. I am getting a connection refused error. How should it be done?


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.


Solution

  • 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.