Search code examples
kuberneteskubernetes-servicekubernetes-deployment

How do I get more control over the NodePorts my Service assigns to my Deployment?


I have a Deployment with 5 replicas. All have ssh and telnet. They should not be load balanced. I would like each to select from a predictable list of 5.

Here is my Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  selector:
    matchLabels:
      app: myapp
  replicas: 5
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:1.0
        ports:
        - name: ssh
          protocol: TCP
          containerPort: 22
        - name: telnet
          protocol: TCP
          containerPort: 23

This is my Service with invalid nodePort values for illustrative purposes.

apiVersion: v1
kind: Service
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  type: NodePort
  ports:
  - name: ssh
    port: 22
    nodePort: [30022, 30122, 30222, 30322, 30422, 30522]
  - name: telnet
    port: 23
    nodePort: [30023, 30123, 30223, 30323, 30423, 30523]

I am hoping to be able to accomplish 2 things:

  1. Each pod replica instance will only get an ssh port from [30022, 30122, 30222, 30322, 30422, 30522] and a telnet port from [30023, 30123, 30223, 30323, 30423, 30523]
  2. A pod replica instance that gets an ssh port of 30022 also gets the telnet port 30023. A pod replica instance that gets an ssh port of 30122 gets a telnet port of 30123 and so on.

Thank you!


Solution

  • You can use a StatefulSet instead of a Deployment:

    Like a Deployment, a StatefulSet manages Pods that are based on an identical container spec. Unlike a Deployment, a StatefulSet maintains a sticky identity for each of their Pods. These pods are created from the same spec, but are not interchangeable: each has a persistent identifier that it maintains across any rescheduling.

    The particularly useful feature of StatefulSets is that you will get a unique label predictably generated for each pod:

    When the StatefulSet controller creates a Pod, it adds a label, statefulset.kubernetes.io/pod-name, that is set to the name of the Pod. This label allows you to attach a Service to a specific Pod in the StatefulSet. [source]

    Then you would create five distinct Services, one for each pod, of the following form:

    apiVersion: v1
    kind: Service
    metadata:
      name: myapp-${n}
      labels: { ... } # whatever you want
    spec:
      type: NodePort
      selector: 
        statefulset.kubernetes.io/pod-name: myapp-${n} # assuming you keep the name
                                                       # "myapp" and just switch kind
                                                       # from Deployment to StatefulSet
      ports:
      - name: ssh
        port: 22
        nodePort: 30${n}22
      - name: telnet
        port: 23
        nodePort: 30${n}23
    

    replacing ${n} with 0 through 4.