k8s service概述

数据主要来源:service官网
 
一. Services简述
将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。
使用Kubernetes,您无需修改应用程序即可使用不熟悉的服务发现机制。 Kubernetes为Pods提供自己的IP地址和一组Pod的单个DNS名称,并且可以在它们之间进行负载平衡。
所谓 Service,其实就是 Kubernetes 为 Pod 分配的、固定的、基于 iptables(或者 IPVS)的访问入口。而这些访问入口代理的 Pod 信息,则来自于 Etcd,由 kube-proxy 通过控制循环来维护。kube-proxy 负责为 Service 实现了一种 VIP(虚拟 IP)的形式.
 
Services动机
  1. Pod 的 IP地址不是固定的,每次通过deploy发布时,Pod都会提供新的IP地址
  2. 一组 Pod 实例之间需要负载均衡
 
定义 Service
假定有一组 Pod,它们对外暴露了 9376 端口,同时还被打上 app=MyApp 标签。
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - name: my-port
     protocol: TCP
     port: 80
     targetPort: 9376
上述配置创建一个名称为 “my-service” 的 Service 对象,它会将请求代理到使用 TCP 端口 9376,并且具有标签 "app=MyApp" 的 Pod 上。 Kubernetes 为该服务分配一个 IP 地址,该 IP 地址由服务代理使用。服务选择器的控制器不断扫描与其选择器匹配的 Pod,然后将所有更新发布到也称为 “my-service” 的Endpoint对象。
 
服务的默认协议是TCP;
 
没有 selector 的 Service
服务最常见的是抽象化对 Kubernetes Pod 的访问,但是它们也可以抽象化其他种类的后端。 实例:
  • 希望在生产环境中使用外部的数据库集群。
  • 希望服务指向另一个 命名空间 中或其它集群中的服务。
  • 您正在将工作负载迁移到 Kubernetes。 在评估该方法时,您仅在 Kubernetes 中运行一部分后端。
在任何这些场景中,都能够定义没有 selector 的 Service。 实例:
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
 
由于此服务没有选择器,因此 不会 自动创建相应的 Endpoint 对象。 您可以通过手动添加 Endpoint 对象,将服务手动映射到运行该服务的网络地址和端口:
apiVersion: v1
kind: Endpoints
metadata:
  name: my-service
subsets:
  - addresses:
      - ip: 192.0.2.42
    ports:
      - port: 9376
 
端点 IPs 必须不可以 :
    1. 环回( IPv4 的 127.0.0.0/8 , IPv6 的 ::1/128 )或本地链接(IPv4 的 169.254.0.0/16 和 224.0.0.0/24,IPv6 的 fe80::/64)。
    2. 端点 IP 地址不能是其他 Kubernetes Services 的群集 IP,因为 kube-proxy 不支持将虚拟 IP 作为目标。
访问没有 selector 的 Service,与有 selector 的 Service 的原理相同。
ExternalName Service 是 Service 的特例,它没有 selector,也没有使用 DNS 名称代替。
 
Endpoint 切片
Endpoint 切片是一种 API 资源,可以为 Endpoint 提供更可扩展的替代方案。
 
为什么不使用 DNS 轮询?
  • DNS 实现的历史由来已久,它不遵守记录 TTL,并且在名称查找结果到期后对其进行缓存。
  • 有些应用程序仅执行一次 DNS 查找,并无限期地缓存结果。
  • 即使应用和库进行了适当的重新解析,DNS 记录上的 TTL 值低或为零也可能会给 DNS 带来高负载,从而使管理变得困难
 
iptables 代理模式
kube-proxy 会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会安装 iptables 规则,从而捕获到达该 Service 的 clusterIP 和端口的请求,进而将请求重定向到 Service 的一组 backend 中的某个上面。 对于每个 Endpoints 对象,它也会安装 iptables 规则,这个规则会选择一个 backend 组合。
默认的策略是,kube-proxy 在 iptables 模式下随机选择一个 backend。
使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理,而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。
如果 kube-proxy 在 iptables模式下运行,并且所选的第一个 Pod 没有响应,则连接失败。 使用 Pod readiness 探测器 验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的后端。
 
