Service
We have learned Pod
the basic usage before, and we also learned Pod
that life is limited, and there will be no resurrection after death. What we learn later RC
can Deployment
be used to dynamically create and destroy Pod
. Although each Pod
has its own IP
address, it is very likely that his will change if Pod
it is restarted . IP
This will bring about a problem: for example, we have some back-end collections that provide services Pod
for other front-end collections in the cluster . If we hardcode the addresses of all these back-ends in the front-end , and then go to a certain way To access one of the services, it seems to work, right? But if it hangs up and then restarts, the address is very likely to change. At this time, the front-end may not be able to access the back-end services.Pod
API
Pod
Pod
Pod
Pod
IP
How to solve such a problem? Before using it Kubernetes
, I believe that many people may have encountered such a problem, and it is not necessarily IP
a problem of change. For example, when we deploy a WEB
service, the front end usually deploys an Nginx
entry as a service, and then Nginx
it must be mounted later. There are a lot of backends for this service. A long time ago, we may manually change the options Nginx
in the configuration to dynamically change the number of services provided. Later , some tools upstream
appeared , such as , and tools we are familiar with . With these After the tools are used, we can just register our services to these service discovery centers, and then let these tools dynamically update the configuration. We don't need to do manual operations at all, isn't it very convenient?服务发现
Consul
ZooKeeper
etcd
Nginx
Similarly, to solve the problems we encountered above, is it possible to implement a service discovery tool? That's right, when we Pod
are destroyed or newly created, we can register this Pod
address to the service discovery center, but in this case, our front-end Pod
combination can't directly connect to the background Pod
collection, right? It should be connected to A middleware that can do service discovery, right?
That's right, Kubernetes
the cluster provides us with such an object - Service
an Service
abstract object that defines a set Pod
of logical collections and a strategy for accessing them. In fact, this concept is very similar to microservices. A set of Serivce
contained below Pod
is generally determined Label Selector
by .
For example, in our example above, if we run 3 copies on the backend, these copies are all replaceable, because the frontend does not care which backend service they use. Although the back-end Pod
collection will send changes due to various reasons, the front-end does not need to know these changes, nor does it need to use a list to record these back-end services. Service
This abstraction can help us achieve this decoupling. .
Three IPs
Before continuing to study Service
, we need to figure out Kubernetes
the issue of the three IPs in the system, because people often get confused.
- Node IP: the address
Node
of the nodeIP
- Pod IP:
Pod
The IP address of the pod - Cluster IP: the address
Service
ofIP
First of all, Node IP
it is Kubernetes
the physical network card address of the nodes in the cluster IP
(usually the intranet). All servers belonging to this network can communicate directly with each other. Therefore, if you Kubernetes
want to access Kubernetes
a node or service inside the cluster outside the cluster, you must Node IP
communicate through (At this time, it is usually through the external network IP
)
Then Pod IP
there is each Pod
address IP
, which is allocated Docker Engine
according to the address segment docker0
of the bridge (we use this kind of network plug-in here to ensure that all nodes will not conflict)IP
flannel
Pod IP
Finally Cluster IP
, it is a virtual one IP
, which only acts on Kubernetes Service
this object and Kubernetes
manages and assigns addresses by itself. Of course, we can’t use ping
this address. It doesn’t have a real entity object to respond to. It can only be combined Service Port
to form a service that can communicate.
Define Service
The definition Service
method and the method types of the various resource objects we defined earlier, for example, suppose we have a group of Pod
services that expose port 8080 to the outside world and are all labeled as app=myapp
such, then we can define a service as follows Service
object:
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
name: myapp-http
Then kubectl create -f myservice.yaml
you can create an object named myservice
by using Service
it, which will proxy the request to the one with the label using TCP port 8080. This will be assigned by the system app=myapp
as we mentioned above , and it will continue to listen to the following , This information will be updated to an object named , which is similar to the collection we mentioned above .Pod
Service
Cluster IP
Service
selector
Pod
Pod
myservice
Endpoints
Pod
Note that it is Service
possible to map a receive port to any targetPort
. By default, targetPort
will be set to port
the same value as the field. Perhaps more interestingly, targetPort can be a string referencing the name of a port on the backend Pod. Because the port number actually assigned to the port name may not be the same in each backend Pod, this method will provide greater flexibility for deploying and designing the Service.
In addition, Service
it can support TCP and UDP protocols, and the default is TCP protocol.
be a proxy
As we mentioned earlier, in Kubernetes
the cluster, each Node
will run a kube-proxy
process, which is responsible for Service
implementing a proxy form of VIP (virtual IP, which is what we said above clusterIP
), which is now Kubernetes
used by default iptables
in this mode to proxy. This mode kube-proxy
monitors Kubernetes master
the addition and removal of Service objects and Endpoints objects. For each Service, it will add iptables rules to capture the request to the clusterIP (virtual IP) and port of the Service, and then redirect the request to one of the set of backends of the Service. For each Endpoints object, it also installs iptables rules that select a backend Pod.
The default strategy is to randomly select a backend. We can also implement session affinity based on client IP, which can be service.spec.sessionAffinity
set to "ClientIP" (the default value is "None").
Another thing to understand is that the iptables proxy can automatically retry another Pod if the initially selected Pod does not respond, so it needs to rely on readiness probes.
[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-sD0QIvZU-1678238488098)(./images/services-iptables-overview.svg)]
Service type
We Service
can specify a type we need when we define it Service
. If we don't specify it, it defaults to ClusterIP
the type.
The types of services we can use are as follows:
-
ClusterIP: The service is exposed through the internal IP of the cluster. If this value is selected, the service can only be accessed within the cluster. This is also the default ServiceType.
-
NodePort: Expose services through IP and static port (NodePort) on each Node node. The NodePort service will be routed to the ClusterIP service, which will be created automatically. A NodePort service can be accessed from outside the cluster by requesting:
-
LoadBalancer: Use the cloud provider's load balancer to expose services to the outside. External load balancers can be routed to NodePort services and ClusterIP services, which need to be operated in conjunction with specific cloud vendors.
-
ExternalName: By returning the CNAME and its value, the service can be mapped to the contents of the externalName field (for example, foo.bar.example.com). No proxy of any kind is created, this is only supported by kube-dns for Kubernetes 1.7 or higher.
NodePort type
If you set the value of type to "NodePort", the Kubernetes master will allocate a port from the given configuration range (default: 30000-32767), and each Node will proxy to the Service from this port (the same port on each Node). The port will be specified through the spec.ports[*].nodePort field of Service, if not specified, a port will be generated automatically.
It should be noted that Service will be visible externally through :spec.ports[ ].nodePort and spec.clusterIp:spec.ports[ ].port.
Next, let's create a NodePort
service for everyone to access our previous Nginx
service: (save as service-demo.yaml)
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
selector:
app: myapp
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 80
name: myapp-http
Create this Service
:
$ kubectl create -f service-demo.yaml
Then we can view Service
the object information:
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d
myservice NodePort 10.104.57.198 <none> 80:32560/TCP 14h
We can see myservice
that the TYPE type has changed , and there is an additional mapped port of 32560 in the NodePort
latter part.PORT(S)
ExternalName
ExternalName
It is a special case of Service, it has no selector, nor does it define any ports and Endpoints. For services running outside the cluster, it provides services by returning the alias of the external service.
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
When querying the host my-service.prod.svc.cluster.local (we will explain it in depth later in service discovery), the DNS service of the cluster will return a CNAME record whose value is my.database.example.com. Accessing this service works the same as the others, the only difference is that the redirection happens at the DNS layer and there is no proxying or forwarding. If you later decide to migrate the database to the Kubernetes cluster, you can start the corresponding Pod, add a suitable Selector or Endpoint, and modify the type of Service without modifying the calling code at all, so that it is completely decoupled.