从0到1聊聊kubernetes service 到 pod的网络链路定位

本文深入探讨了Kubernetes Service的工作原理,包括Service的定义、使用场景、底层实现,以及如何通过示例分析Service到Pod的网络链路。通过了解Service的ClusterIP、NodePort、Headless等类型,以及Service如何通过iptables或ipvs实现负载均衡,有助于解决集群内部网络问题。
摘要由CSDN通过智能技术生成

导语

最近一个环境出现pod尚在not ready状态时就开始有业务流量进入;定位此问题也让我进一步加深对kubernetes集群内(service 到 pod)的网络链路的了解。另外当前kubernetes越来越普及,遇到一些关于kubernetes网络问题也会越频繁。本文将从认识kuberneres service 到kubernetes service 使用场景再到kubernetes service底层实现原理,最后通过示例方式展示如何从service到pod网络链路一步步定位分析。

认识service

Service 是 kuberneres将一组Pod暴露给外界访问的一种机制。为什么引入service?直接pod进行交互不行吗?引入service主要原因有二:

  1. pod 生命周期是短暂的,会随着发布新版本而被销毁,pod ip不固定;
  2. 一组pod负载均衡需求

而service恰好能通过标签选择器或直接与endpoint关联将一组pod进行绑定做为一组pod的统一入口和提供负载均衡能力。Service 有两种类型:service和Headless Service, Service 通常应用在无状态服务上;Headless Service 则应用在有状态服务。Service和Headless Service有什么区别呢?Service 和 Headless Service主要有如下表象区别:

  1. service 有一个cluster ip(虚拟ip)作为一组pod的统一入口,而headless service 则没有这个cluster ip;
  2. 通过service 名访问时,coredns或者kubedns会解析到service的vip地址,而headless service 则通常需要headless service 名前加上pod_name,有状态服务pod_name 都会带编号,这样coredns或者kubedns就可以直接解析到具体的pod实例。
    service vs headless service
    为什么有了service还需要引入headless service呢?引入headless service为了解决有状态服务既要解决pod ip不固定并且还需要固定访问具体的pod(mysql 的主或者备)的问题。service 会采用负载均衡的方式引流到后端,无法固定;而headless service 通过结合coredns/kubedns解析后直接对接具体的pod。上面聊了这么多,接下来看看Service面纱背后面目:
apiVersion: v1
kind: Service # 定义当前kuernetes资源类型为Service
metadata:
  name: my-service # service 名称
spec:
  selector: # 标签选择器与一组pod进行绑定
    app: MyApp # Pod上定义的一组标签
  ports:
    - protocol: TCP # 对外暴露的协议
      port: 80 # service 的端口
      targetPort: 9376 # pod监听端口

上面是通常使用的Service定义,那headless service又如何定义?其实只需要spec.clusterIP值设置为"None" 即可。

service使用场景

对Service有了一定认识,接下来聊聊Service的使用场景。

1. ClusterTpye

clusterType 场景很普遍,通常集群内通信几乎均采用clusterType类型场景;clusterType类型会创建一个虚拟ip地址作为一组pod的统一入口以及负载均衡。例子:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: kibana
    heritage: Tiller
    release: kibana
  name: kibana-kibana
  namespace: default
spec:
  ports:
  - name: http # 当一个service需要对外暴露多个端口时,需要加名称加以区分
    port: 5601 
    protocol: TCP
    targetPort: 5601
  selector:
    app: kibana
    release: kibana
  sessionAffinity: None # 默认时rr(round-robin轮询),可以设置为: ClientIP,基于客户端ip的会话保持类似ha的source ip,nginx的ip_hash
  type: ClusterIP # 定义为cluster Type类型的service,ClusterIP也是默认的service类型

通过使用

