Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Route to specific pod through Kubernetes Service (like a Gateway API)

I am running Kubernetes on "Docker Desktop" in Windows.

I have a LoadBalancer Service for a deployment which has 3 replicas. I would like to access SPECIFIC pod through some means (such as via URL path : < serviceIP >:8090/pod1).

Is there any way to achieve this usecase?


deployment.yaml :

apiVersion: v1
kind: Service
metadata:
  name: my-service1
  labels:
    app: stream
spec:
  ports:
  - port: 8090
    targetPort: 8090
    name: port8090
  selector:
    app: stream
  # clusterIP: None
  type: LoadBalancer
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: stream-deployment
  labels:
    app: stream
spec:
  replicas: 3
  selector:
    matchLabels:
      app: stream
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: stream
    spec:
      containers:
      - image: stream-server-mock:latest
        name: stream-server-mock
        imagePullPolicy: Never
        env:
        - name: STREAMER_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: STREAMER_ADDRESS
          value: stream-server-mock:8090
        ports:
        - containerPort: 8090

My end goal is to achieve horizontal auto-scaling of pods.

How Application designed/and works as of now (without kubernetes) :

There are 3 components : REST-Server, Stream-Server (3 instances locally on different JVM on different ports), and RabbitMQ.

1 - The client sends a request to "REST-Server" for a stream url.
2 - The REST-Server puts in the RabbitMQ queue.
3 - One of the Stream-Server picks it up and populates its IP and sends back to REST-Server through RabbitMQ.
4 - The client receives the IP and establishes a direct WS connection using the IP.

The Problem what I face is :

1 - When the client requests for a stream IP, one of the pods (lets say POD1) picks it up and sends its URL (which is service URL, comes through LoadBalancer Service).
2 - Next time when the client tries to connect (WebSocket Connection) using the Service IP, it wont be the same pod which accepted the request.

It should be the same pod which accepted the request, and must be accessible by the client.

like image 399
Anthony Avatar asked Sep 19 '19 08:09

Anthony


People also ask

Can we use API gateway with Kubernetes?

TL;DR: yes, you can. Have a look at the Kong, Ambassador and Gloo Ingress controllers. You can also use service meshes such as Istio API gateways, but you should be careful.

How does Kubernetes route traffic to pods?

By default, traffic sent to a ClusterIP or NodePort Service may be routed to any backend address for the Service. Kubernetes 1.7 made it possible to route "external" traffic to the Pods running on the same Node that received the traffic.

How do I access API from Kubernetes pod?

From inside the pod, kubernetes api server can be accessible directly on "https://kubernetes.default". By default it uses the "default service account" for accessing the api server. So, we also need to pass a "ca cert" and "default service account token" to authenticate with the api server.


2 Answers

You can use StatefulSets if you are not required to use deployment.

For replica 3, you will have 3 pods named

  1. stream-deployment-0
  2. stream-deployment-1
  3. stream-deployment-2

You can access each pod as $(podname).$(service name).$(namespace).svc.cluster.local

For details, check this

You may also want to set up an ingress to point each pod from outside of the cluster.

like image 116
Shahriar Avatar answered Oct 08 '22 12:10

Shahriar


As mentioned by aerokite, you can use StatefulSets. However, if you don't want to modify your deployments, you can simply use Headless Services. As specified in the documentation:

For headless Services, a cluster IP is not allocated.

For headless Services that define selectors, the endpoints controller creates Endpoints records in the API, and modifies the DNS configuration to return records (addresses) that point directly to the Pods backing the Service.

This means that whenever you query the DNS name for your Service (i.e. my-svc.my-namespace.svc.cluster-domain.example), what you get is a list of all the Pod IPs (unlike regular services where you get the cluster IP). You can then select your Pods using your own mechanisms.

Regarding your new question, if that is your only issue, you can use session affinity. If you set service.spec.sessionAffinity to ClientIP, then connections from a particular client will always go to the same Pod each time. You don't need other modifications like the headless Services mentioned above.

like image 33
Alassane Ndiaye Avatar answered Oct 08 '22 13:10

Alassane Ndiaye