1、概述

在 Kubernetes 中,hostPort 是一种用于将主机上的特定端口映射到运行在 Pod 内部容器的端口的配置选项。通过使用 hostPort,你可以在主机上暴露容器的服务,从而允许外部网络通过主机的 IP 地址和指定的端口访问容器内的应用程序。如:

apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-v1-deployment
spec:
replicas: 2
selector:
matchLabels:
app: tomcat-v1
template:
metadata:
labels:
app: tomcat-v1
spec:
containers:
- name: tomcat
image: tomcat
ports:
- containerPort: 8080
hostPort: 9000

注意 1:hostPort 与 NodePort 的区别是,NodePort 服务默认是把请求转发到随机的一个运行的 Pod 上,而 hostPort 是直接转发到本 Node 上的指定 Pod。

一个 Node 只能启动一个 hostPort,所以最初是用于把守护进程集(DaemonSets)部署到每个 Node (确保一个 Node 只有一个 hostPort )。如下图所示,3个 Node 上部署4个带 hostPort 的 Pod,会有一个不成功。

即便是3个 Node 上部署3个带 hostPort 的 Pod 滚动升级时也会有问题,所以使用 hostPort 的服务在升级的时候一定要保障先停掉旧版本的 Pod 实例再启动新版本的 Pod 实例,服务升级这块内容配置详情可以参见 《Kubernetes应用编排与管理 —— Deployment升级策略》这篇博文。

2、hostPort 与 hostNetwork 的异同

讲到 hostPort 就不得不提 hostNetwork。hostNetwork 也是一种用于将主机上的特定端口映射到运行在 Pod 内部容器的端口的配置选项,对于客户端来说这两种访问方式都是一样的,但是它们的原理却大不相同,下面说一下 hostPort 与 hostNetwork 的异同。

相同点:

  1. hostPort 与 hostNetwork 本质上都是终端用户能访问到pod中的业务;
  2. 访问的时候,只能用 pod所有宿主机IP + 容器端口或 hostport 端口进行访问。

不同点:

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

hostPort 截图:

hostNetwork 截图:

3、hostPort 原理

(1)示例环境

当前示例Kubernetes集群节点信息如下(共五个节点,k8s版本为1.21.14):

[root@master1 ~]# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master1 Ready control-plane,master 19d v1.21.14 10.20.32.201 <none> Kylin Linux Advanced Server V10 (Lance) 4.19.90-52.22.v2207.ky10.x86_64 docker://20.10.9
master2 Ready control-plane,master 19d v1.21.14 10.20.32.202 <none> Kylin Linux Advanced Server V10 (Lance) 4.19.90-52.22.v2207.ky10.x86_64 docker://20.10.9
master3 Ready control-plane,master 19d v1.21.14 10.20.32.203 <none> Kylin Linux Advanced Server V10 (Lance) 4.19.90-52.22.v2207.ky10.x86_64 docker://20.10.9
worker1 Ready worker 19d v1.21.14 10.20.32.204 <none> Kylin Linux Advanced Server V10 (Lance) 4.19.90-52.22.v2207.ky10.x86_64 docker://20.10.9
worker2 Ready worker 19d v1.21.14 10.20.32.205 <none> Kylin Linux Advanced Server V10 (Lance) 4.19.90-52.22.v2207.ky10.x86_64 docker://20.10.9

当前集群kube-proxy模式为ipvs:

[root@master1 ~]# kubectl get configmaps -n=kube-system kube-proxy -o yaml|grep mode
mode: ipvs

(2)示例

启动一个 Pod 示例,其是使用 Go 语言来创建一个简单的 HTTP 服务器,使用 hostPort 将主机上的 80 端口映射到运行在 Pod 内部的容器端口上,其调度到 woker1 (10.20.32.204)节点上。

客户端通过主机 ip:hostPort 访问服务能够正常响应。

(3)原理解析

3.1)节点外客户端访问当前节点容器