iptables的负载均衡分两种:random / nth,random是随机模式,--probability p指定了概率,nth是轮巡模式,--every n和--packet p指定了每n个packet中匹配其中的第p个。
 
IPVS 代理模式
在 ipvs 模式下,kube-proxy监视Kubernetes服务和端点,调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。
而相比于 iptables,IPVS 在内核中的实现其实也是基于 Netfilter 的 NAT 模式,所以在转发这一层上,理论上 IPVS 并没有显著的性能提升。但是,IPVS 并不需要在宿主机上为每个 Pod 设置 iptables 规则,而是把对这些“规则”的处理放到了内核态,从而极大地降低了维护这些规则的代价。“将重要操作放入内核态”是提高性能的重要手段。
IPVS 模块只负责上述的负载均衡和代理功能。而一个完整的 Service 流程正常工作所需要的包过滤、SNAT 等操作,还是要靠 iptables 来实现。只不过,这些辅助性的 iptables 规则数量有限,也不会随着 Pod 数量的增加而增加。
IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数,但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。
IPVS提供了更多选项来平衡后端Pod的流量。 这些是:
  • rr: round-robin
  • lc: least connection (smallest number of open connections)
  • dh: destination hashing
  • sh: source hashing
  • sed: shortest expected delay
  • nq: never queue
 
通过 kube-proxy 设置–proxy-mode=ipvs 来开启这个功能。
要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS Linux 在节点上可用,否则将退回到以 iptables 代理模式运行。
在这些代理模型中,绑定到服务IP的流量:如果要确保每次都将来自特定客户端的连接传递到同一Pod,则可以通过将 service.spec.sessionAffinity 设置为 “ClientIP” (默认值是 “None”),来基于客户端的IP地址选择会话关联。
您还可以通过适当设置 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds 来设置最大会话停留时间。 (默认值为 10800 秒,即 3 小时)。
 
 
二. service的使用
多端口 Service
对于某些服务,您需要公开多个端口。 Kubernetes允许您在Service对象上配置多个端口定义。 为服务使用多个端口时,必须提供所有端口名称,以使它们无歧义。 例如:
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
 
选择自己的 IP 地址
通过设置 spec.clusterIP 字段来指定自己的集群 IP 地址。替换一个已经已存在的 DNS 条目,或遗留系统已经配置了一个固定的 IP 且很难重新配置。
 
服务发现
Kubernetes 支持2种基本的服务发现模式 —— 环境变量和 DNS。
 
环境变量
当 Pod 运行在 Node 上,kubelet 会为每个活跃的 Service 添加一组环境变量。它同时支持 Docker links兼容 变量(查看 makeLinkVariables)、简单的 {SVCNAME}_SERVICE_HOST 和 {SVCNAME}_SERVICE_PORT 变量,这里 Service 的名称需大写,横线被转换成下划线。
举个例子,一个名称为 "redis-master" 的 Service 暴露了 TCP 端口 6379,同时给它分配了 Cluster IP 地址 10.0.0.11,这个 Service 生成了如下环境变量:
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
/ # echo ${REDIS_MASTER_SERVICE_HOST}
10.0.0.11
 
注意⚠️:
    • 当访问服务的Pod,并且使用环境变量方法将端口和群集IP发布到客户端Pod时,必须在客户端Pod出现之前创建服务。
    • 如果仅使用DNS查找服务的群集IP,则无需担心此设定问题。
 
