Kubernetes Services: ClusterIP, Nodeport and LoadBalancer
Tags: kubernetes, services
Published: 2022-12-09 10:03:19

---
title: Kubernetes Services: ClusterIP, Nodeport and LoadBalancer
published: true
description: Your Kubernetes Pods have internal IPs, but, can since Pods are created and destroyed, can you rely on those? Discover Services and its types: ClusterIP, NodePort and LoadBalancer

tags: kubernetes, services
cover_image: https://sysdig.com/wp-content/uploads/Kubernetes-services-00.png
canonical_url: https://sysdig.com/blog/kubernetes-services-clusterip-nodeport-loadbalancer/
# Use a ratio of 100:42 for best results.
---

<!-- wp:paragraph -->
<p>Pods are ephemeral. And they are meant to be. They can be seamlessly destroyed and replaced if using a Deployment. Or they can be scaled at some point when using Horizontal Pod Autoscaling (HPA).</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This means we can’t rely on the Pod IP address to connect with applications running in our containers internally or externally, as the Pod might not be there in the future.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You may have noticed that Kubernetes Pods get assigned an IP address:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">stable-kube-state-metrics-758c964b95-6fnbl               1/1     Running   0          3d20h   100.96.2.5      ip-172-20-54-111.ec2.internal   &lt;none&gt;           &lt;none&gt;
stable-prometheus-node-exporter-4brgv                    1/1     Running   0          3d20h   172.20.60.26    ip-172-20-60-26.ec2.internal
</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>This is a unique and internal IP for this particular Pod, but there’s no guarantee that this IP will exist in the future, due to the Pod's nature.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Services</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>A <strong>Kubernetes Service</strong> is a mechanism to <strong>expose applications both internally and externally</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Every service will create an everlasting IP address that can be used as a connector.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Additionally, it will open a <code>port</code> that will be linked with a <code>targetPort</code>. Some services can create ports in every <a href="https://sysdig.com/learn-cloud-native/kubernetes-101/what-is-a-kubernetes-node/" target="_blank" rel="noreferrer noopener">Node</a>, and even external IPs to create connectors outside the cluster.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>With the combination of both IP and Port, we can create a way to uniquely identify an application.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Creating a service</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Every service has a selector that filters that will link it with a set of Pods in your cluster.</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">spec:
  selector:
    app.kubernetes.io/name: myapp
</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>So all Pods with the label <em>myapp</em> will be linked to this service.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>There are three port attributes involved in a Service configuration:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30036
    protocol: TCP
</pre>
<!-- /wp:preformatted -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li>port: the new service port that will be created to connect to the application.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>targetPort: application port that we want to target with the services requests.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>nodePort: this is a port in the range of 30000-32767 that will be open in each node. If left empty, Kubernetes selects a free one in that range.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>protocol: TCP is the default one, but you can use others like SCTP or UDP.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>You can review services created with:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">kubectl get services
kubectl get svc
</pre>
<!-- /wp:preformatted -->

<!-- wp:heading {"level":3} -->
<h3>Types of services</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Kubernetes allows the creation of these types of services:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li>ClusterIP (default)</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Nodeport</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>LoadBalancer</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>ExternalName</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Let’s see each of them in detail.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>ClusterIP</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>This is the default type for service in Kubernetes.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>As indicated by its name, this is just an address that can be used inside the cluster.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Take, for example, the initial helm installation for Prometheus Stack. It installs Pods, Deployments, and Services for the Prometheus and Grafana ecosystem.</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">NAME                                      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
alertmanager-operated                     ClusterIP   None            &lt;none&gt;        9093/TCP,9094/TCP,9094/UDP   3m27s
kubernetes                                ClusterIP   100.64.0.1      &lt;none&gt;        443/TCP                      18h
prometheus-operated                       ClusterIP   None            &lt;none&gt;        9090/TCP                     3m27s
stable-grafana                            ClusterIP   100.66.46.251   &lt;none&gt;        80/TCP                       3m29s
stable-kube-prometheus-sta-alertmanager   ClusterIP   100.64.23.19    &lt;none&gt;        9093/TCP                     3m29s
stable-kube-prometheus-sta-operator       ClusterIP   100.69.14.239   &lt;none&gt;        443/TCP                      3m29s
stable-kube-prometheus-sta-prometheus     ClusterIP   100.70.168.92   &lt;none&gt;        9090/TCP                     3m29s
stable-kube-state-metrics                 ClusterIP   100.70.80.72    &lt;none&gt;        8080/TCP                     3m29s
stable-prometheus-node-exporter           ClusterIP   100.68.71.253   &lt;none&gt;        9100/TCP                     3m29s
<br><br></pre>
<!-- /wp:preformatted -->