现在连接到 worker1 机器,由于当前集群 kube-proxy 模式选用的是 ipvs,所以当外部客户端的访问当前节点的容器时,流量包通常会先后经过以下链:

  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 的顺序进行处理。但是,实际流量的经过路径可能会受到你的配置和网络堆栈的影响,所以在进行流量管理和路由时,请务必仔细考虑你的需求和设置。

3.1.1)分析 PREROUTING 链规则

外部流量进来后首先经过PREROUTING 链,通过规则匹配只要是访问当前节点的80端口,都会进行dnat转换,转换成 PodIP:Pod端口。

3.1.2)分析 IPVS 规则

执行 ipvsadm -L -n 命令查看当前节点 IPVS 规则,在规则中没有查找到 10.20.32.204:80 匹配项。

3.1.3)分析 FORWARD 链规则规则

无 CNI-HOSTPORT 相关规则。

3.1.4)分析 POSTROUTING 链规则

CNI-HOSTPORT_MASQ规则在最前面,并且无需源地址转换。

3.1.5) 抓包验证

进入示例容器网络命令空间:

[root@worker1 ~]# docker ps|grep http-request-printer
267f462be8b6 25585bdfb0f7 "/usr/local/bin/pilo…" About an hour ago Up About an hour k8s_istio-proxy_http-request-printer-v1-856959f7d9-kxx6g_tracing_fa8a0a82-e233-4757-ba28-f16eb2d311f4_0
e60564d42fc6 6246a84777e8 "./http_request_prin…" About an hour ago Up About an hour k8s_container-rr19ea_http-request-printer-v1-856959f7d9-kxx6g_tracing_fa8a0a82-e233-4757-ba28-f16eb2d311f4_0
432a811e77e1 10.20.32.201:80/cloudbases/pause:3.4.1 "/pause" About an hour ago Up About an hour k8s_POD_http-request-printer-v1-856959f7d9-kxx6g_tracing_fa8a0a82-e233-4757-ba28-f16eb2d311f4_0
[root@worker1 ~]# nsenter -n -t 308222
nsenter: cannot open /proc/308222/ns/net: No such file or directory
[root@worker1 ~]# docker ps|grep http-request-printer
267f462be8b6 25585bdfb0f7 "/usr/local/bin/pilo…" About an hour ago Up About an hour k8s_istio-proxy_http-request-printer-v1-856959f7d9-kxx6g_tracing_fa8a0a82-e233-4757-ba28-f16eb2d311f4_0
e60564d42fc6 6246a84777e8 "./http_request_prin…" About an hour ago Up About an hour k8s_container-rr19ea_http-request-printer-v1-856959f7d9-kxx6g_tracing_fa8a0a82-e233-4757-ba28-f16eb2d311f4_0
432a811e77e1 10.20.32.201:80/cloudbases/pause:3.4.1 "/pause" About an hour ago Up About an hour k8s_POD_http-request-printer-v1-856959f7d9-kxx6g_tracing_fa8a0a82-e233-4757-ba28-f16eb2d311f4_0
[root@worker1 ~]# docker inspect --format "{{.State.Pid}}" 267f462be8b6
145003
[root@worker1 ~]# nsenter -n -t 145003
[root@worker1 ~]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet 10.233.1.133 netmask 255.255.255.0 broadcast 10.233.1.255
ether 2e:2c:82:08:eb:8e txqueuelen 0 (Ethernet)
RX packets 15372 bytes 9093248 (8.6 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 14493 bytes 23701690 (22.6 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
RX packets 8483 bytes 37018407 (35.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8483 bytes 37018407 (35.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [root@worker1 ~]#

抓包来确定进入容器中的包没有进行源地址转换(抓包时客户端 10.20.32.201 通过 curl http://10.20.32.204:80 命令访问此服务)。

[root@worker1 ~]# tcpdump -i eth0 host 10.233.1.133 and dst port 80 -w svc_host_port.pcap
dropped privs to tcpdump
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C6 packets captured
6 packets received by filter
0 packets dropped by kernel

将抓的包下载到本地通过并使用 wireshark 软件进行分析,可以看到当节点外客户端通过 hostPort 访问容器时,进入容器中的包没有进行源地址转换。

3.2)节点上客户端访问当前节点容器

现在连接到 worker1 机器,由于当前集群 kube-proxy 模式选用的是 ipvs,所以当当前节点客户端的访问当前节点的容器时,流量包通常会先后经过以下链:

OUTPUT -> IPVS  -> POSTROUTING 

3.2.1)分析 OUTPUT 链规则

当前节点流量先经过OUTPUT 链,通过规则匹配只要是访问当前节点的80端口,都会进行dnat转换,转换成 PodIP:Pod端口,除了源地址是PodIp或127.0.0.1时会对数据包打标签,其他规则和3.1.1中类似,这里不再赘余。

3.2.2)分析 IPVS 规则

执行 ipvsadm -L -n 命令查看当前节点 IPVS 规则,在规则中没有查找到 10.20.32.204:80 匹配项。

3.2.3)分析 POSTROUTING 链规则

CNI-HOSTPORT_MASQ规则在最前面,如果源地址是PodIp或者127.0.0.1需要源地址转换。

注意 1:没太想明白Pod是互通的,为什么源PodIP还需要进行源地址转换。

3.2.4) 路由匹配将流量发送到 Pod 里面。

