kubernetes网络 – 服务概念

欢迎加入本站的kubernetes技术交流群,微信添加:加Blue_L。


kubernetes中服务主要用来进行服务发现和负载均衡。

在集群中我们的工作负载是不稳定的,ip地址可能随着pod重启,升级和扩容等不断发生变化,为了能够让其他工作负载可以稳定访问到这个工作负载,我们需要为其创建一个服务对象。

服务对象也是一个api资源对象,和其他api对象定义方法相同,下面是一个服务对象的定义:

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    # 根据标签选择pod
    app: nginx
  # type: ClusterIP
  # clusterIP: 192.168.3.251
  ports:
    # TCP, UDP, SCTP
    - protocol: TCP
      appProtocol: http
      name: nginx-http
      port: 80
      targetPort: 80
    # 支持多个端口配置
    - name: https
      protocol: TCP
      port: 443
      targetPort: 9377
  externalTrafficPolicy: Cluster

这个服务对象会创建一个service资源,服务控制器会根据我们的selector选择对应的pod,创建endpoint后endpointslice资源关联到这个服务。服务控制器还会为我们的服务自动创建一个虚拟ip地址,其他工作负载使用这个虚拟ip地址访问这个服务。endpoint资源代表后端真正的服务实例,它关联到pod,访问到虚拟ip的流量会转到对应的后端pod对应的端口上。

通过selector可以让kunbernetes根据标签自动选择pod并创建endpoint关联到service。有些场景我们也可以不使用selector,例如:

引用已有服务的ip列表

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - protocol: TCP
      port: 443
      targetPort: 6443
---
apiVersion: v1
kind: Endpoints
metadata:
  name: my-service
subsets:
  - addresses:
      - ip: 192.0.2.42
    ports:
      - port: 6443

引用外部已有服务

apiVersion: v1
kind: Service
metadata:
  name: my-baidu
  namespace: prod
spec:
  # dns cname
  type: ExternalName
  externalName: www.baidu.com

service对象完整参考:https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/

endpoint对象完整参考:https://kubernetes.io/docs/reference/kubernetes-api/service-resources/endpoints-v1/

考虑到超多service实例的集群,endpoints更新会造成网络性能问题,出现了新endpointslice资源,默认每个slice包含100个endpoint,如果有更多的endpoint会创建新的slice。

在kubernetes中,kube-proxy负责非ExternalName类型的service虚拟ip的转发。

User-space模式

Services overview diagram for userspace proxy

kube-proxy本地启动随机监听端口

clusterIP:port(iptables) -> 监听端口 -> endpoints,默认采用轮询算法。

iptables模式

Services overview diagram for iptables proxy

clusterIP:port -> endpoints,默认随机算法。

问题:如果后端pod异常,iptables方式不会自动使用其他pod重试。最好配置pod的就绪探针保证后端pod都是正常运行的。

ipvs模式

Services overview diagram for IPVS proxy

通过netlink接口创建ipvs规则。ipvs模式使用哈希表存储规则,具有低延迟,更好的同步性能,更高的吞吐性能。同时支持负载均衡算法配置(使用kube-proxy的–ipvs-scheduler参数):

  • rr: round-robin
  • lc: least connection (smallest number of open connections)
  • dh: destination hashing
  • sh: source hashing
  • sed: shortest expected delay
  • nq: never queue

https://kubernetes.io/blog/2018/07/09/ipvs-based-in-cluster-load-balancing-deep-dive/

上述三种模式都支持基于客户端ip的会话保持(SessionAffinity)。iptables下使用recent模块

流量策略

External traffic policy

Cluster:转到所有pod,并且通过nat隐藏客户端源IP。可能数据包会再次转到其他节点。

Local:只转发给在本节点的pod,如果某些节点没有对应pod则不做任何转发。该模式下会保留客户端源IP(LoadBalancer和NodePort类型)。

Internal traffic policy

Cluster:流量转发到所有endpoint。

Local:流量只转发到本地endpoint,如果本地没有对应的pod,则丢弃。

创建对应服务进行测试。

https://www.asykim.com/blog/deep-dive-into-kubernetes-external-traffic-policies

https://blog.cptsai.com/2020/11/15/k8s-external-traffic-policy

服务发现

kubernetes支持通过环境变量和dns方式进行服务发现。

{SVCNAME}_SERVICE_HOST

{SVCNAME}_SERVICE_PORT

例如 redis-master服务

REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11

但是pod创建之前service要首先存在

更多的情况下是使用dns进行服务发现。例如在default命名空间下有个service叫my-service,则可以通过my-service或my-service.default来访问这个服务。

如果service对象的spec.clusterIP=None则称之为无头服务,无头服务不会分配service的ip地址,kube-proxy不对这个服务进行流量负载。

如果无头服务定义了selector字段,则kubernetes进行匹配,自动创建endpoint对象。该服务的dns解析返回一个pod ip地址列表的A记录。

如果无头服务未定义selector,则如果定义了ExternalName,则dns解析返回cname只向这个外部域名。其他情况是匹配同名的endpoint对象。

服务的类型

ClusterIP

NodePort

–service-node-port-range

LoadBalancer

spec.allocateLoadBalancerNodePort

spec.loadBalancerClass

ExternalName

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

外部ip,针对任意类型的service。如果外部主机有针对某个网段到集群内的一个或多个节点的路由,那么就可以使用这个externalIP访问服务。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
  externalIPs:
    - 80.11.12.10

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注