<!-- wp:image {"id":62964,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://sysdig.com/wp-content/uploads/Kubernetes-services-01-1170x644.png" alt="Kubernetes Services ClusterIP" class="wp-image-62964"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>This creates a connection using an internal Cluster IP address and a Port.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>But, what if we need to use this connector from outside the Cluster? This IP is internal and won’t work outside.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This is where the rest of the services come in…</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>NodePort</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>A NodePort differs from the ClusterIP in the sense that it exposes a port in each Node.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>When a NodePort is created, kube-proxy exposes a port in the range 30000-32767:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  selector:
  	app: myapp
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30036
    protocol: TCP</pre>
<!-- /wp:preformatted -->

<!-- wp:image {"id":62965,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://sysdig.com/wp-content/uploads/Kubernetes-services-02-1170x644.png" alt="Kubernetes Services Nodeport" class="wp-image-62965"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>NodePort is the preferred element for non-HTTP communication.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The problem with using a NodePort is that you still need to access each of the Nodes separately.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>So, let’s have a look at the next item on the list…</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>LoadBalancer</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>A LoadBalancer is a Kubernetes service that:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li>Creates a service like ClusterIP</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Opens a port in every node like NodePort</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>Uses a LoadBalancer implementation from your cloud provider (your cloud provider needs to support this for LoadBalancers to work).</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - name: web
    port: 80
  selector:
    app: web
  type: LoadBalancer
my-service                                LoadBalancer   100.71.69.103   &lt;pending&gt;     80:32147/TCP                 12s
my-service                                LoadBalancer   100.71.69.103   a16038a91350f45bebb49af853ab6bd3-2079646983.us-east-1.elb.amazonaws.com   80:32147/TCP                 16m
</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>In this case, Amazon Web Service (AWS) was being used, so an external IP from AWS was created.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Then, if you use <code>kubectl describe my-service</code>, you will find that several new attributes were added:</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">Name:                     my-service
Namespace:                default
Labels:                   &lt;none&gt;
Annotations:              &lt;none&gt;
Selector:                 app.kubernetes.io/name=pegasus
Type:                     LoadBalancer
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       100.71.69.103
IPs:                      100.71.69.103
LoadBalancer Ingress:     a16038a91350f45bebb49af853ab6bd3-2079646983.us-east-1.elb.amazonaws.com
Port:                     &lt;unset&gt;  80/TCP
TargetPort:               9376/TCP
NodePort:                 &lt;unset&gt;  32147/TCP
Endpoints:                &lt;none&gt;
Session Affinity:         None
External Traffic Policy:  Cluster
</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>The main difference with NodePort is that LoadBalancer can be accessed and will try to equally assign requests to Nodes.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":62967,"sizeSlug":"large","linkDestination":"none"} -->
<figure class="wp-block-image size-large"><img src="https://sysdig.com/wp-content/uploads/Kubernetes-services-03-1170x644.png" alt="Kubernetes Service LoadBalancer" class="wp-image-62967"/></figure>
<!-- /wp:image -->

<!-- wp:heading -->
<h2>ExternalName</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The ExternalName service was introduced due to the need of connecting to an element outside of the Kubernetes cluster. Think of it not as a way to connect to an item within your cluster, but as a connector to an external element of the cluster.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This serves two purposes:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li>It creates a single endpoint for all communications to that element.</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>In case that external service needs to be replaced, it’s easier to switch by just modifying the ExternalName, instead of all connections.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
    - name: web
      port: 80
  selector:
    app: web
  type: ExternalName
  externalName: db.myexternalserver.com
</pre>
<!-- /wp:preformatted -->

<!-- wp:heading -->
<h2>Conclusion</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Services are a key aspect of Kubernetes, as they provide a way to expose internal endpoints inside and outside of the cluster.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>ClusterIP service just creates a connector for in-node communication. Use it only in case you have a specific application that needs to connect with others in your node.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>NodePort and LoadBalancer are used for external access to your applications. It’s preferred to use LoadBalancer to equally distribute requests in multi-pod implementations, but note that your vendor should implement load balancing for this to be available.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Apart from these, Kubernetes provides Ingresses, a way to create an HTTP connection with load balancing for external use.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->

<!-- wp:separator -->
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<!-- /wp:separator -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<div class="sysdig-box" style="background-color: #f8f8f8; padding: 2em;">
<h2 style="margin-top: 0;"><em>Debug service golden signals with Sysdig Monitor</em></h2>
<p>With Sysdig Monitor, you can quickly debug:</p>
<ul>
<li>Error rate</li>
<li>Saturation</li>
<li>Traffic</li>
<li>Latency</li>
</ul>
<p>And thanks to its Container Observability with eBPF, you can do this without adding any app or code instrumentation.

Sysdig Advisor accelerates mean time to resolution (MTTR) with live logs, performance data, and suggested remediation steps. It’s the easy button for Kubernetes troubleshooting!</p>
<figure><a https:="" sysdig.com="" wp-content="" uploads="" image-3-1.png"=""><img src="https://sysdig.com/wp-content/uploads/image-3-1.png" alt="How to debug a crashloopbackoff with Sysdig Monitor Advisor" width="1438" height="899" class="aligncenter size-full wp-image-53165"></a></figure>
<p>Sign up now for a <a href="https://sysdig.com/company/free-trial-monitor/" class="gtmbgmonpop" target="_blank" rel="noopener">free trial of Sysdig Monitor</a></p>
</div>
<!-- /wp:html -->