3
votes

I have a StatefulSet with 3 pods. The first is assigned to the master role, the rest have a read replica role.

redis-0 (master)
redis-1 (replica)
redis-2 (replica)

How can I create a Kubernetes Service that matches only the pods redis-1 and redis-2? Basically I want to service that points only to the pods acting as replicas?

Logically what I want is to select every pod in the STS except the first. In pseudocode:

selector: app=redis-sts && statefulset.kubernetes.io/pod-name!=redis-0

Alternatively, selecting all the relevant pods could be viable. Again in psuedocode:

selector: statefulset.kubernetes.io/pod-name=redis-1 || statefulset.kubernetes.io/pod-name=redis-2

Here is the relevant YAML with the selectors & service defined. Full YAML.

apiVersion: v1
kind: Service
metadata:
  name: redis-service
spec:
  ports:
  - port: 6379
  clusterIP: None
  selector:
    app: redis-sts
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: redis-sts
  serviceName: redis-service
  replicas: 3
  template:
    metadata:
      labels:
        app: redis-sts
    spec:
# ...
3

3 Answers

1
votes

You may use pod name labels of your redis statefulset to create the service to access a particular read replica pod.

apiVersion: v1
kind: Service
metadata:
  name: redis-1
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  selector:
    statefulset.kubernetes.io/pod-name: redis-1
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379

And then use the service name for the pod to access the specific pods.

externalTrafficPolicy: Local will only proxy the traffic to the node that has the instance of your pod.

1
votes

The Service v1 API in 1.21 doesn't support the newer "set" based LabelSelector (matchLabels or matchExpressions)

You could write a controller to apply labels to the stateful set that can then meet the simple equality logic for Service selectors. There may be Redis operators that do this type of thing already.

An idea from this stateful set label question is to use an initContainer that has the pod write access to add the label.

1
votes

i would suggest to not be depends on the Kubernetes service as if your master pod got killer or restarted read replica can get change anytime in redis cluster.

https://github.com/harsh4870/Redis-Rejson-HA-Helm-Chart

here is the helm chart which deploys the Redis the same way one master and two read replica but with sentinel.

Your node or python code has to hit the service of Redis and in return redis sentinel will give you all the IP addresses for Mater and slave replicas.

Using that IP you can always connect to the Read replica and Master as per need.

If your cluster gets restarted or POD restarted master read replicas may get changed with time.