DEV Community

Sina Tavakkol
Sina Tavakkol

Posted on

40 Days Of Kubernetes (9/40)

Day 9/40

Kubernetes Services Explained - ClusterIP vs NodePort vs Loadbalancer vs External

Video Link
@piyushsachdeva
Git Repository
My Git Repo

We're going to look at service in kubernetes and its types as below list:

  1. ClusterIP
  2. NodePort
  3. LoadBalancer
  4. External Name

The goal is to expose our front-end app to users, we use service and its benefits.
As you can see in the below diagram, we are using service anywhere which it makes sure there is at least one pod serving and listening on specific port in our cluster and it's accessible only to what we specified.
Image description
(Photo from the video)

1. Node Port

Image description
(Photo from the video)
These services are ideal for applications that need to be accessible from outside the cluster, such as web applications or APIs. With NodePort services, we can access our application using the nodeโ€™s IP address and the port number assigned to the service.
When we create a NodePort service, Kubernetes assigns a port number from a predefined range of 30000-32767.(source)

There are 3 ports to define:

  1. nodePort - for external users
  2. port - for internal clients
  3. targetPort - container port Image description (Photo from the video) multi-pod scenario Image description (Photo from the video)

Implementing

root@localhost:~# kubectl get nodes
NAME                       STATUS   ROLES           AGE   VERSION
lucky-luke-control-plane   Ready    control-plane   4d    v1.30.0
lucky-luke-worker          Ready    <none>          4d    v1.30.0
lucky-luke-worker2         Ready    <none>          4d    v1.30.0

Enter fullscreen mode Exit fullscreen mode
apiVersion: v1

kind: Service

metadata:
  name: nodeport-svc
  labels:
    env: demo

spec:
  selector:
      env: demo
  type:
    NodePort
  ports:
    - nodePort: 30001
      port: 80
      targetPort: 80
Enter fullscreen mode Exit fullscreen mode
root@localhost:~# kubectl apply -f nodeport.yaml
service/nodeport-svc created
root@localhost:~# kubectl get svc
NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
kubernetes     ClusterIP   10.96.0.1     <none>        443/TCP        4d
nodeport-svc   NodePort    10.96.37.68   <none>        80:30001/TCP   15s
root@localhost:~# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE   SELECTOR
kubernetes     ClusterIP   10.96.0.1     <none>        443/TCP        4d    <none>
nodeport-svc   NodePort    10.96.37.68   <none>        80:30001/TCP   23s   env=demo
Enter fullscreen mode Exit fullscreen mode

Note because we are using the kind for creating our cluster, we need to do extra step to expose our port outside the kind.
Mapping ports to the host machine
It needs recreating the cluster because of:
"It's not said explicitly in the official docs, but I found some references that confirm: your thoughts are correct and changing extraPortMappings (as well as other cluster settings) is only possible with recreation of the kind cluster."
source
So our kind cluster would be:

# three node (two workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30001
    hostPort: 30001
- role: worker
- role: worker
Enter fullscreen mode Exit fullscreen mode
  • Delete the current cluster
root@localhost:~# kind delete cluster --name `kind get clusters`
Deleting cluster "lucky-luke" ...
Deleted nodes: ["lucky-luke-control-plane" "lucky-luke-worker2" "lucky-luke-worker"]
Enter fullscreen mode Exit fullscreen mode
  • Create the cluster again with new feature
root@localhost:~# kind create cluster --config kind-lucky-luke.yaml --name lucky-luke
Creating cluster "lucky-luke" ...
 โœ“ Ensuring node image (kindest/node:v1.30.0) ๐Ÿ–ผ
 โœ“ Preparing nodes ๐Ÿ“ฆ ๐Ÿ“ฆ ๐Ÿ“ฆ
 โœ“ Writing configuration ๐Ÿ“œ
 โœ“ Starting control-plane ๐Ÿ•น๏ธ
 โœ“ Installing CNI ๐Ÿ”Œ
 โœ“ Installing StorageClass ๐Ÿ’พ
 โœ“ Joining worker nodes ๐Ÿšœ
Set kubectl context to "kind-lucky-luke"
You can now use your cluster with:

kubectl cluster-info --context kind-lucky-luke

Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community ๐Ÿ™‚
Enter fullscreen mode Exit fullscreen mode

Agian with our cluster:

