深入理解k8s网路原理之-POD连接主机
关于Linux
网络的知识
向外发送一个数据包,执行步骤:
1、查找该数据包的目的地的路由信息,如果是直连,则在邻居表中查找该目的地的Mac
地址
2、如果非直连路由,则在邻居表中查找下一跳的Mac
地址
3、如果找不到对应的路由,则报"network is unreachable"
4、如果在邻居表中没有查到相应的MAC
地址信息,则向外发送ARP
请求询问
5、发送出去的数据帧,源MAC
地址为发送网卡的MAC
地址,目标MAC
则是下一跳的MAC
,只要不经过NAT
,那么源目的IP
全程不会变化,而MAC
地址则每一跳都会变化
收到数据帧,执行步骤
1、如果数据帧目标MAC
地址不是收包网卡的MAC
,也不是ARP
广播地址,且网卡未开启混杂模式,则拒绝收包
2、如果数据帧目标MAC
为ff:ff:ff:ff:ff:ff
,则进入ARP
请求处理流程
3、如果数据帧目标MAC
地址是收包网卡的MAC
,且是IP
包则:
1、目标IP
地址在本机,则上送到上一层协议继续处理
2、目标IP
地址不在本机,则看net.ipv4.ip_forward
是否为1,若是1,则查找目标IP
的路由信息,进行转发
3、目标IP
不在本机,且net.ipv4.ip_forward
为0,则丢弃
常见命令
1 | 查看网卡信息 |
为了让多个进程高效互不影响地运行,衍生出容器技术,其中以
Docker
最为流行:
1、资源隔离: 使用linux control group
解决各种进程CPU
和Memory
、io
的资源分配问题
2、网络隔离: 使用linux network group
让各个进程运行在独立的网络命名空间,使各个进程运行在独立的网络命名空间
3、文件系统隔离:使用union fs
,让各个进程运行在独立的根文件系统中
POD
即共享同一个ns
的多个容器
示例
docker
运行一个容器时,都会为当前容器创建一个ns
,多个容器只能相互访问对方的ip
地址
1 | docker run -itd --name=pause busybox |
此时要在 pause
中访问 nginx
,先查找下nginx
容器的ip
地址
1 | docker inspect nginx | grep IPAddress |
然后在pause
容器中用刚查到的ip
地址进行访问
1 | docker exec -it pause curl 172.17.0.8 |
这里可以让 nginx
容器加入pause
容器的ns
,用下面的命令可以模拟:
1 | docker run -itd --name=pause busybox |
此时pause
容器和nginx
容器是在相同的ns
中,相互间访问就可以使用`localhost进行访问了,可以用下面的命令进行验证:
1 | docker exec -it pause culr localhost |
pause
容器和nginx
容器就是共享一个ns
的两个容器,所以pause
和nginx
两个容器加起来就是k8s
的pod
在
k8s
集群的节点中使用docker ps
,总会发现一堆名为pause
的容器,pause
是为多个业务容器提供共享的ns
的。
1、进入docker
创建的pause
容器的ns 先获取
pause容器的
pid`
1 | docker inspect pause | grep Pid |
2、进入指定pid
的`ns
1 | nsenter --net=/proc/3083138/ns/net |
3、此时已经在pause
容器的ns
中了,可以查看该ns
的网卡,路由表,邻居表等信息了
1 | ip addr show |
认识ns
影响网络方面的配置主要有以下几个:
— 网卡:启动时初始化,后期可以添加虚拟设备
- 端口:1到65535,所有进程共享
iptables
规则: 配置进出主机的防火墙策略和NAT
规则- 路由表:到目标地址的路由信息
- 邻居表:与主机在同个二层网络的其他主机的
MAC
地址与IP
地址的映射关系
示例
1、创建新的ns
1 | ip netns add ns1 |
然后可以使用ip netns exec ns1
前缀来执行命令,这样显示的结果就都是ns1
的网络相关的配置了.
1 | ip netns exec ns1 ip link show |
2、主机与pod
相互访问
首先给ns1
正价一张与主机相连的网卡,这里用到linux
虚拟网络设备veth
网卡对,对于veth
,基本可以理解为中间连着线的两张网卡:
1 | 增加一对veth网卡,名为 ns1-eth0 和 veth-ns1 |
3、测试与主机ip
是否能ping
通
1 | ip netns exec ns1 ping xxx.xxx.xxx.xxx |
此时发现不能ping
通主机,这是因为没有到目的地的路由,所以在这里给ns1
增加一条默认路由
1 | ip netns exec ns1 ip route add default via 172.20.1.1. dev ns-eth0 |
通过
1 | ip netsns exec ns1 ip route |
查看路由信息
此时去ping
发现还是不行,这是因为如果是非直连路由,会先去拿下一跳的mac
地址,下一跳是172..20.1.1
,能获取到它的MAC
地址吗?
用如下命令查一下路由表:
1 | ip netns exec ns1 ip neigh |
会发现获取不到,以为网关ip
地址确实是个不存在的地址,网关IP
是不会出现在pod
发送的数据包中的,真正需要用的是网关的mac
地址,我们的目的是要得到主机端veth-ns1
的mac
地址,有两个方法:
·、设置对端的网卡apr
代答,ns1-eth0
的对端是主机上的veth-ns1
网卡
1 | 这样就开启了veth-ns1的arp代答,只要收到arp请求,不管目标IP是什么,veth-ns1网卡都会把自己MAC地址回复回去 |
或者把网关地址设置在对端的网卡上
4、此时拿到网关的mac
地址但是ping
之后发现还是不行。这是因为主机上没有添加到pod
的直连路由
1 | ip route add 172.20.1.10 dev veth-ns1 |
此时只能保证主机与pod
进行互通,此时pod
是没法访问外网的,这个时候需要做原地址转换,所以我们需要在主机上也要配置针对刚才创建的pod
的原地址转换规则。
pod
访问外网
- 首先第一步需要打开本机的
ip
转发功能1
echo 1 > /proc/sys/net/ipv4/ip_forward
- 设置
snat
规则此时发现可以1
iptables -A POSTROUTING -t nat -s 172.20.1.10 -j MASQUERADE
ping
通百度