测试环境创建
在k8s中部署flannel网络插件
https://blog.csdn.net/weixin_64124795/article/details/128894411
参考文章部署k8s集群和flannel网络插件
我的k8s集群物理环境
我的集群中只有两个节点master和node1节点
[root@master sjs]# kubectl get node
NAME STATUS ROLES AGE VERSION
master Ready master 2d v1.18.0
node1 Ready <none> 44m v1.18.0
允许master节点可以调度
kubectl taint nodes master node-role.kubernetes.io/master:NoSchedule-
创建两个pod分别部署到两个节点上
pod.yaml文件
apiVersion: v1 #定义k8s api的版本v1
kind: Pod #kind资源类型为 Pod
metadata: #元数据声明
name: nginx # 名称是nginx
labels: #标签申明
app: web #标签名称是 app:web
spec: #容器详细信息
nodeSelector:
kubernetes.io/hostname: master
containers: # 容器信息
- name: nginx #容器名称
imagePullPolicy: Never
image: app #容器镜像
pod1.yaml文件
apiVersion: v1 #定义k8s api的版本v1
kind: Pod #kind资源类型为 Pod
metadata: #元数据声明
name: nginx1 # 名称是nginx
labels: #标签申明
app: web #标签名称是 app:web
spec: #容器详细信息
nodeSelector:
kubernetes.io/hostname: node1
containers: # 容器信息
- name: nginx #容器名称
imagePullPolicy: Never
image: app #容器镜像
kubectl apply -f pod1.yaml
kubectl apply -f pod.yaml
pod使用的镜像是我自己创建的,在master和node1节点上都执行
-
生成可执行文件 aa
aa.c文件 #include <stdio.h> #include <unistd.h> int main(){ while(1) { sleep(100000); } } 编译执行 gcc aa.c -o aa
-
编写dockerfile文件
FROM ubuntu RUN apt update && apt install -y git curl net-tools iputils-ping COPY aa . CMD ["./aa"]
-
生成镜像
docker build -t app .
查看测试环境
查看创建的两个pod
可以看到两个pod分别运行在master和node1两个节点上,并且pod的ip不在同一个网段,这是因为在flannel网络插件中是每个节点一个网段的,master上的pod同属于一个网段,node1节点同属于一个网段。
在kube-flannel网络命名空间的kube-flannel-cfg的ConfigMap中全局定义了10.244.0.0/16网段,以后加入k8s的每个节点都会分配一个掩码为24的小网段给节点,比如在我的环境中给master节点分配了10.244.0.0/24网段,给node1分配了10.244.1.0/24的网段
[root@master sjs]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 23m 10.244.0.14 master <none> <none>
nginx1 1/1 Running 0 23m 10.244.1.6 node1 <none> <none>
flannel全局网段10.244.0.0/16
master网段10.244.0.0/24
node1网段10.244.1.0/24
pod互通测试
[root@master home]# kubectl exec -it nginx /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
root@nginx:/# ping 10.244.1.6
PING 10.244.1.6 (10.244.1.6) 56(84) bytes of data.
64 bytes from 10.244.1.6: icmp_seq=1 ttl=62 time=1.41 ms
64 bytes from 10.244.1.6: icmp_seq=2 ttl=62 time=1.10 ms
拓扑图
根据拓扑图来分析网络流量的流程
-
假设nginx访问nginx1,流量的过程 ping 10.244.1.6
-
首先查看nginx的pod里面的路由情况,匹配到默认路由,网关是10.244.0.1即是master节点的cni0
root@nginx:/# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 10.244.0.1 0.0.0.0 UG 0 0 0 eth0 10.244.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 10.244.0.0 10.244.0.1 255.255.0.0 UG 0 0 0 eth0
-
因此访问nginx1的时候首先到达cni0,然后将报文送入master节点协议栈的网络层即ip_recv函数中,会经过netfilter点的prerouting(没有更改),经过master节点的路由判定发现ip地址10.244.1.6不是本机的地址,因此走转发流程即netfilter的forward的hook点,前面在进行路由匹配的时候已经知道了网关是10.244.1.0和出口flannel.1网卡,因此会将报文发到flannel网卡,进入后会组装报文的目的mac地址,那么网关10.244.1.0的mac地址是什么哪,下面可以看出,会将e6:1a:63:79:93:46组装入报文作为目的mac地址。
[root@master home]# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.202.2 0.0.0.0 UG 0 0 0 ens33 0.0.0.0 192.168.40.1 0.0.0.0 UG 100 0 0 ens38 0.0.0.0 192.168.100.1 0.0.0.0 UG 101 0 0 ens37 10.244.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0 10.244.1.0 10.244.1.0 255.255.255.0 UG 0 0 0 flannel.1 172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0 192.168.40.0 0.0.0.0 255.255.255.0 U 100 0 0 ens38 192.168.100.0 0.0.0.0 255.255.255.0 U 101 0 0 ens37 192.168.202.0 0.0.0.0 255.255.255.0 U 0 0 0 ens33 [root@master home]# ip neigh show dev flannel.1 10.244.1.0 lladdr e6:1a:63:79:93:46 PERMANENT
-
因为flannel.1是vxlan口,接下来需要进行vxlan封装了,需要知道外层的ip地址是啥,这个是根据fdb表来根据mac地址查询的,查询出的ip地址是192.168.202.131
[root@master home]# bridge fdb show flannel.1|grep e6:1a:63:79:93:46 e6:1a:63:79:93:46 dev flannel.1 dst 192.168.202.131 self permanent
-
由于vxlan是将二层的报文封装到udp里,所有这里内核会将报文传入到传输层,进行port封装,再到网络层,将刚才查到的ip封装,然后进行路由从指定的网卡发出
-
在master的ens33上抓包
tcpdump -i ens33 'udp[39]=1' -nv -w aa.cap
手动构建flannel拓扑
master节点配置
brctl addbr cni0 #创建网桥名字为br0
ifconfig cni0 192.168.10.1/24 up
#创建两个网络命名空间
ip netns add vm1
ip netns add vm2
# 创建两对veth pair
ip link add veth0 type veth peer name veth1
ip link add veth00 type veth peer name veth11
ifconfig veth1 up
ifconfig veth11 up
# 将veth pair的一端放入网络命名空间
ip link set veth0 netns vm1
ip link set veth00 netns vm2
# 设置网络命名空间的网卡ip
ip netns exec vm1 ip addr add 192.168.10.2/24 dev veth0
ip netns exec vm2 ip addr add 192.168.10.3/24 dev veth00
ip netns exec vm1 ip link set veth0 up
ip netns exec vm2 ip link set veth00 up
# 设置网络命名空间的默认路由,192.168.10.1是cni0的网卡
ip netns exec vm1 ip route add default via 192.168.10.1 dev veth0
ip netns exec vm2 ip route add default via 192.168.10.1 dev veth00
# 将veth pair的一端放入到cni0
brctl addif cni0 veth1 #将eth1网口和br0网口创建联系
brctl addif cni0 veth11 #将eth2网口和br0网口创建联系
# 创建vxlan口,并指定出口网卡
ip link add flannel.1 type vxlan id 100 remote 192.168.202.130 dstport 4789 dev ens33
ip link set flannel.1 up #开启vxlan接口
ip addr add 192.168.10.0/24 dev flannel.1 #为网桥配置ip地址
# 添加路由将流量引入到flannel.1网卡
route add -net 192.168.20.0/24 dev flannel.1
route add -net 192.168.20.0/24 gw 192.168.20.0 dev flannel.1
#添加vxlan对端的mac地址
ip neigh add 192.168.20.0 lladdr 9a:0c:28:83:52:e2 dev flannel.1
node节点
brctl addbr cni0 #创建网桥名字为br0
ifconfig cni0 192.168.20.1/24 up
ip netns add vm1
ip netns add vm2
ip link add veth0 type veth peer name veth1
ip link add veth00 type veth peer name veth11
ifconfig veth1 up
ifconfig veth11 up
ip link set veth0 netns vm1
ip link set veth00 netns vm2
ip netns exec vm1 ip addr add 192.168.20.2/24 dev veth0
ip netns exec vm2 ip addr add 192.168.20.3/24 dev veth00
ip netns exec vm1 ip link set veth0 up
ip netns exec vm2 ip link set veth00 up
ip netns exec vm1 ip route add default via 192.168.20.1 dev veth0
ip netns exec vm2 ip route add default via 192.168.20.1 dev veth00
brctl addif cni0 veth1 #将eth1网口和br0网口创建联系
brctl addif cni0 veth11 #将eth2网口和br0网口创建联系
ip link add flannel.1 type vxlan id 100 remote 192.168.202.129 dstport 4789 dev ens33
ip link set flannel.1 up #开启vxlan接口
ip addr add 192.168.20.0/24 dev flannel.1 #为网桥配置ip地址
route add -net 192.168.10.0/24 dev flannel.1
route add -net 192.168.10.0/24 gw 192.168.10.0 dev flannel.1
#添加vxlan对端的mac地址
ip neigh add 192.168.10.0 lladdr a6:e0:77:01:e4:17 dev flannel.1
验证
-
node1的vm1 ping master的vm1
[root@node1 ~]# ip netns exec vm1 ping 192.168.10.2 PING 192.168.10.2 (192.168.10.2) 56(84) bytes of data. 64 bytes from 192.168.10.2: icmp_seq=1 ttl=62 time=0.991 ms 64 bytes from 192.168.10.2: icmp_seq=2 ttl=62 time=2.32 ms 64 bytes from 192.168.10.2: icmp_seq=3 ttl=62 time=4.42 ms
-
node1的vm1 ping node1的flanneld.1
[root@node1 ~]# ip netns exec vm1 ping 192.168.20.1 PING 192.168.20.1 (192.168.20.1) 56(84) bytes of data. 64 bytes from 192.168.20.1: icmp_seq=1 ttl=64 time=0.036 ms 64 bytes from 192.168.20.1: icmp_seq=2 ttl=64 time=0.044 ms 64 bytes from 192.168.20.1: icmp_seq=3 ttl=64 time=0.094 ms
-
node1的vm1 ping node1的vm2
[root@node1 ~]# ip netns exec vm1 ping 192.168.20.3 PING 192.168.20.3 (192.168.20.3) 56(84) bytes of data. 64 bytes from 192.168.20.3: icmp_seq=1 ttl=64 time=0.034 ms 64 bytes from 192.168.20.3: icmp_seq=2 ttl=64 time=0.067 ms 64 bytes from 192.168.20.3: icmp_seq=3 ttl=64 time=0.104 ms
-
node1的vm1 ping master的flannel.1
[root@node1 ~]# ip netns exec vm1 ping 192.168.10.1 PING 192.168.10.1 (192.168.10.1) 56(84) bytes of data. 64 bytes from 192.168.10.1: icmp_seq=1 ttl=63 time=0.821 ms 64 bytes from 192.168.10.1: icmp_seq=2 ttl=63 time=0.992 ms 64 bytes from 192.168.10.1: icmp_seq=3 ttl=63 time=2.15 ms 64 bytes from 192.168.10.1: icmp_seq=4 ttl=63 time=1.33 ms
-
node1的vm1 ping node1的其他网卡
[root@node1 ~]# ip netns exec vm1 ping 192.168.100.200 PING 192.168.100.200 (192.168.100.200) 56(84) bytes of data. 64 bytes from 192.168.100.200: icmp_seq=1 ttl=64 time=0.065 ms 64 bytes from 192.168.100.200: icmp_seq=2 ttl=64 time=0.079 ms 64 bytes from 192.168.100.200: icmp_seq=3 ttl=64 time=0.101 ms
-
node1的vm1 ping外部网络,没ping通,这是因为vm1的ip是一个内部ip
[root@node1 ~]# ip netns exec vm1 ping 192.168.100.1 PING 192.168.100.1 (192.168.100.1) 56(84) bytes of data.
-
在外部网络的192.168.100.1网卡上抓包是能够收到报文的,只是返回的时候找不到路所有访问不通
-
那么怎么解决访问不通的问题,可以想到使用snat可以实现,将源ip地址是192.168.20.0/24的转换为192.168.100.200
-
在node1上执行
iptables -t nat -A POSTROUTING -s 192.168.20.0/24 -j SNAT --to-source 192.168.100.200
-
在master执行
iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -j SNAT --to-source 192.168.100.100
-
再从node1的vm1 ping外部网络
[root@node1 ~]# ip netns exec vm1 ping 192.168.100.1 PING 192.168.100.1 (192.168.100.1) 56(84) bytes of data. 64 bytes from 192.168.100.1: icmp_seq=1 ttl=127 time=0.484 ms 64 bytes from 192.168.100.1: icmp_seq=2 ttl=127 time=0.818 ms 64 bytes from 192.168.100.1: icmp_seq=3 ttl=127 time=0.789 ms 64 bytes from 192.168.100.1: icmp_seq=4 ttl=127 time=0.785 ms
-
抓包查看
https://zhuanlan.zhihu.com/p/550273312?utm_id=0
https://blog.csdn.net/qq_36963950/article/details/130542890?spm=1001.2014.3001.5506