root@localhost:~# kind get clusters
lucky-luke
root@localhost:~# kubectl get nodes
NAME                       STATUS   ROLES           AGE     VERSION
lucky-luke-control-plane   Ready    control-plane   9m14s   v1.30.0
lucky-luke-worker          Ready    <none>          8m47s   v1.30.0
lucky-luke-worker2         Ready    <none>          8m47s   v1.30.0
Enter fullscreen mode Exit fullscreen mode
  • Create deployment (in day 8/40):
---
apiVersion: apps/v1

kind: Deployment

metadata:
  name: nginx-deploy
  labels:
    env: demo

spec:
  template:
    metadata:
      name: nginx-pod
      labels:
        env: demo
        type: frontend

    spec:
      containers:
      - name: nginx-container
        image: nginx
        ports:
          - containerPort: 80

  replicas: 3
  selector:
    matchLabels:
      env: demo
Enter fullscreen mode Exit fullscreen mode
root@localhost:~# kubectl create -f day08-deploy.yaml
deployment.apps/nginx-deploy created
root@localhost:~# kubectl get all
NAME                                READY   STATUS    RESTARTS   AGE
pod/nginx-deploy-6bfd44d944-dlfcf   1/1     Running   0          71s
pod/nginx-deploy-6bfd44d944-rgmjn   1/1     Running   0          71s
pod/nginx-deploy-6bfd44d944-tpvfz   1/1     Running   0          71s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   14m

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deploy   3/3     3            3           71s

NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deploy-6bfd44d944   3         3         3       71s
Enter fullscreen mode Exit fullscreen mode
  • Create service:
root@localhost:~# kubectl apply -f nodeport.yaml
service/nodeport-svc created
root@localhost:~# kubectl get all
NAME                                READY   STATUS    RESTARTS   AGE
pod/nginx-deploy-6bfd44d944-dlfcf   1/1     Running   0          2m33s
pod/nginx-deploy-6bfd44d944-rgmjn   1/1     Running   0          2m33s
pod/nginx-deploy-6bfd44d944-tpvfz   1/1     Running   0          2m33s

NAME                   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/kubernetes     ClusterIP   10.96.0.1      <none>        443/TCP        15m
service/nodeport-svc   NodePort    10.96.145.18   <none>        80:30001/TCP   7s

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deploy   3/3     3            3           2m33s

NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deploy-6bfd44d944   3         3         3       2m33s
Enter fullscreen mode Exit fullscreen mode
  • Check the service:
root@localhost:~# kubectl describe svc nodeport-svc
Name:                     nodeport-svc
Namespace:                default
Labels:                   env=demo
Annotations:              <none>
Selector:                 env=demo
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.96.145.18
IPs:                      10.96.145.18
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30001/TCP
Endpoints:                10.244.1.4:80,10.244.2.3:80,10.244.2.4:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
Enter fullscreen mode Exit fullscreen mode
  • Current state:
root@localhost:~# kubectl get pod,deploy,svc --show-labels -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP           NODE                 NOMINATED NODE   READINESS GATES   LABELS
pod/nginx-deploy-c95b4f658-gj6jl   1/1     Running   0          47s   10.244.2.4   lucky-luke-worker2   <none>           <none>            env=demo,pod-template-hash=c95b4f658,type=frontend
pod/nginx-deploy-c95b4f658-nc2qg   1/1     Running   0          47s   10.244.1.4   lucky-luke-worker    <none>           <none>            env=demo,pod-template-hash=c95b4f658,type=frontend
pod/nginx-deploy-c95b4f658-nfgrn   1/1     Running   0          47s   10.244.2.3   lucky-luke-worker2   <none>           <none>            env=demo,pod-template-hash=c95b4f658,type=frontend

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS        IMAGES   SELECTOR   LABELS
deployment.apps/nginx-deploy   3/3     3            3           47s   nginx-container   nginx    env=demo   env=demo

NAME                   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE    SELECTOR   LABELS
service/kubernetes     ClusterIP   10.96.0.1      <none>        443/TCP        21m    <none>     component=apiserver,provider=kubernetes
service/nodeport-svc   NodePort    10.96.145.18   <none>        80:30001/TCP   6m5s   env=demo   env=demo

Enter fullscreen mode Exit fullscreen mode
  • Check the service from our local:
root@localhost:~# curl localhost:30001
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

2. Cluster IP

Because every pod which is restarted has got another IP address, we need to create a clusterIP service type. It's default service type in Kubernetes. We only need port and targetPort in its yaml configuration file.
selector section is related to deployment label.
Image description
(Photo from the video)

Implementation

apiVersion: v1