DNS
使用群集的DNS服务器(例如CoreDNS)监视 Kubernetes API 中的新服务,并为每个服务创建一组 DNS 记录。 如果在整个群集中都启用了 DNS,则所有 Pod 都应该能够通过其 DNS 名称自动解析服务。
例如,如果您在 Kubernetes 命名空间 "my-ns" 中有一个名为 "my-service" 的服务, 则控制平面和DNS服务共同为 "my-service.my-ns" 创建 DNS 记录。 "my-ns" 命名空间中的Pod应该能够通过 my-service 进行名称查找来找到它( "my-service.my-ns" 也可以工作)。
其他命名空间中的Pod必须将名称限定为 my-service.my-ns 。 这些名称将解析为为服务分配的群集IP。
Kubernetes 还支持命名端口的 DNS SRV(服务)记录。 如果 "my-service.my-ns" 服务具有名为 "http" 的端口,且协议设置为TCP, 则可以对 _http._tcp.my-service.my-ns 执行DNS SRV查询查询以发现该端口号, "http"以及IP地址。
Kubernetes DNS 服务器是唯一的一种能够访问 ExternalName 类型的 Service 的方式。 更多关于 ExternalName 信息可以查看 DNS Pod 和 Service
 
Pod DNS
此外,对于 ClusterIP 模式的 Service 来说,它代理的 Pod 被自动分配的 A 记录的格式是:..pod.cluster.local。这条记录指向 Pod 的 IP 地址。
[root@m3 ~]# vim pod-dns.yaml
apiVersion: v1
kind: Service
metadata:
  name: default-subdomain
spec:
  selector:
    name: busybox
  clusterIP: None
  ports:
  - name: foo
    port: 1234
    targetPort: 1234
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox1
  labels:
    name: busybox
spec:
  hostname: busybox-1
  subdomain: default-subdomain
  containers:
  - image: busybox
    command:
      - sleep
      - "3600"
    name: busybox
[root@m3 ~]# kubectl apply -f pod-dns.yaml 
 
在上面这个 Service 和 Pod 被创建之后,你就可以通过 busybox-1.default-subdomain.default.svc.cluster.local 解析到这个 Pod 的 IP 地址了。
看到也有同学问pod DNS,希望能讲得更详细些。我查阅官方文档及自己实践后的了解是这两种pod有DNS记录:
    1. statefulset的pod。有人问之前讲DNS的是在哪,就是“20 | 深入理解StatefulSet(三):有状态应用实践”这一篇。
    2. pod显式指定了hostname和subdomain,并且有个headless service的名字和subdomain一样。
 
 
 
 
Headless Services
有时不需要或不想要负载均衡,以及单独的 Service IP,可以通过指定 Cluster IP(spec.clusterIP)的值为 "None" 来创建 Headless Service。
您可以使用 headless Service 与其他服务发现机制进行接口,而不必与 Kubernetes 的实现捆绑在一起。
对这 headless Service 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了 selector。
配置 Selector
对定义了 selector 的 Headless Service,Endpoint 控制器在 API 中创建了 Endpoints 记录,并且修改 DNS 配置返回 A 记录(地址),通过这个地址直接到达 Service 的后端 Pod 上。
不配置 Selector
对没有定义 selector 的 Headless Service,Endpoint 控制器不会创建 Endpoints 记录。 然而 DNS 系统会查找和配置,无论是:
  • ExternalName 类型 Service 的 CNAME 记录
  • 记录:与 Service 共享一个名称的任何 Endpoints,以及所有其它类型
[root@m3 ~]# vim svc-Endpoints.yaml
apiVersion: v1
kind: Endpoints
metadata:
  name: mysql-service
subsets:
  - addresses:
    - ip: 192.168.1.108
      hostname: mysql-service
    ports:
      - port: 3306
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  ports:
    - port: 3306
 
 
三。发布服务 —— 服务类型
Kubernetes ServiceTypes 允许指定一个需要的类型的 Service,默认是 ClusterIP 类型。
Type 的取值以及行为如下:
    • ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType。
    • NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 <NodeIP>:<NodePort>,可以从集群的外部访问一个 NodePort 服务。
    • LoadBalancer:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
    • ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。 没有任何类型代理被创建。
 
