kubernetes-Service类型介绍、NodePort、LoadBalancer、ExternalName、服务发现

313 阅读10分钟

流量分发

  • iptables/ipvs 取决于kube-roxy的配置

    • configmap/kube-proxy kube-system
  • 当client访问服务(pod)时

    • 访问同一个实例的 不同的副本
    • 访问分布式的服务
  • 服务入口

    • 东西流量 南北流量
    • client -->service ip:port---> pod ip:port

service类型

  • ClusterIP 仅支持集群内的 客户端请求, 这个是集群内的IP

  • NodePort 全方位的地址转换, 源目标 地址转换

    • 核心作用 接入集群外部的客户端 对service的请求
    • NodeIP + Nodeport是介入外部流量的接口
      • 30000-32768端口
  • LoadBalancer

    • client ---> LB IP(附着在某个NODE):LB PORT---> POD IP:PORT
      • NODE到POD 可能还会经过一次负载均衡
      • LB的负载均衡算法 挑选出NODE
      • NodePort的负载均衡算法 挑出Pod
      • 可能出现二次转发, 所以尽可能选出的Node和Pod在一起 避免流量大的问题
    • externalTrafficPolicy
      • local 当一个节点收到请求后 只能调用当前Node运行的Pod
      • cluster
  • ExternalName

    • 让用户把运行于外部的流量 接入 到集群内部

一些组织将生产环境 前到k8s 要经历的步骤

  • 第一阶段: 先迁移无状态服务 无状态应用, 如果要请求有状态服务的话 只能请求外部
    • 方式1 写死请求地址IP PORT
    • 方式2 将有状态服务的 dns名称 做一个别名 放到k8s中
  • 第二阶段: 逐渐迁移有状态应用
  • 第三阶段: 应用重构 重复利用k8s的重写整个应用
  • 第四阶段: 微服务化

re-platform 面向k8s重新做优化

re-host 将面向裸机 转换到容器内

ExternalName的使用场景 pod client -->访问 servicename:serviceport -->解析成externalServiceDNSName:serviceport -->externalDNS(外部的DNS) -->解析成外部的 ExternalhostIP 即serviceip:port(外部的服务)

endpoint资源

对于每个service 都存在一个与之同名的 EndpointSlice对象 创建的方式 - 在本身不存在的情况下 会自动创建Endpoint资源 - 在本身存在的情况下 会直接引用该Endpoint资源

手动创建Endpoint资源 关联的上游断点的IP 不是自动发现, 由用户静态指定的(外部断点的服务地址)

访问路径: pod client --> servicename:serviceport --->解析成 serviceip:serviceport--->直接到达externalHostIP:port

Headless Service

创建service的时候 明确指定不配置clusterIP 但依然会使用label selector 访问路径 pod client --->servicename:serviceport --->解析成PodIP

特殊的service

image.png 对比常规的路径Service解析的结果: ServiceName --->ServiceIP--->PodIP ExternalName:

  • ServiceName解析的结果 是外部的服务地址ExternaleServiceName 是一个DNS地址
  • ServiceName解析的结果 依然是ServiceIp(上游端点 是外部的IP地址ExternalIp)
  • ServiceName解析的结果 直接到PodIP

Service 介绍

image.png

Service是Kubernetes标准的API资源类型之一

功能1 为动态的Pod资源提供近似静态的流量入口

- 负责服务发现:通过标签选择器筛选同一名称空间下的Pod资源的标签,完成Pod筛选 
    - 实际上是由与Service同名的Endpoint或EndpointSlice资源及控制器完成 
    - 自动创建Endpoint资源
- 负责流量调度:由运行各工作节点的kube-proxy根据配置的模式生成相应的流量调度规则
    - iptables 
    - ipvs

配置策略

image.png

功能2 持续监视着相关Pod资源的变动,并实时反映至相应的流量调度规则之上

  • 服务发现

Service服务发现

  • 以pod形式运行的服务
  • pod添加lable 后面通过 lable selector
  • 注解

动态可配置负载均衡

image.png

从Service的视角来看,Kubernetes集群的每个工作节点都是动态可配置的负载均衡器

  • 对于隶属某Service的一组Pod资源,该Service资源能够将集群中的每个工作节点配置为该组Pod的负载均衡器
  • 客户端可以是来自集群之上的Pod,也可以是集群外部的其它端点
  • 对于一个特定的工作节点上的某Service来说,其客户端通常有两类
    • 集群内部的client(该节点之上的进程) 可通过该Service的Service_IP:Service_Port 访问进入
    • 集群外部的client(该节点之外的端点) 可经由Node_IP:Node_Port 访问进入
      • iptable中存在 NAT规则

