<p>I am trying to deploy a small <code>Node.js</code> server using <code>Kubernetes</code>. And I have exposed this app internally as well as externally using <code>ClusterIP</code> type service and <code>NodePort</code> type service respectively. </p>

<p>I can, without any problem connect internally to the app using <code>ClusterIP</code> service.</p>

<p><strong>Problem is I can't use <code>NodePort</code> service to connect to app</strong></p>

<p>I am running <code>curl</code> cmd the ClusterIP and NodePort from my <code>master</code> node. As mentioned, only the ClusterIP is working.</p>

<p>Here is my <code>deployment.yaml</code></p>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-test
spec:
  replicas: 2
  selector:
    matchLabels:
      name: deployment-test
  template:
    metadata:
      labels:
        # you can specify any labels you want here
        name: deployment-test
    spec:
      containers:
      - name: deployment-test
        # image must be the same as you built before (name:tag)
        image: banukajananathjayarathna/bitesizetroubleshooter:v1
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        imagePullPolicy: Always
      terminationGracePeriodSeconds: 60
</code></pre>

<p>And here is my 'clusterip.yaml`</p>

<pre><code>kind: Service
apiVersion: v1
metadata:
  labels:
    # these labels can be anything
    name: deployment-test-clusterip
  name: deployment-test-clusterip
spec:
  selector:
    name: deployment-test
  ports:
    - protocol: TCP
      port: 80
      # target is the port exposed by your containers (in our example 8080)
      targetPort: 8080
</code></pre>

<p>and here is <code>nodeport.yaml</code></p>

<pre><code>kind: Service
apiVersion: v1
metadata:
  labels:
    name: deployment-test-nodeport
  name: deployment-test-nodeport
spec:
  # this will make the service a NodePort service
  type: NodePort
  selector:
    name: deployment-test
  ports:
    - protocol: TCP
      # new -&gt; this will be the port used to reach it from outside
      # if not specified, a random port will be used from a specific range (default: 30000-32767)
      # nodePort: 32556
      port: 80
      targetPort: 8080
</code></pre>

<p>And here are my services:</p>

<pre class="lang-sh prettyprint-override"><code>$ kubectl get svc -n test49
NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
deployment-test-clusterip   ClusterIP   172.31.118.67   &lt;none&gt;        80/TCP         3d8h
deployment-test-nodeport    NodePort    172.31.11.65    &lt;none&gt;        80:30400/TCP   3d8h
</code></pre>

<p>When I try (from master) <code>$ curl 172.31.118.67</code>, then it gives <code>Hello world</code> as the output from the app.</p>

<p><strong>But</strong>, when I run <code>$ curl 172.31.11.65</code>, I get the following error:</p>

<pre class="lang-sh prettyprint-override"><code>$ curl 172.31.11.65
curl: (7) Failed to connect to 172.31.11.65 port 80: Connection refused
</code></pre>

<p>I even tried <code>$ curl 172.31.11.65:80</code> and <code>$ curl 172.31.11.65:30400</code>, it still gives the error.</p>

<p>Can someone please tell me what I have done wrong here?</p>

Jananath Banuka
<blockquote>
  <p>When I try (from master) <code>$ curl 172.31.118.67</code>, then it gives <code>Hello
  world</code> as the output from the app.</p>
</blockquote>

<p>It works because you exposed your deployment within the cluster using <a href="https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/#creating-a-service" rel="nofollow noreferrer">ClusterIP Service</a> which "listens" on port 80 on its <code>ClusterIP</code> (172.31.118.67). As the name says it is an IP available only within your cluster. If you want to expose your <code>Deployment</code> to so called external world you cannot do it using this <code>Service</code> type.</p>

<p>Generally you use <code>ClusterIP</code> to make your application component (e.g. set of backend <code>Pods</code>) available for other application components, in other words to expose it within your cluster. Good use case for <code>ClusterIP</code> service is exposing your database (which can be additionally clustered and run as a set of <code>Pods</code>) for backend <code>Pods</code> which need to connect to it, as a single endpoint.</p>

<blockquote>
  <p><strong>But</strong>, when I run <code>$ curl 172.31.11.65</code>, I get the following error:</p>
  
  <p><code>bash $ curl 172.31.11.65 curl: (7) Failed to connect to
    172.31.11.65 port 80: Connection refused</code></p>
</blockquote>

<p>Where are you trying to connect from ? It should be accessible from other <code>Pods</code> in your cluster as well as from your nodes. As @suren already mentioned in his answer, <code>NodePort</code> Service has all features of <code>ClusterIP</code> Service, but it additionally exposes your Deployment on some random port in range <code>30000-32767</code> on your Node's IP address (if another port within this range wasn't specified explicitly in <code>spec.ports.nodePort</code> in your <code>Service</code> definition). So basically any <code>Service</code> like <a href="https://kubernetes.io/docs/concepts/services-networking/service/#nodeport" rel="nofollow noreferrer">NodePort</a> or <a href="https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer" rel="nofollow noreferrer">LoadBalancer</a> has also its <code>ClusterIP</code>.</p>

<blockquote>
  <p>I even tried <code>$ curl 172.31.11.65:80</code> and <code>$ curl 172.31.11.65:30400</code>,
  it still gives the error.</p>
</blockquote>

<p><code>curl 172.31.11.65:80</code> should have exactly the same effect as <code>curl 172.31.11.65</code> as <code>80</code> is the default http port. Doing <code>curl 172.31.11.65:30400</code> is pointless as it is not "listening" on this port (Service is actually nothing more than set of iptables port-forwarding rules so in fact there is nothing really listening on this port) on its <code>ClusterIP</code>. This port is used only to expose your <code>Pods</code> on your worker nodes IP addresses. Btw. you can check them simply by running <code>ip -4 a</code> and searching through available network interfaces (applied if you have kubernetes on premise installation). If you are rather using some cloud environment, you will not see your nodes external IPs in your system e.g. in GCP you can see them on your Compute Engine VMs list in GCP console. Additionally you need to set appropriate firewall rules as by default traffic to some random ports is blocked. So after allowing TCP ingress traffic to port <code>30400</code>, you should be able to access your application on <code>http://&lt;any-of-your-k8s-cluster-worker-nodes-external-IP-address&gt;:30400</code></p>

<p><code>ip -4 a</code> will still show you the internal IP address of your node and you should be able to connect using <code>curl &lt;this-internal-ip&gt;:30400</code> as well as using <code>curl 127.0.0.1:30400</code> (from node) as by default <code>kube-proxy</code> considers all available network interfaces for <code>NodePort</code> Service:</p>

<blockquote>
  <p>The default for --nodeport-addresses is an empty list. This means that
  kube-proxy should consider all available network interfaces for
  NodePort.</p>
</blockquote>

<p>If you primarily want to expose your Deployment to external world and you want it to be available on standard port I would recommend you using <a href="https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer" rel="nofollow noreferrer">LoadBalancer</a> rather than <code>NodePort</code>. If you use some cloud environment it is available out of the box and you can easily define it as any other Service type without a need of additional configuration. If you have on-prem k8s installation you'll need to resort to some additional sollution such as <a href="https://metallb.universe.tf/" rel="nofollow noreferrer">MetalLB</a>.</p>

<p>Let me know if it clarified a bit using <code>Service</code> in kubernetes. It's still not completely clear to me what you want to achieve so it would be nice if you explain it in more detail.</p>