1. NodePort 类型
如果将 type 字段设置为 NodePort,则 Kubernetes 控制平面将在 --service-node-port-range 标志指定的范围内分配端口(默认值:30000-32767)。 每个节点将那个端口代理到您的服务中。 您的服务在其 .spec.ports[*].nodePort 字段中要求分配的端口。
如果您想指定特定的IP代理端口,则可以将 kube-proxy 中的 --nodeport-addresses 标志设置为特定的IP块。该标志采用逗号分隔的IP块列表(例如10.0.0.0/8、192.0.2.0/25)来指定 kube-proxy 应该认为是此节点本地的IP地址范围。
如果需要特定的端口号,则可以在 nodePort 字段中指定一个值。注意可能发生的端口冲突。 您还必须使用有效的端口号,该端口号在配置用于NodePort的范围内。
Service 能够通过 <NodeIP>:spec.ports[*].nodePort 和 spec.clusterIp:spec.ports[*].port 而对外可见。
 
[root@m3 ~]# vim svc-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30008
  selector:
    run: my-nginx
[root@m3 ~]# kubectl apply -f svc-nodeport.yaml 
service/my-nginx created
 
[root@s3 ~]#  iptables-save | grep "my-nginx"
-A KUBE-EXTERNAL-SERVICES -p tcp -m comment --comment "default/my-nginx:http has no endpoints" -m addrtype --dst-type LOCAL -m tcp --dport 28080 -j REJECT --reject-with icmp-port-unreachable
-A KUBE-SERVICES -d 10.96.154.242/32 -p tcp -m comment --comment "default/my-nginx:http has no endpoints" -m tcp --dport 80 -j REJECT --reject-with icmp-port-unreachable
 
 
[root@s3 ~]#  iptables-save | grep "KUBE-POSTROUTING"
:KUBE-POSTROUTING - [0:0]
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE
可以看到,这条规则设置在 POSTROUTING 检查点,也就是说,它给即将离开这台主机的 IP 包,进行了一次 SNAT 操作,将这个 IP 包的源地址替换成了这台宿主机上的 CNI 网桥地址,或者宿主机本身的 IP 地址(如果 CNI 网桥不存在的话)。当然,这个 SNAT 操作只需要对 Servicespec.externalTrafficPolicy 转发出来的 IP 包进行(否则普通的 IP 包就被影响了)。而 iptables 做这个判断的依据,就是查看该 IP 包是否有一个“0x4000”的“标志”。你应该还记得,这个标志正是在 IP 包被执行 DNAT 操作之前被打上去的。
 
可以将 Service 的 spec.externalTrafficPolicy 字段设置为 local,这就保证了所有 Pod 通过 Service 收到请求之后,一定可以看到真正的、外部 client 的源地址。
这时候,一台宿主机上的 iptables 规则,会设置为只将 IP 包转发给运行在这台宿主机上的 Pod。
       client
       ^ /   \
      / /     \
     / v       X
   node 1     node 2
    ^ |
    | |
    | v
 endpoint
 
 
2. LoadBalancer 类型
使用支持外部负载均衡器的云提供商的服务,设置 type 的值为 "LoadBalancer",将为 Service 提供负载均衡器。 负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 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
  loadBalancerIP: 78.11.24.19
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
      - ip: 146.148.47.155
 
来自外部负载均衡器的流量将直接打到 backend Pod 上,不过实际它们是如何工作的,这要依赖于云提供商。
在这些情况下,将根据用户设置的 loadBalancerIP 来创建负载均衡器。 某些云提供商允许设置 loadBalancerIP。如果没有设置 loadBalancerIP,将会给负载均衡器指派一个临时 IP。 如果设置了 loadBalancerIP,但云提供商并不支持这种特性,那么设置的 loadBalancerIP 值将会被忽略掉。
 
