• Home
  • Docker
  • Kubernetes
  • Java
  • Ubuntu
  • Maven
  • Big Data
  • CI
  • Install
  • Samples
  • Archived
Kubernetes | Services (services|svc)
  1. Notes
  2. Services (services|svc)
  3. ClusterIP
  4. NodePort
  5. Expose a Service using the "kubectl expose" command
  6. Delete Services
  7. Kubernetes Service Discovery

  1. Notes
    Please visit these pages for more details about Services:
    https://kubernetes.io/docs/concepts/services-networking/service/
    https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
    https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/
    https://kubernetes.io/docs/concepts/security/controlling-access/
    https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
  2. Services (services|svc)
    Pods have their own unique IP addresses but these IP addresses are not reliable (if a Pod get rescheduled it might get a new IP address). For a large deployment, it will be hard to maintain and keep updated a list of all these IP addresses,.

    Kubernetes provides a solution that makes accessing the Pods easier and reliable. The Kubernetes Service is a special object that regroup a set of related Pods. A Kubernetes Service has a unique IP address (ClusterIP), DNS name, and Port that last for the life of the service. The Kubernetes Service load balance requests across its associated Pods.

    Kubernetes Service uses the Kubernetes Endpoints object (endpoints|ep) to manage Pods. For each service, an associated EndPoints object will be created. This object will keep updating the list of all the Pods that their labels match the Service's selector. Pods (coming from new deployment, scaling up an existing deployment) that their labels match the Service's label selector, will dynamically be added to the Endpoints object. If a Pod get updated (labels), become unhealthy (failure), or terminated (an existing deployment get deleted or rolled back), it will be removed from the Endpoints object. The EndPoints object will have the name of the Service.

    Linking Pods to a Service using labels and label selectors allow Pods to be loosely coupled with the Service. To be selected, a pod must define all the labels defined in the Service's label selector. A Pod can define more labels than the one defined in the Service's selector.

    The Service object allow you to specify the type (spec.type) of the Service you want. The possible values are:
    • ClusterIP (default):
      The Service (unique IP address, DNS name, and Port) will be, by default, only available within the cluster.

    • NodePort:
      Superset of ClusterIP. It also exposes a node port (TCP/UDP) that allow the Service to be available from outside the cluster.

    • LoadBalancer:
      Superset of NodePort. If supported, It creates an external load balancer in the cloud provider and assigns an external IP address to the Service.

    • ExternalName:
      Can be used when there's need to direct requests to applications running outside the Kubernetes cluster.

    "Headless" Service (spec.clusterIP set to none) is a special case of the ClusterIP Service. A query to the Service will return the Pods' IP addresses (no load balancing). Statefulset is a known use case where "Headless" Services are used.

    To create/deploy a Service, you need first to create a manifest YAML file. The manifest file describe the Service and its components (name, type, Ports, Selector, ...). You can use "kubectl" (or any rest client tool) to post the manifest file to the API server If applicable, the API server verifies that the request is authenticated, validates it's authorized, and runs the admission controllers on it. The API server verifies the manifest file and, if no issues, it writes a record for that manifest in the cluster store (etcd). The scheduler will then read the record and deploy the Pod of the Service to a healthy worker node with enough available resources.

    The same behaviour, described above, applies if you use the imperative command ("kubectl create") to create the Service.
  3. ClusterIP
    Let's define a simple Service:

    The Service defines a Selector (spec.selector): "app=hello-nginx"
    Pods that have all the labels defined in the Service's Selector will be selected.

    Let's apply now the Service:

    Check the Service:

    In the bellow Deployment example, the Pods will be selected because they define (spec.template.metadata.labels) the label "app=hello-nginx". The other labels of the Pods ("product=mtitek", "stage=dev") are not considered.

    Let's define a simple deployment:

    Let's apply the Deployment:

    Verify that Pods are running and ready (note the IP addresses of each Pod):

    Let's validate the Service (note that the Endpoints field contains the Pods' IP addresses):

    Check the Endpoints object of the Service (note the ENDPOINTS column):

    Describe the Endpoints object of the Service (note the Addresses field):

    To access the service from inside the cluster:
  4. NodePort
    The NodePort Service defines a node port on every node in the cluster. Requests from outside the cluster can target the node port of any cluster node to reach the Service. The NodePort Service will load balance requests to the Pods that are associated to it.

    Requests -> Cluster Node (NodePort) -> Service -> Pods

    Let's use the Deployment created previously (hello-nginx-deployment.yaml).

    Let's define a simple NodePort Service:

    Let's apply the Service:

    Check the Service:

    Let's validate that Service (note that the Endpoints field contains the Pods' IP addresses):

    Check the Endpoints object of the Service (note the ENDPOINTS column):

    Describe the Endpoints object of the Service (note the Addresses field):

    To access the service from inside the cluster, execute the same command we did above for the ClusterIP service (on port 80).

    To access the service from outside the cluster (note the node port 30080 and the IP address of the docker desktop VM):
  5. Expose a Service using the "kubectl expose" command
    You can use the "kubectl expose" command to create a Service object that exposes a Deployment.

    Let's use the Deployment created previously (hello-nginx-deployment.yaml).

    To expose the "hello-nginx"" Deployment:

    • The --name flag defines the name of the service.

    • The --port flag defines the port that the Service listens on inside the cluster.

    • The --target-port flag defines the port that the Pods are listening on.

    • The --type flag defines the service type.

    To get details about the Service, you can use the same commands explained above (kubectl get services, kubectl describe services).
  6. Delete Services
    To delete a Service: using manifest file (kubectl delete):

    To delete a Service using its name:
  7. Kubernetes Service Discovery
    Please see more details about Kubernetes DNS Service (and dnsutils utility) in this page: Kubernetes Cluster

    The Kubernetes DNS (controller) watches the API Server for new Services. When a new Service is created (get assigned a virtual IP address: ClusterIP), the Kubernetes DNS will automatically create the DNS records for the Service (the Service's name and IP address get registered with the cluster DNS).

    The fully qualified domain name (FQDN) of a Service will be created by combing the following data:
    • The Service name (metadata.name).
      This's also called the short name or the unqualified name of the Service (i.e. hello-nginx).

    • The namespace where the service is created.

    • The service type name (svc).

    • The cluster domain address (cluster.local).

    This can be represented as following: <SERVICE-NAME>.<NAMESPACE>.svc.cluster.local
    Example (Service: hello-nginx): hello-nginx.default.svc.cluster.local

    • A request to a Service from outside its namespace needs to use the Service's FQDN: hello-nginx.default.svc.cluster.local.

    • A request to a Service from inside its namespace can use the Service's name (short name or unqualified name): hello-nginx.

    It's also possible to use the Service's name concatenated with the namespace: hello-nginx.default.

    The nslookup command can be used to resolve the "hello-nginx" Service (you should get something like the following):

    When Pods are created, they are configured to know about the Kubernetes DNS (ClusterIP, search domains). This will allow Pods to query the Kubernetes DNS to resolve a service's name to its IP address.

    Kubernetes will configure each Pod's "/etc/resolv.conf" file with the IP address (nameserver) of the Kubernetes DNS Service and the search domains (search) that can be appended to the Services' unqualified names.
© 2025  mtitek