k8s

hostport和hostNetwork区别

介绍

hostport需要cni插件支持,比如calico,flannel等都支持该功能。如果你想要启动hostPort,则必须在cni的配置文件中指定portMappings capability

cat /etc/cni/net.d/10-calico.conflist

file

hostNetwork:true,开启后pod内服务可以访问到宿主机网络,局域网内其他服务也可以直接访问该服务。

区别

相同点

  • hostport和hostNetwork都可以实现外部服务访问集群内服务。
  • 可以用宿主机IP+容器端口或hostport端口进行访问。

不同点

  1. 网络地址空间不同。hostport使用CNI分配的地址,hostNetwork使用宿主机网络地址空间;
  2. 宿主机端口生成。hostport宿主机不生成端口,hostNetwork宿主机生成端口;
  3. hostport通过iptables防火墙的nat表进行转发,hostNetwork 直接通过主机端口到容器中;
  4. 定义的路径不同。deploy.spec.template.spec.containers.ports.hostPortdeploy.spec.template.spec.hostNetwork
  5. 优先级不同,hostNetwork高于hostPort。

hostport原理

部署服务

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:stable-alpine
        ports:
        - containerPort: 80
          hostPort: 10000
          name: http
          protocol: TCP

部署nginx服务,查看主机上没有监听10000端口。

file

使用hostport端口访问nginx服务,可以正常访问。

curl 172.16.255.180:10000

file

查看iptables nat表规则,确定是通过iptables进行转发的。

k get po nginx-666b766f9c-g9dc8 -o wide
iptables -t nat -nvL | grep 192.168.137.84:80

file

转发路径

我的环境中kube-proxy是ipvs模式。

file

所以当外部客户端访问当前节点的容器时,流量包通常会先后经过以下链:

  1. PREROUTING 链(iptables): 外部流量进入主机后,首先经过 PREROUTING 链(位于 nat 表),这是网络地址转换(NAT)处理的第一个步骤。你可以在 PREROUTING 链中创建规则,以便将流量导入其他自定义的 iptables 链或 ipvs 转发路径。
  2. IPVS 转发路径: 如果你使用了 ipvs 来进行负载均衡,外部流量可能会直接进入 ipvs 的负载均衡路径。这是流量被转发到正确的后端 Pod 的地方,绕过了 iptables 的后续处理。
  3. FORWARD 链(iptables): 如果流量需要在主机内部进行转发,它会进入 FORWARD 链(位于 filter 表),在这里可以进行进一步的处理,例如网络策略、防火墙规则等。
  4. POSTROUTING 链(iptables): 流量最终经过 POSTROUTING 链(位于 nat 表),这是 NAT 处理的最后一步。你可以在这里进行出站流量的地址转换等处理。

大体上会按照 PREROUTING -> IPVS -> FORWARD -> POSTROUTING 的顺序进行处理。但是,实际流量的经过路径可能会受到你的网络配置的影响。

PREROUTING链

外部流量进来后首先经过cali-PREROUTING链,然后到KUBE-SERVICES链,再到DOCKER链,匹配不成功后到CNI-HOSTPORT-DNAT链。

file

然后查看CNI-HOSTPORT-DNAT链规则。dnat名字为k8s-pod-network,id是nginx pod的pause容器id。

file

file

再查看CNI-DN-2fe3a07970a494f609ee7链规则。只要访问当前节点的10000端口,都会进行dnat转换,转换成PodIP:Pod端口,这里就是nginx pod的192.168.137.102:80

file

IPVS规则

查找关于10000端口的规则,没有输出。

ipvsadm -L -n | grep 10000

file

FORWARD链规则

FORWARD链在filter和mangle表中。前者用于对数据包进行过滤,后者用于修改数据包的服务类型,生存周期,为数据包设置标记,实现流量整形、策略路由等。

iptables -t filter -nvL FORWARD
iptables -t mangle -nvL FORWARD

file

可以看到没有CNI-HOSTPORT链相关规则。

POSTROUTING链规则

流量到达cali-POSTROUTING链后,转发到CNI-HOSTPORT-MASQ链,这个链就是hostport相关的链。

file

再查看CNI-HOSTPORT-MASQ链的规则,MASQUERADE在hostport的流量出去时将源地址转换成主机网卡的ip,并对数据包打标签。

file

最后根据路由将数据包发送到pod内。

hostnetwork原理

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      containers:
      - name: nginx
        image: nginx:stable-alpine

查看pod ip为主机ip,主机上启动了容器的80端口。

file

这时可以直接通过主机ip+80端口访问服务。

dns策略

pod的yaml中定义了dnsPolicy,这个有什么用呢?

  • Default: Pod 从运行所在的节点继承名称解析配置。
  • ClusterFirst: 与配置的集群域后缀不匹配的任何 DNS 查询(例如 "www.kubernetes.io") 都会由 DNS 服务器转发到上游名称服务器。集群管理员可能配置了额外的存根域和上游 DNS 服务器。
  • ClusterFirstWithHostNet: 对于以 hostNetwork 方式运行的 Pod,应将其 DNS 策略显式设置为 "ClusterFirstWithHostNet"。否则,以 hostNetwork 方式和 "ClusterFirst" 策略运行的 Pod 将会做出回退至 "Default" 策略的行为。注意:这在 Windows 上不支持。
  • None: 此设置允许 Pod 忽略 Kubernetes 环境中的 DNS 设置。Pod 会使用其 dnsConfig 字段所提供的 DNS 设置。

说人话就是:如果nginx服务有多个pod,如果没有使用ClusterFirstWithHostNet,那么这些pod就无法通过svc name访问集群中其他pod。开启该参数之后,pod内的/etc/resolv.conf中dns服务器的地址就会被设置为k8s集群的dns地址。这样就可以访问其他服务。

file

去掉ClusterFirstWithHostNet后,pod的dns就变成了主机dns,无法通过svc访问其他服务。

file

总结

虽然hostport和hostNetwork都可以对外暴露服务,但是一般不要为Pod指定hostPort,除非非常有必要这样做。当你为Pod绑定了hostPort,那么能够运行该Pod的节点就有限了,因为每个 <hostIP, hostPort, protocol> 组合必须是唯一的。

如果你没有明确指定hostIP和protocol,k8s将使用 0.0.0.0 作为默认的hostIP,使用TCP作为默认的protocol。hostNetwork同样的原因也不建议使用。

分类: k8s
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
内联反馈
查看所有评论

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x