By Wang Bingshen (Xiheng), Technical Expert at Alibaba
Applications in a Kubernetes cluster are deployed by using pods, which is different from the conventional approach of deploying applications on specific machines. We know how to call the IP addresses of other machines, but the pod lifecycle is short. The IP address of a pod changes during its lifecycle, for example, when the pod is created or destroyed. This makes it impossible to deploy applications in a Kubernetes cluster by using the conventional approach because application access through a specified IP address is impossible.
To deploy applications in a Kubernetes cluster, you need to create a group of pods in addition to Deployments, provide a central endpoint for the pods, and implement traffic load balancing among the pods. You need to keep the same deployment template and access mode for the test environment, staging environment, and production environment when deploying applications. In this way, you can use the same template to directly publish applications to different environments.
Applications need to be exposed so that external users can call them. Pods are located in a different network segment from machines. To expose the pod network for external access, you need to configure service discovery.
In Kubernetes, service discovery and load balancing are provided as services. The preceding figure shows the architecture of a Kubernetes Service, which provides access to the external network and pod network in the uplink direction.
The Kubernetes Service interworks with a group of pods in the downlink direction to implement load balancing among the pods. This provides a central endpoint for service discovery and enables access to the external network and access among different pods through the same address.
The following is an actual use case to show how to declare and use Services for pods in Kubernetes.
To start, let's look at the syntax of a Kubernetes Service. The preceding figure shows a declaration structure of Kubernetes. This structure contains many syntaxes, which are similar to some standard Kubernetes objects described earlier. For example, you can make selections by using the labels and selector fields and make declarations by using the labels field.
The template defines a protocol and a port for the Kubernetes Service used for service discovery. The template declares a Kubernetes Service named my-service
, which has the app:my-service
label. The Service selects the pod with the app:MyApp
label as its backend.
TCP and port 80
are defined for service discovery. The target port is 9376
. Access requests to port 80
are routed to port 9376
of the pod with the app:MyApp
label at the backend. This implements load balancing.
This section explains how to create the Service declared earlier and view the created Service. Run the following command:
kubectl apply -f service.yaml
Or
kubectl created -f service.yaml
The preceding commands are used to create a Service. After a Service is created, run the following command:
kubectl describe service
This lets you view the created Service.
The created Service is named my-service
. The Namespace
, Labels
, and Selector
fields are the same as the fields in the earlier declaration. An IP address is created for the Service and can be accessed by pods in the cluster. The IP address is the central endpoint for all pods and is used by service discovery.
The Endpoints
field indicates the pods specified by the selector
field. You can view the pod status. For example, you can view the IP addresses and target ports of the selected pods.
The preceding figure shows the architecture. A virtual IP address and a port are created along with the Service in the cluster. All pods and nodes in the cluster can access the Service through this IP address and port. The Service mounts the selected pods and their IP addresses to the backend. In this way, access requests through the Service's IP address are distributed to these pods for load balancing.
When a pod's lifecycle changes, for example, when the pod is destroyed, the Service automatically removes the pod from the backend. This ensures that the endpoint remains unchanged despite the changes in the pod lifecycle.
After a Service is created in a cluster, the pods in the cluster can access the Service in one of the following ways:
my-service
created earlier, you can run the kubectl get svc
or kubectl describe service
command to view the virtual IP address 172.29.3.27
and port 80
of the Service, which can be directly used by pods to access the Service.service_name.service_namespace
. For example, the Service can be accessed through curl in the format my-service:80
.$
to get the value of an environment variable. MY_SERVICE_SERVICE_HOST
indicates the Service's IP address, MY_SERVICE
is the declared service name, and SERVICE_PORT
is the Service's port. In this way, the pod can send requests to the Service indicated by MY_SERVICE
in the cluster.Headless services are a special type of service. When creating a Service, you can specify clusterIP:None
to tell Kubernetes that you do not need the cluster IP address, that is, the virtual IP address mentioned earlier. Then, Kubernetes does not allocate a virtual IP address to this Service. Even without the virtual IP address, the Service can implement load balancing and provide a central endpoint as follows:
Pods can directly resolve the Service name through the A record of DNS to the IP addresses of all pods at the backend. The client can select any of the resolved backend IP addresses. The A record changes with the changes in the pod lifecycle, as does the returned A record list. The client needs to select an appropriate IP address from the list of the DNS-returned A record to access pods.
Compared with the earlier-declared template, the template in the preceding figure adds clusterIP:None
, indicating that the virtual IP address is not required. When a pod in the cluster accesses my-service
, it directly resolves the service name to the IP addresses of all pods that match the Service. Then, the pod selects an IP address from the returned list to directly access the Service.
The preceding section showed how to access a Service from nodes or pods in a cluster. This section shows how to expose a Service outside the cluster and expose applications for access from the Internet. You can use NodePort
and LoadBalancer
to expose Services externally.
NodePort
mode, the port of a node in a cluster is exposed on the node host. When receiving an access request, the exposed port forwards the request to the virtual IP address of the Service configured on the host.LoadBalancer
mode, an additional forwarding layer is added. NodePort
is implemented on the port of every node in the cluster, whereas LoadBalancer
mounts a load balancer to all nodes. For example, you can mount an Alibaba Cloud Server Load Balancer (SLB) instance to provide a central endpoint and evenly distribute incoming traffic to the pods of all nodes in the cluster. Then, the pods forward the traffic to the target pods based on the cluster IP address.The following example demonstrates how to use a Kubernetes Service in Alibaba Cloud Container Service.
Prerequisites: You have created an Alibaba Cloud container cluster and configured a connection from the local terminal to the Alibaba Cloud container cluster.
Run the kubectl get cs
command to check that the Alibaba Cloud container cluster is connected.
You can use the following templates to implement a Kubernetes Service in Alibaba Cloud. There are three templates. The client template is used to access a Kubernetes Service that evenly distributes traffic to the pods declared by the Service.
Create a Kubernetes Service template to declare pods so that traffic is evenly distributed from port 80
at the frontend to port 80
at the backend. Then, set the selector
field to select backend pods
with the run:nginx
label.
Then, create a group of pods with the run:nginx
label by using Kubernetes Deployments. A Deployment has two replicas, matching two pods.
Run the kubectl create -f service.yaml
command to create a Deployment. After a Deployment is created, check whether pods are also created. As shown in the following figure, the two pods created along with the Deployment are in the Running
state. Run the kubectl get pod -o wide
command to view the IP addresses of the pods. Use -l
to implement filtering based on run=nginx
. As shown in the following figure, the two pods have the IP addresses 10.0.0.135
and 10.0.0.12
, and both have the label run=nginx
.
Run the following command to create a Kubernetes Service that selects the two pods:
Run the kubectl describe svc
command to view the status of the Service. As shown in the following figure, the created Kubernetes Service named nginx
uses the selector run=nginx
to select the pods 10.0.0.12
and 10.0.0.135
as backend pods. A virtual IP address in the cluster is created for the Kubernetes Service to evenly distribute traffic to the two pods at the backend.
Run the client.yaml
command to create a client pod to access the Kubernetes Service. Run the kubectl get pod
command to check that the client pod was created and in the Running
state.
Run the kubectl exec
command to access the client pod and experience the three access modes. Use curl to directly access the cluster IP address (or virtual IP address) of the Kubernetes Service. The client pod does not have curl installed. Run the wget
command and enter the virtual IP address. You can access the Kubernetes Service named nginx
at the backend through the virtual IP address, which is also the central endpoint.
You can also access the Kubernetes Service through the service name. Run the wget
command to access the Kubernetes Service nginx
and you will get the same result as earlier.
If the client pod is in a different namespace from the Kubernetes Service, you can add the name of the namespace where the Service is located to access the Service. Here, we use the namespace named default
as an example.
You can also access the Kubernetes Service through environment variables. Run the env
command on the client pod to view the injected environment variables. All configurations of the nginx
Service are registered.
Run the wget
command to access the environment variables. Then, you can access the Kubernetes Service.
The following explains how to access the Kubernetes Service from an external network. Modify some configurations of the Kubernetes Service in Vim
.
Add the type
field and set it to LoadBalancer
to enable external access.
Run the kubectl apply
command to apply the modifications to the Service.
Now, let's see what changes occur in the Service. Run the kubectl get svc -o wide
command and you will find that the Service nginx
adds EXTERNAL-IP
, which is the IP address for external access. As mentioned earlier, the Service is accessed within the cluster through the virtual IP address defined by CLUSTER-IP
.
Access the external IP address 39.98.21.187
to see how applications are exposed through the Service. Enter the external IP address in the web browser of the terminal to access the Service.
The following shows how to use the Service to implement service discovery in Kubernetes. The Service access address is unrelated to the pod lifecycle. Let's first look at the IP addresses of the two pods selected for the Service.
Run the kubectl delete
command to delete the first pod.
Then, the Deployment automatically creates another pod with an IP address that ends with 137
.
Run the describe command to view the Service information, as shown in the following figure. The endpoint is still the cluster IP address. In LoadBalancer
mode, the IP address for external access remains unchanged. The IP address of a backend pod is automatically included in the backend IP address list of the Service. This does not affect client access.
In this way, the changes in the pod lifecycle have no impact on calls to application components.
This chapter analyzes the design and implementation of Kubernetes.
The preceding figure shows the architecture of a Kubernetes Service for service discovery.
The architecture contains a master node and multiple worker nodes.
The Kubernetes API Server is deployed on the master node to centrally manage all Kubernetes objects. All components are registered on the API server to listen to object changes, such as changes in the pod lifecycle.
The master node has three major components:
CoreDNS
listens to changes of the backend pods of the Service on the API server. You can configure DNS resolution to directly access the virtual IP address of the Service through the service name. You can also configure DNS resolution to resolve the IP addresses in the IP address list kept by the headless Service.kube-proxy
on every node listens to changes of the Service and pods, allowing you to configure the nodes and pods in the cluster or configure access through the virtual IP address based on the actual situation.Let's have a look at the actual access link. For example, assume Client Pod 3 in the cluster wants to access the Service. Client Pod 3 resolves the Service IP address through CoreDNS
, which returns the IP address that matches the service name. Client Pod 3 initiates a request through the Service IP address. After the request is sent to the host network, it is intercepted based on iptables or the IP virtual server (IPVS) configured by kube-proxy
. Then, the request is distributed by the load balancer to each pod at the backend. This implements the service discovery and load balancing processes.
Let's look at how external traffic is processed, for example, when a request is sent from the Internet. A load balancer is configured after the external cloud controller manager, which is also a load balancer, listens to changes of the Service. The configured load balancer forwards an external access request to the port of a node, which then forwards the request to the cluster IP address based on the iptables configured by kube-proxy
. Then, the cluster IP address is mapped to the IP address of a backend pod, to which this request is finally sent. This implements the service discovery and load balancing processes. This is the architecture of a Kubernetes Service for service discovery.
This section explains how to implement a Kubernetes Service and how to diagnose and fix network errors of the Service.
Let's summarize what we have learned in this article:
I hope that, after reading this article, you can orchestrate complex enterprise-level applications in a standard and fast manner by using Kubernetes Services.
Fundamentals of Declarative Application Management in Kubernetes
Getting Started with Kubernetes | Further Analysis of Linux Containers
507 posts | 48 followers
FollowAlibaba Developer - June 22, 2020
Adrian Peng - February 1, 2021
Alibaba Developer - February 26, 2020
Alibaba Container Service - March 12, 2021
Alibaba Developer - June 19, 2020
Alibaba Developer - February 1, 2021
507 posts | 48 followers
FollowAlibaba Cloud Container Service for Kubernetes is a fully managed cloud container management service that supports native Kubernetes and integrates with other Alibaba Cloud products.
Learn MoreProvides a control plane to allow users to manage Kubernetes clusters that run based on different infrastructure resources
Learn MoreAccelerate and secure the development, deployment, and management of containerized applications cost-effectively.
Learn MoreRespond to sudden traffic spikes and minimize response time with Server Load Balancer
Learn MoreMore Posts by Alibaba Cloud Native Community