问题

显然,若客户端进入的节点,并非目标Pod所在的节点时,报文转发的路径中必然存在跃点 我们期望访问node的时候 直接将流量给当前node上的pod 不要再经过其他的路由

解决方案:

client-->外部的负载均衡器(决定调用哪个NodeIP)-->Node_IP:Node_Port

外部的负载均衡器 请求apiserver 获取当前service关联的pod 以及 pod所在的节点, 当外部的负载均衡器接收到请求时 直接将流量调度给运行了该pod的node节点

Service类型

可以分为4种类型

ClusterIP

仅支持集群内部的client访问, 因为需要通过节点的内核进行转发 支持Service_IP:Service_Port接入;

NodePort

image.png

支持Node_IP:Node_Port接入,同时支持ClusterIP 增强版的ClusterIP

LoadBalancer(需要自己开发)

image.png

支持通过外部的LoadBalancer的LB_IP:LB_Port接入,同时支持NodePort和ClusterIP;

  • Kubernetes集群外部的LoadBalancer负责将接入的流量转发至工作节点上的NodePort
  • LoadBalancer需与相关的NodePort的Service生命周期联动
  • LoadBalancer 需要和apiserver联动 获取当前service关联的pod 以及 pod所在的节点
    • LoadBalancer应该是由软件定义
    • Kubernetes需要同LoadBalancer所属的管理API联动

ExternalName

应用部署在k8s内部 数据库在集群外部 两者通信怎么办?

  • 让用户把运行于外部的流量 接入 到集群内部
  • 负责将集群外部的服务引入到集群中
  • 需要借助于ClusterDNS上的CNAME资源记录完成
  • 特殊类型,无需ClusterIP和NodePort
  • 无须定义标签选择器发现Pod对象

k8s内部的服务 访问外部的mysql怎么办?

  • 直接访问外网IP
  • 手工定义成集群内的一个service
    • 手工定义endpoint 写上外部的ip
    • externalname 指向一个 dns dns然后解析到外部的mysql

三种网络 service network node network pod network

创建Service资源

image.png

由Service表示的负载均衡器,主要定义如下内容

  • 负载均衡器入口:ClusterIP及相关的Service Port、NodePort(每个节点的Node IP都可用)
    • 根据通信需求,确定选择的类型
  • 标签选择器:用于筛选Pod,并基于筛选出的Pod的IP生成后端端点列表(被调度的上游端点)
  • Service类型的专有配置

标签和标签选择器

标签:附加在资源对象上的键值型元数据

  • 键标识:由“键前缀(可选)”和“键名”组成,格式为“key_prefix/key_name”
    • 键前缀必须使用DNS域名格式
    • 键名的命名格式:支持字母、数字、连接号、下划线和点号,且只能以字母或数字开头;最长63个字符;
  • “kubectl label”命令可管理对象的标签

标签选择器:基于标签筛选对象的过滤条件,支持两种类型

  • 基于等值关系的选择器
    • 操作符:=或==、!=
  • 基于集合关系的选择器
    • 操作符:in、notin和exists
    • 使用格式:KEY in (VALUE1, VALUE2, …)、 KEY notin (VALUE1, VALUE2, …)、KEY 和 !KEY

Service资源规范

规范

apiVersion: v1 
kind: Service 
metadata: 
    name:  
    namespace:  
spec: 
    type # Service类型,默认为ClusterIP 
    selector # 等值类型的标签选择器,内含“与”逻辑 
    ports: # Service的端口对象列表 
    - name # 端口名称 
      protocol # 协议,目前仅支持TCP、UDP和SCTP,默认为TCP 
      port # Service的端口号 
      targetPort # 后端目标进程的端口号或名称,名称需由Pod规范定义 
      nodePort # 节点端口号,仅适用于NodePort和LoadBalancer类型 
    clusterIP # Service的集群IP,建议由系统自动分配 
    externalTrafficPolicy # 外部流量策略处理方式,Local表示由当前节点处理,Cluster表示向集群范围调度 
    loadBalancerIP # 外部负载均衡器使用的IP地址,仅适用于LoadBlancer 
    externalName # 外部服务名称,该名称将作为Service的DNS CNAME值

