<p>I am trying to set up access to Pods on multiple Nodes with a single Service yaml. The Pods all have the same label (say, <code>label:app</code>), but are distributed across several Nodes, instead of on a single Node.</p>
<p>As far as I know, I can set up a Service to forward access to a Pod through a NodePort, like:</p>
<pre><code>spec:
  type: NodePort
  selector:
    label: app
  ports:
    targetPort: 5000
    nodePort: 30000 

</code></pre>
<p>where accessing port 30000 on a node forwards to port 5000 on the pod.</p>
<p>If I have pods on multiple nodes, is there a way a client can access a single endpoint, e.g. the Service itself, to get any pod in round-robin? Or does a client need to access a set of pods on a specific node, using that node's IP, as in <code>xx.xx.xx.xx:30000</code>?</p>

<p>Although <a href="https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer" rel="noreferrer">LoadBalancer</a> is an undeniably recommended solution (especially in cloud environment), it's worth mentioning that <a href="https://kubernetes.io/docs/concepts/services-networking/service/#nodeport" rel="noreferrer">NodePort</a> also has <strong>load balancing capabilities</strong>.</p>
<p>The fact that you're accessing your <code>NodePort</code> Service on a particular node doesn't mean that you are able to access this way only <code>Pods</code> that have been scheduled on that particular node.</p>
<p>As you can read in <code>NodePort</code> Service <a href="https://kubernetes.io/docs/concepts/services-networking/service/#nodeport" rel="noreferrer">specification</a>:</p>
<blockquote>
<p>Each node proxies that port (the same port number on every Node)
into your <code>Service</code>.</p>
</blockquote>
<p>So by accessing port <code>30080</code> on one particular node your request is not going directly to some random <code>Pod</code>, scheduled on that node. It is proxied to the <code>Service</code> object which is an abstraction that spans across all nodes. And this is probably the key point here as your <code>NodePort</code> Service isn't tied in any way to the node, IP of which you use to access your pods.</p>
<p>Therefore <code>NodePort</code> Service is able to route client requests to all pods across the cluster using simple <strong>round robin algorithm</strong>.</p>
<p>You can verify it easily using the following <code>Deployment</code>:</p>
<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      initContainers:
      - name: init-myservice
        image: nginx:1.14.2
        command: ['sh', '-c', &quot;echo $MY_NODE_NAME &gt; /usr/share/nginx/html/index.html&quot;]
        env:
        - name: MY_NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: cache-volume
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: cache-volume
      volumes:
      - name: cache-volume
        emptyDir: {}
</code></pre>
<p>This will allow you to test to which node your http request is going to. You may additionally need to scale a bit this <code>Deployment</code> to make sure that all nodes are used:</p>
<pre><code>kubectl scale deployment nginx-deployment --replicas=9
</code></pre>
<p>Then verify that your pods are scheduled on different nodes:</p>
<pre><code>kubectl get pods -o wide
</code></pre>
<p>List all your nodes:</p>
<pre><code>kubectl get nodes -o wide
</code></pre>
<p>and pick the IP address of a node that you want to use to access your pods.</p>
<p>Now you can expose the <code>Deployment</code> by running:</p>
<pre><code>kubectl expose deployment nginx-deployment --type NodePort --port 80 --target-port 80
</code></pre>
<p>or if you want to specify the port number by yourself e.g. as <code>30080</code>, apply the following <code>NodePort</code> Service definition as <code>kubectl expose</code> doesn't allow you to specify the exact <code>nodePort</code> value:</p>
<pre><code>apiVersion: v1
kind: Service
metadata:
  name: nginx-deployment
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080
</code></pre>
<p>Then try to access your pods exposed via <code>NodePort</code> Service using IP of the previously chosen node. You may need to try both normal and private/incognito modes or even different browser (simple refresh may not work) but eventually you will see that different requests land on pods scheduled on different nodes.</p>
<p>Keep in mind that if you decide to use <code>NodePort</code> you won't be able to use <strong>well known ports</strong>. Actually it might be even feasible as you may change the default port range (<code>30000-32767</code>) to something like <code>1-1024</code> in <a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/" rel="noreferrer">kube-apiserver</a> configuration by using <code>--service-node-port-range</code> option but its not recommended as it might lead to some unexpected issues.</p>
