searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

K8s Service如何实现集群外访问

2023-09-01 01:21:53
62
0

Kubernetes(K8s)Service提供了一种机制,使得集群内的应用程序可以从集群外部进行访问。通过使用不同类型的Service(如NodePort、LoadBalancer和Ingress),Kubernetes实现了不同级别的集群外访问。NodePort为每个节点分配了一个静态端口,使得外部流量可以通过节点访问服务。LoadBalancer通过云服务商提供的负载均衡器将流量分配到集群中的服务。Ingress则提供了更高级的路由功能,允许基于域名和路径将流量转发到不同的服务。K8s Service为集群外部用户提供了可靠且灵活的访问方式,使得应用程序可以无缝地与外部系统进行交互。

NodePort类型Service如何定义?

nodePort->servicePort->podPort

apiVersion: v1

kind: Service

metadata:

name: service-nodeport

namespace: dev

spec:

selector:

app: nginx-pod

type: NodePort # service类型

ports:

- port: 80

nodePort: 30002 # 指定绑定的node的端口(默认的取值范围是:30000-32767), 如果不指定,会默认分配

targetPort: 80

nodeport和clusterip的service端口展示对比

nodeport:

[root@master k8sYamlForCSDN]# kubectl get svc service-nodeport -n dev

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

service-nodeport NodePort 10.99.95.186 <none> 80:30002/TCP 11s

clusterIp:

[root@master k8sYamlForCSDN]# kubectl get svc -n dev -o wide

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR

service-clusterip ClusterIP 10.97.97.97 <none> 80/TCP 17s app=nginx-pod

NodePort类型Service实现原理?

NodePort 模式也就非常容易理解了。显然,kube-proxy 要做的,就是在每台宿主机上生成这样一条 iptables 规则

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - nodePort: 8080
    targetPort: 80
    protocol: TCP
    name: http
  selector:
    run: my-nginx

Iptables规则:nodePort(8080)->service

  • 控制面:
    • 添加Iptables规则:让nodeport转给svc
      • -A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx: nodePort" -m tcp --dport 8080 -j KUBE-SVC-67RL4FN6JRUPOJYM
      • 表示:访问nodeport80端口,则跳转给service规则:KUBE-SVC-67RL4FN6JRUPOJYM
      • 所以接下来的流程,就跟 ClusterIP 模式完全一样了
    • 添加Iptables规则:NodePort 方式下,Kubernetes 会在 IP 包离开宿主机发往目的 Pod 时,对这个 IP 包做一次 SNAT 操作
      • -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE
      • 只对service转发的做SNAT, IP 包是否有一个“0x4000”的“标志”,认为是service转发的
      • IP 包的源地址替换成了这台宿主机上的 CNI 网桥地址,或者宿主机本身的 IP 地址(如果 CNI 网桥不存在的话)
  • 数据面:
    • 请求进入node节点机器,被Iptable拦截,如果是访问指定nodeport端口,则转给service
    • service如果将请求转给其他node上的pod,会对该请求包做SNAT

NodePort类型Service,如何拿到client真实源IP?

  • 问题:
    • node2暴露nodeport,请求转发到node1上的pod时候,会做SNAT,源IP改成node2的ip
    • 但有些场景,我们的应用需要拿到client真实来源IP,如何做?
  • 解决方案:
    • 将 Service 的 spec.externalTrafficPolicy 字段设置为 local(默认值是cluster)
      • 原理:
        • ocal表示service只把请求转给当前节点的pod(即不存在SNAT),这样就可以拿到client真实来源IP
      • 缺点:
        • 转到node2上没有pod,则直接报错

LoadBalance类型Service如何定义?

---

kind: Service

apiVersion: v1

metadata:

name: example-service

spec:

ports:

- port: 8765

targetPort: 9376

selector:

app: example

type: LoadBalancer

在公有云提供的 Kubernetes 服务里,都使用了一个叫作 CloudProvider 的转接层,来跟公有云本身的 API 进行对接

LoadBalance类型Service实现原理?

Loadbalancer 的实现方面各个厂家的方案不尽一致,从大类来做下对比:

  • 控制面实现:
    • 实现方式一:
      • External Cloud Provider 直接与 Kubernetes 集群对接,监听 Kubernetes 资源对象变更事件:这种方式要求 Cloud Provider 本身支持与 Kubernetes 环境对接,兼容性和灵活性上略差;
    • 实现方式二:
      • 使用 Operator 在集群内监听 Kubernetes 事件:Kubernetes 原生建议的对接方式,集群内 Operator 可以理解为 Kubernetes 与外部负载均衡器的桥梁,可以做 API 转换等工作,灵活性很强。
  • 数据面实现:
    • 实现方式一:
      • 在集群内部署 Pod 实现负载均衡服务:将 LB 数据面直接放在 Pod 中运行,这样的好处是 LB Pod 到业务 Pod 流量路径短,理论上也支持 ClusterIP 类型服务的实现。但缺点是复杂,需要考虑 Kubernetes 兼容性、网络如何暴露、资源争夺等诸多问题;
    • 实现方式二:
      • 外部负载均衡器+NodePort:一种云厂商使用较多的方式,这种实现可以理解为 NodePort 的优化,但继承了 NodePort 的诸多缺点;
    • 实现方式三:
      • 外部负载均衡器直连 Pod:外部负载均衡器直接通过 Pod IP 访问 Pod,中间不会经过 NodePort,这种实现性能更优,而且流量路径更简化,便于排错,Avi 通常使用这种方式

0条评论
作者已关闭评论
q****n
20文章数
0粉丝数
q****n
20 文章 | 0 粉丝
q****n
20文章数
0粉丝数
q****n
20 文章 | 0 粉丝
原创