4、总结

在 Kubernetes 中,hostPort 是一种用于将主机上的特定端口映射到运行在 Pod 内部容器的端口的配置选项。通过使用 hostPort,你可以在主机上暴露容器的服务,从而允许外部网络通过主机的 IP 地址和指定的端口访问容器内的应用程序。

一个 Node 只能启动一个 hostPort,所以最初是用于把守护进程集(DaemonSets)部署到每个 Node (确保一个 Node 只有一个 hostPort ),或者部署固定在特定节点的应用程序(比如 Nginx Ingress Controller 通常以高可用形式部署在固定三个节点上面)。

按照官方文档说的,除非绝对必要,否则不要为 Pod 指定 hostPort。 将 Pod 绑定到 hostPort 时,它会限制 Pod 可以调度的位置数,因为每个 <hostIP, hostPort, protocol> 组合必须是唯一的。 如果您没有明确指定 hostIP 和 protocol,Kubernetes 将使用 0.0.0.0 作为默认 hostIP 和 TCP 作为默认 protocol,请在使用 hostPort 之前考虑使用 NodePort 服务。

参考:https://knowledge.zhaoweiguo.com/build/html/cloudnative/k8s/yamls/option_hostport

参考:hostPort 与 hostNetwork 异同

Kubernetes hostPort 使用的更多相关文章

  1. Docker Kubernetes hostPort 代理转发

    Docker Kubernetes  hostPort 代理转发 hostPort: 1. 类似docker -p 映射宿主级端口到容器. 2. 容器所在的主机暴露端口转发到指定容器中. 3. hos ...

  2. Docker 运维高级应用管理

     Docker 基本应用 1.Docker 介绍及安装 2.Docket 使用命令 3.Docker run命令参数整理 4.Docker 构建镜像 Docker Compose 高级应用 1.Doc ...

  3. 基于Kubernetes在AWS上部署Kafka时遇到的一些问题

    作者:Jack47 转载请保留作者和原文出处 欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 交代一下背景:我们的后台系统是一套使用Kafka消息队列的数据处理管线 ...

  4. kubernetes多节点部署解析

    注:以下操作均基于centos7系统. 安装ansible ansilbe可以通过yum或者pip安装,由于kubernetes-ansible用到了密码,故而还需要安装sshpass: pip in ...

  5. [经验交流] Kubernetes Nginx Ingress 安装与使用

    Ingress 介绍 Kubernetes 上部署的微服务运行在它的私有网络中, 通过Pod实例的hostPort或Service实例的NodePort可以暴露到主机端口上,便于用户访问.但这样的方法 ...

  6. Docker实践(6)—CentOS7上部署Kubernetes

    Kubernetes架构 Kubernetes的整体架构如下: Master为主控节点,上面运行apiserver,scheduler,controller-manager等组件.Minion相当于工 ...

  7. CoreOS实践(2)—在coreos上安装Kubernetes

    下载kubernetes sudo mkdir -p /opt/bin sudo wget https://storage.googleapis.com/kubernetes/binaries.tar ...

  8. 基于kubernetes构建Docker集群管理详解-转

    http://blog.liuts.com/post/247/ 一.前言        Kubernetes 是Google开源的容器集群管理系统,基于Docker构建一个容器的调度服务,提供资源调度 ...

  9. kubernetes集群部署

    鉴于Docker如此火爆,Google推出kubernetes管理docker集群,不少人估计会进行尝试.kubernetes得到了很多大公司的支持,kubernetes集群部署工具也集成了gce,c ...

  10. Docker系列(八)Kubernetes介绍

    Kubernetes组件功能图   各组件说明: 节点 节点在Kubernetes由虚拟机或者实体机表示,常称为Minion,即从属主机.当一个节点加入到Kubernetes系统中时,它将会创建一个数 ...