3. 类型ExternalName
类型为 ExternalName 的服务将服务映射到 DNS 名称,而不是典型的选择器,例如 my-service 或者 cassandra。 您可以使用 spec.externalName 参数指定这些服务。
例如,以下 Service 定义将 prod 名称空间中的 my-service 服务映射到 my.database.example.com:
apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com
 
4. 外部 IP
如果外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes Service 会被暴露给这些 externalIPs。 通过外部 IP(作为目的 IP 地址)进入到集群,打到 Service 的端口上的流量,将会被路由到 Service 的 Endpoint 上。 externalIPs 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。
根据 Service 的规定,externalIPs 可以同任意的 ServiceType 来一起指定。 在上面的例子中,my-service 可以在 “80.11.12.10:80”(externalIP:port) 上被客户端访问。
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
 
 
 
四. service服务实现过程
1. 创建svc和pod
最典型的 Service 定义。使用了 selector 字段来声明这个 Service 只代理携带了 app=hostnames 标签的 Pod。 Service 的 80 端口,代理的是 Pod 的 9376 端口。
[root@m3 ~]# vim svc-test.yaml
apiVersion: v1
kind: Service
metadata:
  name: hostnames
spec:
  selector:
    app: hostnames
  ports:
  - name: default
    protocol: TCP
    port: 80  #监听的端口号
    targetPort: 9376