K8s Service如何实现集群外访问

2023-09-01 01:21:53
62
0

Kubernetes(K8s)Service提供了一种机制,使得集群内的应用程序可以从集群外部进行访问。通过使用不同类型的Service(如NodePort、LoadBalancer和Ingress),Kubernetes实现了不同级别的集群外访问。NodePort为每个节点分配了一个静态端口,使得外部流量可以通过节点访问服务。LoadBalancer通过云服务商提供的负载均衡器将流量分配到集群中的服务。Ingress则提供了更高级的路由功能,允许基于域名和路径将流量转发到不同的服务。K8s Service为集群外部用户提供了可靠且灵活的访问方式,使得应用程序可以无缝地与外部系统进行交互。

NodePort类型Service如何定义?

nodePort->servicePort->podPort

apiVersion: v1

kind: Service

metadata:

name: service-nodeport

namespace: dev

spec:

selector:

app: nginx-pod

type: NodePort # service类型

ports:

- port: 80

nodePort: 30002 # 指定绑定的node的端口(默认的取值范围是:30000-32767), 如果不指定,会默认分配

targetPort: 80

nodeport和clusterip的service端口展示对比

nodeport:

[root@master k8sYamlForCSDN]# kubectl get svc service-nodeport -n dev

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

service-nodeport NodePort 10.99.95.186 <none> 80:30002/TCP 11s

clusterIp:

[root@master k8sYamlForCSDN]# kubectl get svc -n dev -o wide

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR

service-clusterip ClusterIP 10.97.97.97 <none> 80/TCP 17s app=nginx-pod

NodePort类型Service实现原理?

NodePort 模式也就非常容易理解了。显然,kube-proxy 要做的,就是在每台宿主机上生成这样一条 iptables 规则

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - nodePort: 8080
    targetPort: 80
    protocol: TCP
    name: http
  selector:
    run: my-nginx

Iptables规则:nodePort(8080)->service

  • 控制面:
    • 添加Iptables规则:让nodeport转给svc
      • -A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-nginx: nodePort" -m tcp --dport 8080 -j KUBE-SVC-67RL4FN6JRUPOJYM
      • 表示:访问nodeport80端口,则跳转给service规则:KUBE-SVC-67RL4FN6JRUPOJYM
      • 所以接下来的流程,就跟 ClusterIP 模式完全一样了
    • 添加Iptables规则:NodePort 方式下,Kubernetes 会在 IP 包离开宿主机发往目的 Pod 时,对这个 IP 包做一次 SNAT 操作
      • -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE
      • 只对service转发的做SNAT, IP 包是否有一个“0x4000”的“标志”,认为是service转发的
      • IP 包的源地址替换成了这台宿主机上的 CNI 网桥地址,或者宿主机本身的 IP 地址(如果 CNI 网桥不存在的话)
  • 数据面:
    • 请求进入node节点机器,被Iptable拦截,如果是访问指定nodeport端口,则转给service
    • service如果将请求转给其他node上的pod,会对该请求包做SNAT

NodePort类型Service,如何拿到client真实源IP?

  • 问题:
    • node2暴露nodeport,请求转发到node1上的pod时候,会做SNAT,源IP改成node2的ip
    • 但有些场景,我们的应用需要拿到client真实来源IP,如何做?
  • 解决方案:
    • 将 Service 的 spec.externalTrafficPolicy 字段设置为 local(默认值是cluster)
      • 原理:
        • ocal表示service只把请求转给当前节点的pod(即不存在SNAT),这样就可以拿到client真实来源IP
      • 缺点:
        • 转到node2上没有pod,则直接报错

LoadBalance类型Service如何定义?

---

kind: Service

apiVersion: v1

metadata:

name: example-service

spec:

ports:

- port: 8765

targetPort: 9376

selector:

app: example

type: LoadBalancer

在公有云提供的 Kubernetes 服务里,都使用了一个叫作 CloudProvider 的转接层,来跟公有云本身的 API 进行对接

LoadBalance类型Service实现原理?

Loadbalancer 的实现方面各个厂家的方案不尽一致,从大类来做下对比:

  • 控制面实现:
    • 实现方式一:
      • External Cloud Provider 直接与 Kubernetes 集群对接,监听 Kubernetes 资源对象变更事件:这种方式要求 Cloud Provider 本身支持与 Kubernetes 环境对接,兼容性和灵活性上略差;
    • 实现方式二:
      • 使用 Operator 在集群内监听 Kubernetes 事件:Kubernetes 原生建议的对接方式,集群内 Operator 可以理解为 Kubernetes 与外部负载均衡器的桥梁,可以做 API 转换等工作,灵活性很强。
  • 数据面实现:
    • 实现方式一:
      • 在集群内部署 Pod 实现负载均衡服务:将 LB 数据面直接放在 Pod 中运行,这样的好处是 LB Pod 到业务 Pod 流量路径短,理论上也支持 ClusterIP 类型服务的实现。但缺点是复杂,需要考虑 Kubernetes 兼容性、网络如何暴露、资源争夺等诸多问题;
    • 实现方式二:
      • 外部负载均衡器+NodePort:一种云厂商使用较多的方式,这种实现可以理解为 NodePort 的优化,但继承了 NodePort 的诸多缺点;
    • 实现方式三:
      • 外部负载均衡器直连 Pod:外部负载均衡器直接通过 Pod IP 访问 Pod,中间不会经过 NodePort,这种实现性能更优,而且流量路径更简化,便于排错,Avi 通常使用这种方式

文章来自个人专栏
云技术专栏
20 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0