随机推荐

  1. 2022-01-15:中心对称数 III。 中心对称数是指一个数字在旋转了 180 度之后看起来依旧相同的数字(或者上下颠倒地看)。 写一个函数来计算范围在 [low, high] 之间中心对称数的个

    2022-01-15:中心对称数 III. 中心对称数是指一个数字在旋转了 180 度之后看起来依旧相同的数字(或者上下颠倒地看). 写一个函数来计算范围在 [low, high] 之间中心对称数的个 ...

  2. jmeter如何保存变量到结果jtl文件里

    将变量保存到结果jtl文件里,可以方便的在generate报告时,自行取用jtl中的变量进行展示,实现过程如下: 1.打开jmeter/bin目录下的jmeter.properties文件,将变量名加 ...

  3. Create Vite App 支持 OpenTiny 啦🎉

    大家好,我是 Kagol,个人公众号:前端开源星球. 一个月前,日日自新写了一篇介绍 Create Vite App 开源项目的文章: 基于vite 4.x 快速搭建开箱即用,高度可定制化模版脚手架 ...

  4. Python基础 - 第一个python程序

    Python程序是什么? Python源程序就是一个特殊格式的文本文件,可以使用任意文本编辑器软件做python的开发,python的文件扩展名为 .py 执行python程序的三种方式 直接调用解释 ...

  5. Spring 核心概念之一 IoC

    前言 欢迎来到本篇文章!通过上一篇什么是 Spring?为什么学它?的学习,我们知道了 Spring 的基本概念,知道什么是 Spring,以及为什么学习 Spring.今天,这篇就来说说 Sprin ...

  6. 数据科学工具 Jupyter Notebook 教程(一)

    ipython notebook 是一个基于浏览器的 python 数据分析工具,使用起来非常方便,具有极强的交互方式和富文本的展示效果.jupyter 是它的升级版,它的安装也非常方便,一般 Ana ...

  7. DIY制作隔离信号注入变压器

    最近在学习模电知识,接触到了测量运放环路增益,需要使用合适的注入变压器,查找资料发现商用信号注入变压器价格昂贵,不适合个人学习使用.看到LOTO使用普通音频变压器做测试,也跟技术群友做了交流,尝试使用 ...

  8. java中基本数据类型和包装数据类型

    基本数据类型和包装数据类型在 Java 中有着重要的区别和联系,对于 Java 程序员来说,熟悉这两种数据类型的特点和使用方法是非常必要的. 基本数据类型 Java 中的基本数据类型一共有 8 种,分 ...

  9. 如何取消Blazor Server烦人的重新连接?

    如何取消Blazor Server烦人的重新连接? 相信很多Blazor的用户在开发内部系统上基本上都选择速度更快,加载更快的Blazor Server模式. 但是Blazor Server由于是Si ...

  10. IDEA的安装准备

    IDEA的安装 第一步 第二步 第三部 第四步