在kubernetes集群中每个Pod都有自己的 IP 地址。使用Service可以实现不需要显式地在它们之间创建链接,创建了一个简洁的网络。而且Kubernetes网络实现了以下功能:
Service是kubernetes核心资源之一,Service定义了一个服务的访问入口地址,前端的应用(pod)或者ingress通过这个地址访问其背后一组由Pod副本组成的集群实例。
在解决服务发现和服务通信的问题上,kubernetes使用了一种独特的方法:Service,Service没有共用一个负载均衡的IP(通常做法是共用一个IP,用端口进行区分),反而是给每个Service分配了一个全局虚拟IP,也叫Cluster IP,这样的好处在于服务调用就变成TCP通信问题。
众所周知,Pod的Endpoint地址随着容器生命周期发生改变,新部署的Pod地址和之前的Pod地址不尽相同,Kubernetes Service定义了这样一种抽象:一个Pod的逻辑分组,一种可以访问它们的策略,通常称为微服务。这一组Pod能够被Service访问到,通常是通过Label Selector来实现。如果要了解无 Selector 的其他方法,请参阅3.2
设置spec.externalTrafficPolicy字段
说明 您的服务类型为虚拟集群IP或负载均衡时,才能设置外部流量策略。
设置spec.internalTrafficPolicy字段
最常用的模式,通常用在集群内的两个服务相互访问
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
该配置创建了一个名为“my-service”的服务对象,它可以将my-service:80流量转发到任何带有标签app=MyApp且端口为9376的 Pod 上 。
Kubernetes 为该服务分配一个 IP 地址(有时称为“Cluster IP”),我们可以使用Cluster IP和服务名称进行访问。仅限定在集群内访问。
在集群的每一个Node节点分配静态端口 (the NodePort) 绑定后端Pod服务。ClusterIPService 路由到的ServiceNodePort是自动创建的。外部服务可以通过NodePort请求集群Pod,方式:
好处在于给开发者们设置自己的负载均衡器的自由,或者将Kubernetes配置在完全支持负载均衡的云环境上,或者甚至可以直接开放一个或者多个节点的IP。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: MyApp
ports:
# By default and for convenience, the `targetPort` is set to the same value as the `port` field.
- port: 80
targetPort: 80
# Optional field
# By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767)
nodePort: 30007
请注意,此服务显示为:spec.ports[].nodePort 和.spec.clusterIP:spec.ports[].port。如果设置–nodeport-addresses kube-proxy 的标志或 在kube-proxy 配置了等效字段,则将忽略节点 IP。
对于某些服务,您需要公开多个端口。Kubernetes 允许在服务对象上配置多个端口定义。当为一个服务使用多个端口时,必须提供所有端口名称,以便明确这些名称。例如:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377
名字写法与 Kubernetes 一样,端口名称只能包含小写字母数字字符和-. 端口名称也必须以字母数字字符开头和结尾。
在支持负载均衡器的云提供商上,将type 字段设置LoadBalancer可以为服务提供负载均衡(例如:SLB、CLB)。负载均衡器的实际创建是异步发生的,有关已配置的均衡器的信息会发布在 Service的.status.loadBalancer字段中。例如:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.0.2.127
注意:可用于 LoadBalancer 类型的服务的协议集仍由云提供商定义。
一些云提供商允许指定loadBalancerIP. 在这些情况下,负载均衡器是使用用户指定的loadBalancerIP. 如果loadBalancerIP未指定该字段,则使用临时 IP 地址设置 loadBalancer。如果您指定 aloadBalancerIP 但云提供商不支持该功能,则loadbalancerIP设置的字段将被忽略。
以阿里云为列,我们需要如下配置:
service.beta.kubernetes.io/alicloud-loadbalancer-address-type决定负载均衡器是否是公网还是内网
apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/alicloud-loadbalancer-address-type: intranet
service.beta.kubernetes.io/alicloud-loadbalancer-force-override-listeners: 'true'
service.beta.kubernetes.io/alicloud-loadbalancer-id: xxxx
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: xx.xxx.xxx.xx
注意: 如果在SLB设置了externalTrafficPolicy: Local类型,这种类型的SLB地址只有在Node中部署了对应的后端Pod,才能被访问。因为SLB的地址是集群外使用,如果集群节点和Pod不能直接访问,请求不会到SLB,会被当作Service的扩展IP地址,被kube-proxy的iptables或ipvs转发。
我们有时在进行服务迁移,或者集群迁移,又或者想把某个外部服务像内部服务一样连接,需要将一个集群的流量转发到另一个集群的流量,我们可以使用如下写法,即不指定selector app字段,手动配置endpoint
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
由于此 Service 没有选择器,因此不会自动创建相应的 Endpoints 对象。您可以通过手动添加 Endpoints 对象,手动将服务映射到其运行的网络地址和端口:
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 192.0.2.42
ports:
- port: 9376
Endpoints 对象的名称必须和Service 同名。
对于许多想要使用Service的人来说,以上的信息应该足够了。但是我们可以尝试理解Service背后的原理
如
1、ClusterIP 如何保证唯一
2、 kube-proxy在你的集群中使用的那种模式,
3、iptables和IPVS有何不同
如果你的集群规模特别大,如有10000个Pod。那么请使用IPVS模式吧,IPVS 专为负载平衡而设计,并基于内核哈希表。因此,可以通过基于 IPVS 的 kube-proxy 实现大量服务的性能一致性。同时,基于 IPVS 的 kube-proxy 具有更复杂的负载平衡算法(最少连接数、局部性、加权、持久性)。