理解Kubernetes中service是什么
Kubernetes-service
什么是Service (服务)
Service是Kubernetes里最核心的资源对象之一,Service定义了一个服务的访问入口地址,前端的应用(Pod)通过这个入口地址访问其背后的一组由Pod副本组成的集群实力。 Service与其后端Pod副本集群之间则是通过Label Selector来实现"无缝对接"。而RC的作用实际上是保证Service 的服务能力和服务质量处于预期的标准。
通过分析、识别并建模系统中所有服务为微服务---Kubernetes Service,最终我们的系统由多个提供不同业务能力而又彼此独立的微服务单元组成,服务之间通过TCP/IP进行通信,从而拥有了强大的分布式能力、弹性扩展能力、容错能力
既然每个Pod都会被分配一个单独的IP地址,而且每个Pod都提供了一个独立的Endpoint(Pod IP+ContainerPort)以被客户端访问,现在多个Pod副本组成了一个集群来提供访问。
Kubernetes 需要在每个Node上安装kube-proxy,kube-proxy进程其实就是一个智能的软件负载均衡器,它负责把对Service的请求转发到后端的某个Pod实例上,并在内部实现服务的负载均衡与会话保持机制。
Kubernetes发明了一个很巧明的设计,Service不是共用一个负载均衡器的IP地址,而是每个Service分配了一个全局唯一的虚拟IP地址,这个虚拟IP被称为Cluster IP。这样每个服务就变成了具备唯一IP地址的"通信节点",服务调用就变成了最基础的TCP网络通信问题
Pod的Endpoint地址会随着Pod的销毁和重新创建而发生改变,因为新的Pod地址与之前的旧的Pod不同。而Service一旦被创建,Kubernetes就会自动为它分配一个可用的Cluster IP,而且在Service的整个声明周期内,它的Cluster IP不会发生改变。所以只要将Service的name与Service的Cluster IP地址做一个DNS域名映射即可解决问题
创建一个Service
案例:手动创建一个Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
kind: Service
apiVersion: v1
metadata:
name: svc
spec:
selector:
app: nginx
type: NodePort
ports:
- protocol: TCP #仅支持TCP和UDP,不写默认TCP
port: 80
targetPort: 80
nodePort: 30123
[root@kubernetes-m media]# kubectl create -f pod-svc.yaml
deployment.apps/nginx created
service/svc created
[root@kubernetes-m media]# kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-97499b967-v2fz9 1/1 Running 0 30s
pod/nginx-97499b967-w4d76 1/1 Running 0 30s
pod/nginx-97499b967-xrxmb 1/1 Running 0 30s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 100.1.0.1 <none> 443/TCP 2d2h
service/svc NodePort 100.1.149.238 <none> 80:30123/TCP 30s
[root@kubernetes-m media]# curl 10.0.0.10:30123
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@kubernetes-m media]# kubectl describe service svc
Name: svc
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: NodePort
IP: 100.1.149.238
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 30123/TCP
Endpoints: 200.1.1.65:80,200.1.1.66:80,200.1.2.47:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
温馨提示: targetPort支持字符串 场景: 如果有2个pod lables标签都为nginx,但是我们的业务知识匹配其中一个,就可以在其中一个pod中为containerPort下添加一个name变量,然后通过svc引用的时候,targetPort直接写入变量就可以
参数 | 解释 |
---|---|
Port | port表示:service暴露在cluster ip(Seriver ip )上的端口,:port 是提供给集群内部客户访问service的入口。 |
NodePort | nodePort是kubernetes提供给集群外部客户访问service入口的一种方式(另一种方式是LoadBalancer,:nodePort 是提供给集群外部客户访问service的入口。 |
targetPort | targetPort很好理解,targetPort是pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort上进入容器。 |
外部系统访问Service问题
我们需要掌握kubernetes中的三种IP
1.Node IP:Node节点IP地址 2.Pod IP:Pod的IP地址 3.Cluster IP:Service的IP地址
参数解释: 1.Node IP是Kubernetes集群中每个节点的物理网卡的IP地址,这是一个真实存在的物理网络,所有属于这个网络的服务器之间都能通过这个网络直接通讯,不管他们中间是否含有不属于Kubernetes集群中的节点。想Kubernetes之外的节点访问Kubernetes集群内的节点或者TCP/IP服务时,必须通过Node IP
s
2.Pod IP是每个Pod的IP地址,它是Docker Engine 根据docker0网桥的IP地址段进行分配的,通常是一个虚拟的二层网络,Kubernetes要求位于不同Node上的Pod能够彼此直接通讯,所以Kubernetes里一个Pod里的容器访问另外一个Pod里的容器,就是通过Pod IP所在的虚拟二层网络进行通信,而真实的TCP/IP流量则是通过Node IP所在的物理网卡流出
3.Cluster IP,它是一个虚拟IP,但更像是一个伪造的IP网络
(1)Cluster IP仅仅作用于Kubernetes Service对象,并由Kubernetes管理和分配IP地址(来源于Cluster IP地址池) (2)Cluster IP无法被Ping,因为没有一个"实体网络对象"来响应 (3)在Kubernetes集群内,Node IP、Pod IP、Cluster IP之间的通信,采用的是Kubernetes自己设计的特殊路由规则
简述NodePort实现方式
NodePort的实现方式是在Kubernetes集群里的每个Node上为需要外部访问的Service开启一个对应的TCP请求,外部系统只要用任意Node的IP地址+具体的NodePort端口即可访问服务,在任意node上运行netstat服务,我们可以看到NodePort端口被监听
但NodePort还没有完全解决外部访问Service的所有问题,比如负载均衡的问题,假如说我们集群中有10个Node,则此时最好有一个负载均衡,外部的请求只需要访问此负载均衡器的IP地址,由负载均衡负责转发流量到后面某个NodePort上
例子
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
type: NodePort
ports:
- name: nginx-svc
protocol: TCP
port: 80
targetPort: 80
nodePort: 30001 #如果我们不指定nodeport端口,会生成一个随机端口30000-32767之间
查看
[root@kubernetes-m media]# kubectl get svc,pod -A | grep nginx
default service/nginx-svc NodePort 100.1.119.55 <none> 80:30001/TCP 24s
default pod/nginx-97499b967-6pch6 1/1 Running 0 24s
default pod/nginx-97499b967-kqpqv 1/1 Running 0 24s
default pod/nginx-97499b967-tfc7h 1/1 Running 0 24s
接下来就可以访问了
[root@kubernetes-m media]# curl -I 10.0.0.10:30001
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Mon, 01 Nov 2021 03:34:27 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:50:58 GMT
Connection: keep-alive
ETag: "61378a62-267"
Accept-Ranges: bytes
可以看到返回了nginx的版本 而且状态码是200
我们可以看到,svc访问实际上是通过kube-proxy来生成,下面就可以看看kube-proxy的原理
[root@kubernetes-m media]# netstat -nplt | grep 30001
tcp 0 0 0.0.0.0:30001 0.0.0.0:* LISTEN 51074/kube-proxy
Kube-proxy 工作原理
1.Service在很多情况下知识一个概念,真正起到Service作用的是kube-proxy服务进程。 2.每个Node节点上都会运行一个kube-proxy服务进程 3.对每个TCP类型的Kubernetes Service,Kube-proxy都会在本地Node节点上建立一个SocketServer来负责接收请求,然后均匀发送到后端某个Pod的端口上,这个过程默认采用Round Robin(rr)负责均衡算法 4.kube-proxy通过查询和监听Api Server中Service与Endpoints的变化,为每个Service都建立一个"服务代理对象",并自动同步。服务代理对象是kube-proxy程序内部的一种架构,它包括一个用于监听此服务请求的SocketServer,SocketServer的端口是随机选择一个本地空闲端口,此外kube-proxy内部创建了一个负载均衡器LoadBalancer 6.针对发生变化的Service列表,kube-proxy会逐个处理
--- 如果没有设置集群IP,则不做任何处理,否则,取该Service的所有端口定义列表
--- 为Service端口分配服务代理对象并为该Service创建相关的iptables规则
--- 更新负载均衡组件中对应Service的转发地址列表
7.kube-proxy在启动时和监听到Service或Endpoint的变化后,会在本机Iptables的NAT表中添加4条规则链。
--- KUBE-PORTABLS-CONTAINER: 从容器中通过Cluster IP和端口号访问service
--- KUBE-PORTALS-HOST: 从主机中通过Cluster IP和端口号访问service
--- KUBE-NODEPORT-CONTAINER: 从容器中通过NODE IP和端口号访问service
--- KUBE-NODEPORT-HOST: 从主机中通过Node IP和端口号访问service
注意:我们也可以给kube-proxy设置一个默认的策略是随机选择一个 pod。 我们也可以实现基于客户端 IP 的会话亲和性,可以将 service.spec.sessionAffinity的值设置为 "ClientIP"(默认值为 "None")。