[root@m3 ~]# kubectl apply -f svc-test.yaml 
service/hostnames created 
[root@m3 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostnames    ClusterIP   10.96.132.245   <none> 80/TCP 4s
 
设置pod后端
[root@m3 ~]# vim deploy-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostnames
spec:
  selector:
    matchLabels:
      app: hostnames
  replicas: 2
  template:
    metadata:
      labels:
        app: hostnames
    spec:
      containers:
      - name: hostnames
        image: k8s.gcr.io/serve_hostname
        ports:
        - containerPort: 9376
          protocol: TCP
[root@m3 ~]# kubectl apply -f deploy-test.yaml
deployment.apps/hostnames created      
 
2. 查看后端服务
被 selector 选中的 Pod,就称为 Service 的 Endpoints,可以使用 kubectl get ep 命令看到它们
[root@m3 ~]# kubectl get endpoints hostnames
NAME        ENDPOINTS                                 AGE
hostnames   10.100.130.119:9376,10.100.152.254:9376 42m
 
Service 提供的是 Round Robin 方式的负载均衡,我们称为:ClusterIP 模式的 Service。
[root@m3 ~]# kubectl get svc hostnames
NAME        TYPE        CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostnames   ClusterIP   10.96.132.245   <none> 80/TCP 43m
[root@m3 ~]# curl 10.96.132.245:80
hostnames-78f4d6f547-6tc6q
[root@m3 ~]# curl 10.96.132.245:80
hostnames-78f4d6f547-tp7fc
 
3. iptables过滤请求到svc的规则
对于我们前面创建的名叫 hostnames 的 Service 来说,一旦它被提交给 Kubernetes,那么 kube-proxy 就可以通过 Service 的 Informer 感知到这样一个 Service 对象的添加。而作为对这个事件的响应,它就会在宿主机上创建这样一条 iptables 规则(你可以通过 iptables-save 看到它),如下所示:
[root@s3 ~]# iptables-save | grep hostnames
-A KUBE-SERVICES ! -s 10.100.0.0/16 -d 10.96.132.245/32 -p tcp -m comment --comment "default/hostnames:default cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.96.132.245/32 -p tcp -m comment --comment "default/hostnames:default cluster IP" -m tcp --dport 80 -j KUBE-SVC-ODX2UBAZM7RQWOIU
 
4. iptables将请求转发到后端
这条 iptables 规则的含义是:凡是目的地址是 10.96.132.245、目的端口是 80 的 IP 包,都应该跳转到另外一条名叫 KUBE-SVC-ODX2UBAZM7RQWOIU 的 iptables 链进行处理。
10.96.132.245 正是这个 Service 的 VIP。所以这一条规则,就为这个 Service 设置了一个固定的入口地址。并且,由于 10.96.132.245 只是一条 iptables 规则上的配置,并没有真正的网络设备,所以你 ping 这个地址,是不会有任何响应的。
[root@s3 ~]# iptables-save | grep KUBE-SVC-ODX2UBAZM7RQWOIU
:KUBE-SVC-ODX2UBAZM7RQWOIU - [0:0]
-A KUBE-SERVICES -d 10.96.132.245/32 -p tcp -m comment --comment "default/hostnames:default cluster IP" -m tcp --dport 80 -j KUBE-SVC-ODX2UBAZM7RQWOIU
-A KUBE-SVC-ODX2UBAZM7RQWOIU -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-JVSOCRZ6JY75X2W7
-A KUBE-SVC-ODX2UBAZM7RQWOIU -j KUBE-SEP-3WIYSPFWPJKZWGOR
 
这一组规则,实际上是一组随机模式(–mode random)的 iptables 链。
而随机转发的目的地,分别是KUBE-SEP-JVSOCRZ6JY75X2W7,KUBE-SEP-3WIYSPFWPJKZWGOR
[root@s3 ~]# iptables-save | grep KUBE-SEP-JVSOCRZ6JY75X2W7
:KUBE-SEP-JVSOCRZ6JY75X2W7 - [0:0]
-A KUBE-SEP-JVSOCRZ6JY75X2W7 -s 10.100.130.119/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-JVSOCRZ6JY75X2W7 -p tcp -m tcp -j DNAT --to-destination 10.100.130.119:9376
-A KUBE-SVC-ODX2UBAZM7RQWOIU -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-JVSOCRZ6JY75X2W7
 
 
需要注意的是,iptables 规则的匹配是从上到下逐条进行的,所以为了保证上述三条规则每条被选中的概率都相同,我们应该将它们的 probability 字段的值分别设置为 1/2和1。但在 DNAT 规则之前,iptables 对流入的 IP 包还设置了一个“标志”(–set-xmark)。
而 DNAT 规则的作用,就是在 PREROUTING 检查点之前,也就是在路由之前,将流入 IP 包的目的地址和端口,改成–to-destination 所指定的新的目的地址和端口。可以看到,这个目的地址和端口,正是被代理 Pod 的 IP 地址和端口。这样,访问 Service VIP 的 IP 包经过上述 iptables 处理之后,就已经变成了访问具体某一个后端 Pod 的 IP 包了。
 
5. service使用iptables总结
如果 kube-proxy 一切正常,你就应该仔细查看宿主机上的 iptables 了。而一个 iptables 模式的 Service 对应的规则,我在上一篇以及这一篇文章里已经全部介绍到了,它们包括:
  1. KUBE-SERVICES 或者 KUBE-NODEPORTS 规则对应的 Service 的入口链,这个规则应该与 VIP 和 Service 端口一一对应;
  2. KUBE-SEP-(hash) 规则对应的 DNAT 链,这些规则应该与 Endpoints 一一对应;
  3. KUBE-SVC-(hash) 规则对应的负载均衡链,这些规则的数目应该与 Endpoints 数目一致;
  4. 如果是 NodePort 模式的话,还有 POSTROUTING 处的 SNAT 链。
 
Service异常排查思路
当你的 Service 没办法通过 DNS 访问到的时候。
  1. 集群的 DNS是否正常
  2. Service 本身的配置问题
    1. Service 是否有 Endpoints:
    2. 通过kube-proxy日志确认 kube-proxy 是否在正确运行
    3. 查看iptables规则
  3. Pod 没办法通过 Service 访问到自己

猜你喜欢

转载自www.cnblogs.com/wangzhangtao/p/12168676.html