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

9/19/2019

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.

-- Anthony
kubernetes
kubernetes-ingress
kubernetes-pod

3 Answers

9/19/2019

IMO, the only way to achieve this will be:

  1. Instead of using a deployment with 3 replicas, use 3 deployments with 1 replicas each (or just create pods only); deployment1 -> pod1, deployment2 -> pod2, deployment3 -> pod3
  2. Expose all the deployments on a separate service, service1 -> deployment1, service2 -> deployment2, service3 -> deployment3
  3. Create an ingress resource and route to each pod using the service for each deployment. For example:
    • ingress-url/service1
    • ingress-url/service2
    • ingress-url/service3
-- Junaid
Source: StackOverflow

9/19/2019

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.

-- Mir Shahriar Sabuj
Source: StackOverflow

9/19/2019

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.

-- Alassane Ndiaye
Source: StackOverflow