kind: Service

metadata:
  name: clusterip-svc
  labels:
    env: demo

spec:
  selector:
      env: demo
  type:
    ClusterIP
  ports:
    - port: 80
      targetPort: 80

Enter fullscreen mode Exit fullscreen mode
root@localhost:~# kubectl apply -f clusterip.yaml
service/clusterip-svc created
root@localhost:~# kubectl get svc
NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
clusterip-svc   ClusterIP   10.96.242.10   <none>        80/TCP         6s
kubernetes      ClusterIP   10.96.0.1      <none>        443/TCP        67m
nodeport-svc    NodePort    10.96.145.18   <none>        80:30001/TCP   51m
root@localhost:~# kubectl get svc --show-labels -o wide
NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE   SELECTOR   LABELS
clusterip-svc   ClusterIP   10.96.242.10   <none>        80/TCP         23s   env=demo   env=demo
kubernetes      ClusterIP   10.96.0.1      <none>        443/TCP        67m   <none>     component=apiserver,provider=kubernetes
nodeport-svc    NodePort    10.96.145.18   <none>        80:30001/TCP   51m   env=demo   env=demo
root@localhost:~# kubectl describe svc clusterip-svc
Name:              clusterip-svc
Namespace:         default
Labels:            env=demo
Annotations:       <none>
Selector:          env=demo
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.96.242.10
IPs:               10.96.242.10
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.4:80,10.244.2.3:80,10.244.2.4:80
Session Affinity:  None
Events:            <none>
root@localhost:~# kubectl get endpoints
NAME            ENDPOINTS                                   AGE
clusterip-svc   10.244.1.4:80,10.244.2.3:80,10.244.2.4:80   3m25s
kubernetes      172.19.0.2:6443                             70m
nodeport-svc    10.244.1.4:80,10.244.2.3:80,10.244.2.4:80   54m

Enter fullscreen mode Exit fullscreen mode

3. Load Balancer

LoadBalancer services are ideal for applications that need to handle high traffic volumes, such as web applications or APIs. With LoadBalancer services, we can access our application using a single IP address assigned to the load balancer.source
Image description
(Photo from the video)

Implementation

apiVersion: v1

kind: Service

metadata:
  name: loadbalancer-svc
  labels:
    env: demo

spec:
  selector:
      env: demo
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80
Enter fullscreen mode Exit fullscreen mode
root@localhost:~# kubectl apply -f loadbalancer.yaml
service/loadbalancer-svc created
root@localhost:~# kubectl get svc
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
clusterip-svc      ClusterIP      10.96.242.10    <none>        80/TCP         12m
kubernetes         ClusterIP      10.96.0.1       <none>        443/TCP        80m
loadbalancer-svc   LoadBalancer   10.96.153.185   <pending>     80:31076/TCP   7s
nodeport-svc       NodePort       10.96.145.18    <none>        80:30001/TCP   64m
root@localhost:~# kubectl get all
NAME                               READY   STATUS    RESTARTS   AGE
pod/nginx-deploy-c95b4f658-gj6jl   1/1     Running   0          59m
pod/nginx-deploy-c95b4f658-nc2qg   1/1     Running   0          59m
pod/nginx-deploy-c95b4f658-nfgrn   1/1     Running   0          59m

NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/clusterip-svc      ClusterIP      10.96.242.10    <none>        80/TCP         13m
service/kubernetes         ClusterIP      10.96.0.1       <none>        443/TCP        80m
service/loadbalancer-svc   LoadBalancer   10.96.153.185   <pending>     80:31076/TCP   15s
service/nodeport-svc       NodePort       10.96.145.18    <none>        80:30001/TCP   64m

NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deploy   3/3     3            3           59m

NAME                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deploy-c95b4f658   3         3         3       59m

Enter fullscreen mode Exit fullscreen mode

As we can see, EXTERNAL-IP for our LoadBalancer service type is <pending>. This is what we can provide an IP Address or DNS name for our users, and yer we don't have provision them in the service and it behaves as a NodePort service.
For more info


4. External Name

We actually map it to a DNS.
The below sample is from official documentation.source

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com
Enter fullscreen mode Exit fullscreen mode

5. Creating service in command-line

Syntax:

kubectl create nodeport NAME [--tcp=port:targetPort] [--dry-run=server|client|none]

Example

kubectl create service nodeport myservice --node-port=31000 --tcp=3000:80
Enter fullscreen mode Exit fullscreen mode

6. Useful links

Top comments (0)