创建pod

kubectl create deployment demoapp --image=ikubernetes/demoapp:v1.0 --replicas=3


root@k8s-master01:~# kubectl get pods -o wide --show-labels
NAME                      READY   STATUS    RESTARTS      AGE     IP            NODE           NOMINATED NODE   READINESS GATES   LABELS
demoapp-75f59c894-7kmns   1/1     Running   0             4m30s   10.244.1.10   k8s-master02   <none>           <none>            app=demoapp,pod-template-hash=75f59c894
demoapp-75f59c894-dqzvp   1/1     Running   0             4m30s   10.244.2.10   k8s-master03   <none>           <none>            app=demoapp,pod-template-hash=75f59c894
demoapp-75f59c894-rwfkl   1/1     Running   0             4m30s   10.244.0.19   k8s-master01   <none>           <none>            app=demoapp,pod-template-hash=75f59c894
redis-pv-pod              1/1     Running   3 (66m ago)   5d22h   10.244.2.8    k8s-master03   <none>           <none>            app=redis
volumes-hostpath-demo     1/1     Running   8 (66m ago)   5d23h   10.244.1.8    k8s-master02   <none>           <none>            app=redis

创建一个ClusterIP类型的service 生成一个定义文件 service_demoapp_cluster_ip.yml

root@k8s-master01:~# kubectl create service clusterip demoapp_cluster_ip --tcp=80:80 --dry-run=client -o yaml  

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: demoapp
  name: demoapp
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: demoapp_cluster_ip
  type: ClusterIP
status:
  loadBalancer: {}

测试连通性

root@k8s-master01:~# kubectl apply -f service_demoapp_cluster_ip.yml                                         
root@k8s-master01:~# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
demoapp      ClusterIP   10.106.219.38   <none>        80/TCP    5s
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   9d
root@k8s-master01:~# ping 10.106.219.38 
PING 10.106.219.38 (10.106.219.38) 56(84) bytes of data.
^C
--- 10.106.219.38 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

root@k8s-master01:~# curl 10.106.219.38 
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.1, ServerName: demoapp-75f59c894-rwfkl, ServerIP: 10.244.0.19!
root@k8s-master01:~# curl 10.106.219.38 
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp-75f59c894-7kmns, ServerIP: 10.244.1.10!
root@k8s-master01:~# curl 10.106.219.38 
iKubernetes demoapp v1.0 !! ClientIP: 10.244.0.0, ServerName: demoapp-75f59c894-dqzvp, ServerIP: 10.244.2.10!

创建一个nodeport类型的service

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: demoapp-nodeport
  name: demoapp-nodeport
spec:
  ports:
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: demoapp
  type: NodePort
status:
  loadBalancer: {}

查看创建的资源 注意生成了一个31671的端口 这个可以从集群外部进行访问

root@k8s-master01:~# kubectl apply -f service_node_port.yml 
service/demoapp-nodeport created
root@k8s-master01:~# kubectl get svc -o wide
NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE    SELECTOR
demoapp            ClusterIP   10.106.219.38   <none>        80/TCP         6m9s   app=demoapp
demoapp-nodeport   NodePort    10.111.40.126   <none>        80:31671/TCP   6s     app=demoapp
kubernetes          ClusterIP   10.96.0.1       <none>        443/TCP        9d     <none>

集群外测试联通 image.png

跃点问题

externalTrafficPolicy: local 哪个节点接入 就把流量调度给这个节点上的pod

如果你使用一个外部负载均衡器来检查它端点的运行状况(就像 AWS ELB 所做的那样),它就会只将流量发送到应该接收流量的节点上,这样就能改善延迟、减少计算开销、降低出口成本并提升健全性。

NodePort Service流量策略

流量策略一:externalTrafficPolicy: Cluster

image.png 表示在整个Kubernetes集群范围内调度;

  • 该流量策略下,请求报文从某个节点上的NodePort进入,该节点 上的Service会将其调度至任何一个可用后端Pod之上,而不关心 Pod运行于哪个节点;

流量策略二:externalTrafficPolicy: Local

表示仅将请求调度至当前节点上运行的 可用后端端点;

  • 该流量策略下,请求报文从某节点NodePort进入后,该节点上的 Service仅会将请求调度至当前节点上适配到该Service的后端端点
  • 仅应该从运行有目标Service对象后端Pod对象的节点的NodePort 发起访问
  • 需要在上层做一个loadbalancer

image.png