Service is the core concept of the k8s networking part, and in k8s, Service is mainly responsible for four layers of load balancing. This article explains the network-related principles of k8s in terms of load balancing, extranet access, DNS service construction, and the Ingress seven-layer routing mechanism.
Service is the main mechanism used to implement the application to provide services to the outside world.
As shown in the figure above, Service is a layer of abstraction for Pod, mainly through TCP/IP mechanism and listening IP and port number to provide services to the outside world. Unlike Pods, once a Service is created, the system distributes a ClusterIP for it (or you can specify it yourself), and it will not change during its lifetime.
Command Line Quick Creation
After creating an RC, you can quickly create a corresponding Service by using the command line
kubectl expose. For example, there is now an rc named hdls.
The ClusterIP of a Service created in this way is automatically assigned to it, and the port number of the Service is copied from the containerPort in the Pod.
created via YAML
Once the YAML file is defined, it can be created with the command
kubectl create -f <service.yml>. The Service definition requires the following key fields to be specified.
- port: the virtual port of the Service.
- targetPort: The port number of the backend Pod, if not filled in, it will be the same as the Service’s port by default.
- selector: Label selector, specifying the Label owned by the backend Pod.
Load Distribution Policies
k8s provides two load distribution strategies.
- RoundRobin: Polling method. That is, polling to forward requests to each Pod on the backend.
- SessionAffinity: Session holding mode based on client IP address. That is, requests from clients with the same IP address are forwarded to the same Pod.
By default, k8s uses polling mode for routing. However, we can also enable SessionAffinity mode by setting “service.spec.SessionAffinity” to ClusterIP.
Some special cases
In this case, k8s is implemented through the concept of Headless Service, where the Service is not given a ClusterIP (no ingress IP) and only the list of back-end Pods is returned to the calling client via Label Selector.
The Service does not have a virtual ClusterIP and access to it can get a list of all Pods with
app=hdls, the client needs to implement its own responsible balancing policy and then determine which Pod to access.
No LabelSelector Service.
Typically, applications need to connect to an external database as a backend service, or a service in another cluster or namespace as a backend service. In these cases, this can be achieved by creating a Service without Label Selector.
The Service does not have a tag selector, i.e., it cannot select a backend Pod; in this case, the Endpoint is not created automatically, and an Endpoint with the same name as the Service needs to be created manually to point to the actual backend access address.
In this case, the Endpoint is created as in the YAML above, and accessing the Service without Label Selector routes the request to the user-specified Endpoint.
Define multiple ports in service.spec.ports, including the name and protocol of the specified port.
Pods and Services are virtual concepts inside the k8s cluster, so they are not accessible to clients outside the cluster. However, under some special conditions, we need to have external access to Pod or Service, then we need to map the port number of Pod or Service to the host, so that clients can access the container application through the physical machine.
Extranet access to Pod
Map the port number of the container application to the physical machine. There are two ways to do this, as follows.
Set the container level hostPort
This kind is to map the port number of the container application to the physical machine. The settings are as follows.
Set Pod level hostNetwork=true
This maps all container port numbers in that Pod directly to the physical machine. Note that in the container ports definition section, if hostPort is not specified, the default hostPort=containerPort, and if hostPort is set, hostPort must be equal to containerPort. set as follows.
Extranet Access Service
There are also two ways to do this.
Set nodePort mapping to physical machine
First you need to set the nodePort mapping to the physical machine, and you need to set the Service type to NodePort.
Set up LoadBalancer mapping to the LoadBalancer address provided by the cloud service provider
This usage is only used in scenarios where the service is set up on the cloud platform of the public cloud service provider. The service.status.loadBalancer.address.ip needs to be set to the IP of the load balancer provided by the cloud service provider. The load balancing implementation depends on the implementation mechanism of the LoadBalancer provided by the cloud provider.
To enable mutual access to services within the cluster by service name, a virtual DNS service needs to be created to resolve the service name to the ClusterIP.
DNS provided by k8s
The DNS service provided by k8s is called skydns and consists of the following four components.
- etcd: DNS storage.
- kube2sky: registers the Service in k8s Master to etcd; * kube2sky: registers the Service in k8s Master to etcd.
- skyDNS: DNS domain name resolution service.
- healthz: health check for skyDNS.
The skyDNS service consists of an RC and a Service. In the configuration file of the RC, four containers, etcd / kube2sky / skydns / healthz, need to be defined to ensure that the DNS service works properly. It is important to note that:
- the kube2sky container needs to access the k8s Master, so you need to configure the IP address and port of the physical host where the Master is located in the configuration file for it.
- you need to set the startup parameter
--domainof kube2sky and skydns containers to the domain name of the Service in the k8s cluster. After the container is started, kube2sky will monitor the definition of all services in the cluster through API Server, generate the corresponding records and save them to etcd; 3. The skydns startup parameter
-addr=<IP:Port>indicates that the local TCP and UDP port provides services.
In the DNS Service configuration file, we need to specify the ClusterIP of skydns, which will be used by each Node kubelet and will not be automatically assigned by the system; in addition, this IP needs to be in the kube-apiserver startup parameter
Before the skydns container is created, you need to modify the kubelet startup parameters on each Node: * –cluster_dns
--cluster_dns=<dns_cluster_ip>, dns_cluster_ip is the ClusterIP of the DNS service.
--cluster_domain=<dns_domain>, dns_domain is the domain name set in the DNS service.
How DNS works
- first kube2sky container application gets all the service information in the cluster by calling k8s Master’s API, and continuously monitors the new service generation and writes it to etcd;
- According to the kubelet startup parameters, kubelet will set the DNS resolution configuration file
/etc/resolv.confto add a nameserver configuration and a search configuration in each newly created Pod, and the nameserver will actually access the DNS resolution service provided by skydns on the corresponding port. The DNS resolution service provided by skydns on the corresponding port.
- Finally, the application can access the service just by its name, just like a website domain name.
Service works at TCP/IP layer, and Ingress forwards different URL access requests to different services at the backend, implementing the business routing mechanism at HTTP layer. In k8s, you need to combine Ingress and Ingress Controller to form a complete HTTP load balancing.
The Ingress Controller is used to provide a unified entry point for all back-end services, and needs to implement load distribution rules based on different HTTP URLs forwarded backwards.
- Listen to APIServer and get all Ingress definitions.
- Generate the required Nginx configuration file
/etc/nginx/nginx.confbased on the Ingress definitions.
nginx -s reloadto reload the contents of the nginx.conf configuration file.
There is a separate resource in k8s called Ingress where you can set forwarding rules to the backend service in its configuration file. For example, define an ingress.yml for hdls.me.
kubectl create -f ingress.yml to create Ingress, and log in to the nginx-ingress Pod to see the contents of its automatically generated nginx.conf configuration file.