Kubernetes Service Concepts: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
Line 30: Line 30:
=Service Manifest=
=Service Manifest=
{{Internal|Kubernetes Service Manifest|Service Manifest}}
{{Internal|Kubernetes Service Manifest|Service Manifest}}
=Service=
=<span id='Service'></span>Service (ClusterIP Service)=
In its simplest form, a service is a [[Kubernetes API Resources Concepts#Service|Kubernetes API resource]] providing a single, stable [[Kubernetes_Networking_Concepts#Cluster_IP_Address|Cluster IP address]] and a set of ports that serve as point of entry to a group of pods providing the same service. A service that does not specify a type is by default a "ClusterIP" service.
In its simplest form, a service is a [[Kubernetes API Resources Concepts#Service|Kubernetes API resource]] providing a single, stable [[Kubernetes_Networking_Concepts#Cluster_IP_Address|Cluster IP address]] and a set of ports that serve as point of entry to a group of pods providing the same service. A service that does not specify a type is by default a "ClusterIP" service.



Revision as of 05:48, 20 September 2020

External

Internal

Playground

https://github.com/ovidiuf/playground/tree/master/kubernetes/httpd-pod-and-service

Overview

A service is a Kubernetes resource that provides stable network access to a set of ephemeral pods. The need for such a resource is explained in the Need for Services section. The simplest kind of service provides a stable Cluster IP address. More complex services, such as NodePort and LoadBalancer services, use ClusterIP services and expand their functionality. The services and the pods they are exposed are associated using labels and selectors. Once the logical association is declared, the Kubernetes cluster monitors the state of the pods and includes or excludes pods from the pod set exposed by the service. Other Kubernetes API resources, such as Endpoints, are involved in this process.

Need for Services

Most pods exist to serve requests sent over the network, so the pods' clients need to know how to open a network connection into the pod - they need an IP address and a port. This is true for clients external to the Kubernetes cluster, and also for pods running inside the cluster, which act as clients for other pods.

However, the pods are ephemeral, they come and go. If a pod fails, it is not resurrected, but its failure is detected as result of lack of response from the liveness probe embedded within it and another pod is usually scheduled as replacement. The pod does not need to fail to be removed, the removal can be the result of a normal scale-down operation. In consequence, the IP address of an individual pod cannot be relied on.

First off, the IP address is dynamically allocated to the pod at the time of pod initialization, after the pod has been scheduled to a node and before the pod is started, and secondly, the IP address becomes obsolete the moment the pod disappears. As such, it is practically very difficult, if not impossible for application's clients running outside the Kubernetes cluster, or even for other pods acting as clients to keep track of ephemeral pod IP addresses.

Multiple pods may be providing the same service, and each of them has its own IP address. The client must not be put in the position to have to chose a specific IP address and pod, they should not even need to know there are multiple pods providing the service.

The solution to all these problems is maintain an instance of a specialized resource, the service, for each of such group of pods. The service instance exposes a stable IP address and set of ports for the life of the service instance.

Service Manifest

Service Manifest

Service (ClusterIP Service)

In its simplest form, a service is a Kubernetes API resource providing a single, stable Cluster IP address and a set of ports that serve as point of entry to a group of pods providing the same service. A service that does not specify a type is by default a "ClusterIP" service.

The IP address will remain unchanged throughout the whole lifetime of the service. A client opens a network connection to the IP address and port, and the service load-balances the connection to one of the pods associated with it. Individual pods exposed by the service may come and go, and the service makes this transparent to the clients, as explained in the Associating a Service with Pods section.

Internal Kubernetes cluster clients, such as other pods, can use the service's IP address and ports to connect to the pods exposed by the service. This type of service is know as a ClusterIP service. Only internal clients can use a ClusterIP service, because the Cluster IP address is only routable from inside the Kubernetes cluster. Designating a service as a ClusterIP service by specifying spec.type=ClusterIP in the service's manifest is optional.

The pods may be scheduled on different physical Kubernetes nodes, but they are accessible to the service and each other via the virtual pod network.

Learning Kubernetes KubernetesServices ClusterIPService.png

The Cluster IP and the service's external port is reported by kubectl get svc:

NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
httpd-svc    ClusterIP   10.106.185.218   <none>        9898/TCP   43m
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP    3h26m

Service Port(s)

A service port designates a port exposed by the service externally. This is a port the service will be available on, and the value will be used by the external clients connecting to the service. It is declared with .spec.ports[*].port in the service manifest.

A service may expose more than one port, and the requests arrived on any of these ports will be forwarded to the corresponding configured target ports.

apiVersion: v1
kind: Service
spec:
  ports:
  - name: http
    port: 80            
    targetPort: 8080
  - name: https
    port: 443            
    targetPort: 8443
  ...

Note that the label selector applies to the service as a whole. It cannot be configured on a per-port basis. If different ports must map to a different subset of pods, different services must be created.

Port Name

When more than one port is specified for a service, a name must be specified for each port with .spec.ports[*].name, as shown in the above example. If there is just one port per service, the name element is optional.

Service Target Port

A target port represents the port exposed by a container from the pods associated with the service, as declared by the .spec.containers[*].ports array elements of the pod manifest. The service will forward requests over connections opened with this port as target. It is declared with .spec.ports[*].targetPort in the service manifest.

In most cases, an integral port value is used as .spec.ports[*].targetPort value, but it is also it is possible to name ports in the pod's manifest using .spec.containers[*].ports.name elements, and use those names as value for targetPort in the service definition:

apiVersion: v1
kind: Service
spec:
  ports:
  - name: http
    port: 80            
    targetPort: 'http'

The benefit of using names instead of port numbers is that the port numbers can be changed by the pods without changing the service spec.

Discovering ClusterIP Services inside the Cluster

A Kubernetes cluster automatically advertises its ClusterIP services throughout the cluster by publishing their name/IP address association as they come online. The potential clients can use two mechanism to learn the cluster IP address and ports associated with a specific service: environment variables and DNS.

Environment Variables

Any pod gets its environment automatically initialized by the cluster with special environment variables pointing to the IP address and ports for all services from the same namespace that exist at the moment of initialization. ⚠️ If a service comes on-line after a potential client pod has been deployed, the potential client pod's environment will not be updated.

The IP address of a service will be exposed as <SERVICE-NAME>_SERVICE_HOST and the port will be exposed as <SERVICE-NAME>_SERVICE_PORT, where all letters in the service name are uppercased and the dashes in the name are converted to underscores (some-service → SOME_SERVICE). If more than one port is declared for the service, the mandatory "name" element is uppercased and used to assemble the environment variable carrying the port value, following the pattern: <SERVICE-NAME>_SERVICE_PORT_<PORT-NAME>:

EXAMPLE_SERVICE_HOST=10.103.254.75
EXAMPLE_SERVICE_PORT_A=80
EXAMPLE_SERVICE_PORT_B=81

DNS

Session Affinity

With no additional configuration, successive requests to a service, even if they are made by the same client, will be forwarded to different pods, randomly. By default, there is no session affinity, and this corresponds to a .spec.sessionAffinity configuration of "None".

The only kind of session affinity that can be configured is "ClientIP": all requests made by a certain client, identified by its IP, are proxied to the same pod every time.

Services do not provide cookie-based session affinity because they operate at transport level (TCP/UDP) and do not inspect the payload carried by the packets. To have cookie-based session affinity, the proxy must be capable of understanding HTTP, which is not the case for services.

Kubernetes API Server Service

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

NodePort Service

LoadBalancer Service

ExternalName Service

Associating a Service with Pods

Service manifest - selector

Endpoints

"Endpoints" is a Kubernetes API resource.

Readiness Probe

Exposing Services to External Clients

Connecting to External Services from inside the Cluster

Kubernetes Service Concepts TODEPLETE

Service Operations