kubectl get svc $SERVICE_NAME -n $NAME_SPACES 
[root@VM_70_26_centos ~]# kubectl get svc -n default
NAME                            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
elasticsearch-master            ClusterIP   172.x.y.127   <none>        9200/TCP,9300/TCP            6d6h
elasticsearch-master-headless   ClusterIP   None            <none>        9200/TCP,9300/TCP            6d6h
kafka                           ClusterIP   172.x.y.142   <none>        9092/TCP                     6d6h
kafka-headless                  ClusterIP   None            <none>        9092/TCP                     6d6h
kafka-manager                   ClusterIP   172.x.y.198   <none>        9000/TCP                     6d6h
kafka-zookeeper                 ClusterIP   172.x.y.86    <none>        2181/TCP                     6d6h
kafka-zookeeper-headless        ClusterIP   None            <none>        2181/TCP,3888/TCP,2888/TCP   6d6h
kibana-kibana                   ClusterIP   172.x.y.143   <none>        5601/TCP                     6d6h

获取当前namespace下的service 列表. 使用

kubectl describe svc $SERVICE_NAME -n $NAME_SPACES 
[root@VM_70_26_centos ~]# kubectl describe svc kibana-kibana -n pot 
Name:              kibana-kibana
Namespace:         pot
Labels:            app=kibana
                   heritage=Tiller
                   release=kibana
Annotations:       <none>
Selector:          app=kibana,release=kibana
Type:              ClusterIP
IP:                172.x.y.143
Port:              http  5601/TCP
TargetPort:        5601/TCP
Endpoints:         172.x.z.8:5601 # pod ip+port
Session Affinity:  None
Events:            <none>

查看service事件信息。使用

kubectl get svc $SERVICE_NAME -n $NAME_SPACES -o yaml

查看当前service配置内容。

2. NodePort

当一组pod需要跨集群或需要提供集群外访问能力时可以采用NodePort模式,使用NodePort方式会在集群内所有节点占用一个宿主机端口(默认值:30000-32767),可以通过–service-node-port-range设置端口范围段,为此使用此场景需要注意端口规划;访问时直接访问kubernetes集群中任意节点IP+映射的宿主机端口即可。

apiVersion: v1
kind: Service
labels:
    app: kibana
    heritage: Tiller
    release: kibana
  name: kibana-kibana
  namespace: default
spec:
  - name: http
    port: 5601 
    protocol: TCP
    targetPort: 5601
  selector:
    app: kibana
    release: kibana
  sessionAffinity: None
  type: NodePort # 只需要将type 类型改为NodePort即可。

3. Headless

Headless service 主要应用在statefulset(有状态服务),对于有状态服务有的需要固定访问,比如mysql主从模式时需要写的时候通过service 访问时候不能轮训模式,因为只有主节点可以写,这时候就需要headless service,通过访问$pod_name.$headless_service_name.$namespace.svc.cluster.local coredns/kubedns就会将此域名解析到具体的pod ip实现固定访问。

apiVersion: v1
kind: Service
metadata:
  labels:
    app: kibana
    heritage: Tiller
    release: kibana
  name: kibana-kibana
  namespace: default
spec:
  clusterIP: None # 只需要将clusterIP设置为None即可
  ports:
  - name: http 
    port: 5601 
    protocol: TCP
    targetPort: 5601
  selector:
    app: kibana
    release: kibana
  sessionAffinity: None 
  type: ClusterIP

4. LoadBalancer

当一组pod需要跨集群或需要提供集群外访问除了上述提到的NodePort方式,还可以对接IaaS层的负载均衡器,当然这个是需要编写对应的driver实现注册到IaaS的LoadBalancer,这种场景在云上(腾讯云,阿里云,华为云,ucloud等)已经做好了集成;不同厂商需要添加的annotations不一样,annotations届时看所应用的厂商配置说明即可,但根还是一样的。这种方式就解决了NodePort端口规划以及当某个节点异常了也会导致统一入口的高可用问题。以下annotations 以腾讯云tke为例:

apiVersion: v1
kind: Service
metadata:
  annotations: # annotations 部分需要根据不同厂商而定
    service.kubernetes.io/loadbalance-id: lb-xxx
    service.kubernetes.io/qcloud-loadbalancer-clusterid: cls
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值