摘要:

network.xml;smcroute;clusterIP: None;Time to Live;mangle --ttl-set;tcpdump;mnt;init;libudisks2-devel;Deployment

 

Tip:

  • 由于没有在/etc/resolv.conf配nameserver 114.114.114.114,导致部署pod失败Init:0/1( Warning  FailedCreatePodSandBox )
sdfp2    Init:0/1     k8s-node07
  • Linux容器的“单进程”模型,指的是容器的生命周期等同于 PID=1 的进程(容器应用进程)的生命周期,而不是说容器里不能创建多进程。当然,一般情况下,容器应用进程并不具备进程管理能力,所以你通过 exec 或者ssh 在容器里创建的其他进程,一旦异常退出(比如 ssh 终止)是很容易变成孤儿进程的。反过来,其实可以在容器里面 run 一个 systemd,用它来管理其他所有的进程。这样会产生第二个问题:实际上没办法直接管理我的应用了,因为我的应用被 systemd 给接管了,那么这个时候应用状态的生命周期就不等于容器生命周期。
  • 管理虚拟机= 管理基础设施;管理容器 = 直接管理应用本身
  • 管理容器 = 管理systemd != 直接管理应用本身 (即容器运行/usr/sbin/init
  • Pod:kubelet 会去调 Container runtime 来真正去启动配置容器和容器的运行环境,去调度 Storage Plugin 来配置存储,network Plugin 配置网络。Pod 这个抽象也给这些容器提供了一个共享的运行环境,它们会共享同一个网络环境,这些容器可以用 localhost 来进行直接的连接。而 Pod 与 Pod 之间,是互相有 isolation 隔离的。
  • Spec 是希望 Pod 达到的一个预期的状态;
  • 在Spec 下面会有一个项目叫 status,它表达了这个资源当前的状态;
  • Pod 的生命周期等同于 Infra container 的生命周期,与容器 A 和 B 是无关的。这也是为什么在 Kubernetes 里面,它是允许去单独更新 Pod 里的某一个镜像的;
  • 在每个 Pod 里,额外起一个 Infra container 小容器来共享整个Pod 的 Network Namespace,一个Pod 里面的所有容器,它们看到的网络视图是完全一样的。即:它们看到的网络设备、IP地址、Mac地址等等。
  • 容器设计模式(如何更新程序版本和配置——所有“设计模式”的本质是:结构和重用):通过组合两个不同角色的容器,并且按照一些像 Init Container 这样一种编排方式,统一的去打包一个应用,把它用 Pod 来去做,在 Kubernetes 里面就是一个非常经典的容器设计模式,叫做:“Sidecar”。
  • 具体应用中,首先定义一个 Init Container(基于 alpine 镜像,只是打包服务/home/cdatc/AirNet/目录的进程和配置),只做一件事情,把/home/cdatc/AirNet/bin(或/home/cdatc/AirNet/config)从镜像里拷贝到一个 Volume (emptyDir)里面,它做完这个操作就退出了,所以 Init Container 会比用户容器先启动,并且严格按照定义顺序来依次执行。然后,关键在于一个Pod 里面的多个容器,共享这个 Volume ,所以现在另一个msdp容器,在启动的时候,要声明使用Volume,并且挂载在/home/cdatc/AirNet/ 目录下面。这个时候,由于前面已经运行过了一个 Init Container,已经执行完拷贝操作了,所以这个 Volume 里面已经存在了应用的/bin应用程序包:第二步执行启动这个msdp容器的时候,去挂这个 Volume,一定能在里面找到前面拷贝来的 自己定义版本的应用程序/bin或配置文件/config。下面的截图是 flannel 组件的 InitContainer 的一个配置,它的 InitContainer 主要是为 kube-flannel 这个普通容器启动之前准备一些网络配置文件。参考实现Network,xml文件中IP地址(指定为Pod的动态IP)的更新?!

AirNet使用笔记10(pod组播)_xml

  • (mid的功能参考该用法)Sidecar的用法,作为代理容器 Proxy。 假如现在有个 Pod 需要访问一个外部系统,或者一些外部服务,但是这些外部系统是一个集群,那么这个时候如何通过一个统一的、简单的方式,用一个 IP 地址,就把这些集群都访问到?有一种方法就是:修改代码。因为代码里记录了这些集群的地址;另外还有一种解耦的方法,即通过 Sidecar 代理容器。简单说,单独写一个这么小的 Proxy,用来处理对接外部的服务集群,它对外暴露出来只有一个 IP 地址就可以了。所以接下来,业务容器主要访问 Proxy,然后由 Proxy 去连接这些服务集群,这里的关键在于 Pod 里面多个容器是通过 localhost 直接通信的,因为它们同属于一个 network Namespace,网络视图都一样,所以它们俩通信 localhost,并没有性能损耗。

1、修改MSDP2的主机名,IP改为不同网段,加路由测试

SMC:
 /home/cdatc/AirNet/config/network.xml
<node hostname="msdp2"  showname="msdp2" position="ACC" logic_position="ACC" stationno="4" bakenode="3"   grouptype="SERVER" ip_a="192.168.50.153" 
msdp2:
<node hostname="msdp2"  showname="MSDP2" position="ACC" logic_position="ACC" stationno="4" bakenode="3"   grouptype="SERVER" ip_a="192.168.50.153" 
msdp2 -->  eth0:  192.168.50.153/24 
 [root@msdp2 ~]# ip route
192.168.5.0/24 dev eth0 scope link 
[root@SMC1 ~]# ip route
192.168.50.0/24 dev eth0 scope link 
[root@MSDP1 log]# ip route               //# ip route add 192.168.50.0/24 dev eth0,否则MSDP1/2都是主态
192.168.50.0/24 dev eth0 scope link
  • SMC/MSDP1/msdp2加路由测试,MSDP1一直主态,切不成备态,但是MSDP1  kill掉某个进程可以切换为备态,原因是时钟同步error导致(即 192.168.50.153网段没有配时钟同步)。
  • MSDP1必须加路由,否则MSDP1/msdp2都是主态。
  • SMC和msdp2的network.xml配置,SMC监控(40001/40002组播端口)使用hostname="msdp2"主机名,但是不区分大小写,但是在SMC上Restart/Stop/Restart All/Stop All进程,报错”operate failed!“ ,SMC先通过225.1.0.1:40001(40002)组播获取进程、网络状态,通过后,再使用smc和mnt进程间的tcp链接发控制信息,可能是smc对hostname大小写敏感

2、测试,POD运行msdp2(pod里只能是小写),smcroute设置静态组播路由,ip route添加tcp路由。

  • pod里的network.xml配置:小写hostname="msdp2";Pod的IP地址,对应MSDP1和SMC也需要修改。
  • 测试过程中注意:pod重启过程中,对应calixxx网卡也会删除,smcrouted关于该calixxx网卡静态路由也会被自动删掉,需要核对smcroute.conf配置,重启进程smcrouted。

3、测试,POD运行前端服务sdfp2(smcroute.conf需额外配监视源的组播),遗留问题:有ADS-B信号没有雷达信号。

sdfp2  172.27.29.132  k8s-node07   cat /sys/class/net/eth0/iflink  175    calid3eb6b9ab72
smcroute.conf example
#--->sdfp2的组播
mgroup from enp4s0f0 group 225.1.0.1
mroute from enp4s0f0 group 225.1.0.1 to calid3eb6b9ab72 
mroute from calid3eb6b9ab72  group 225.1.0.1 to enp4s0f0 
mgroup from enp4s0f0 group 225.1.0.2
mroute from enp4s0f0 group 225.1.0.2 to calid3eb6b9ab72 
mroute from calid3eb6b9ab72  group 225.1.0.2 to enp4s0f0 
#--->sdfp2的MPDC/ADS-B组播
mgroup from enp4s0f0 group 233.1.21.1
mroute from enp4s0f0 group 233.1.21.1 to calid3eb6b9ab72 
mroute from calid3eb6b9ab72  group 233.1.21.1 to enp4s0f0  
#--->k8s宿主机节点、SDFP1、SMC加路由
 ip route add 192.168.5.0/24 dev enp4s0f0                //运行sdfp2 POD的宿主机上
 route add -net 172.27.29.128/26 gw  192.168.31.220      //SDFP1  SMC
#--->pod运行后,手动更新进程rfp、afp、mid等,更新mnt进程提示缺库文件,说明改动较大
[root@k8s-master01 ~]# k -n vm-airnet cp /root/AirNet/bin/rfp sdfp2:/home/cdatc/AirNet/bin/ -c sdfp2
#--->pod启动后,手动运行服务进程
  /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf   1>/dev/null 2>&1
  /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis_6378.conf   1>/dev/null 2>&1
  /home/cdatc/AirNet/bin/mnt  > /dev/null 2>&1 &
  • 更新mnt进程提示缺库文件,说明改动较大,需重新制作镜像。
  • smcroute.conf不能加:phyint enp4s0f0 enable ttl-threshold 250,否则组播路由失效。

4、迁移到pod后,使用在k8s集群内定义的External Services访问集群外部服务器测试。OK!

  • network.xml中IP改为域名,例如msdp1.airnet 192.168.5.52,配置到(k8s的service和)宿主机的hostname进行测试OK!
--->将SMC和MSDP1的network.xml中IP地址改成域名msdp1.airnet,并修改/etc/hosts :192.168.5.52    msdp1.airnet
<node hostname="MSDP1"  showname="MSDP1"   ip_a="msdp1.airnet"
  • 测试IP指定为k8s的service,使用DNS服务解析域名(smc 192.168.5.31),创建外部无头service(clusterIP: None),必须是无头service,否则不通。
apiVersion: v1
kind: Service
metadata:
  name: smc
  namespace: vm-airnet
spec:
  type: ClusterIP
  clusterIP: None  
  ports:
  - name: smc1
    port: 49001
    protocol: TCP
  - name: smc2
    port: 49002
    protocol: TCP    
---
apiVersion: v1
kind: Endpoints
metadata:
  name: smc
  namespace: vm-airnet
subsets:
- addresses:
  - ip: 192.168.5.31
  ports:
  - name: smc1
    port: 49001
    protocol: TCP
  - name: smc2
    port: 49002
    protocol: TCP
  • 问题:k8s集群中的service:smc,域名解析没问题,但是集群出来没有到192.168.5.0/24网段的路由。endpoints改成192.168.31.158测试OK。k8s中在哪实现到192.168.5.0/24网段的路由?这里使用sleep-7dbc8959b8-8pndc测试,它位于master02,在该节点加路由 ip route add 192.168.5.0/24 dev enp4s0f0测试OK,所以需要在所有宿主机节点加该网段的路由。以下使用sleep POD测试涉及到master02,加路由后测试OK。
[root@k8s-master01 ]#  k -n vm-airnet exec -ti sleep-7dbc8959b8-8pndc -- ping smc
PING smc (192.168.5.31): 56 data bytes
sleep-7dbc8959b8-8pndc     172.25.92.90     k8s-master02
[root@k8s-master02 ~]# ip route add 192.168.5.0/24 dev enp4s0f0
[root@k8s-master02 ~]# k -n vm-airnet exec -ti sleep-7dbc8959b8-8pndc -- ping smc
64 bytes from 192.168.5.31: seq=0 ttl=63 time=0.416 ms
  • 继续测试,sdfp2这个Pod使用service:smc.vm-airnet访问集群外部SMC(192.168.5.31)。如下修改Pod sdfp2的network.xml,测试OK(当然,前提是POD sdfp2的宿主机加了路由ip route add 192.168.5.0/24 dev enp4s0f0)。
<node hostname="SMC1"  ...... ip_a="smc.vm-airnet" ip_b="smc.vm-airnet" ip_c="smc.vm-airnet"

5、将POD:sdfp2、msdp2部署在vm-airnet命名空间,启用istio,测试OK。证明sitio-sidecar对组播是完全透明的

6、SMCRoute 是一个 UNIX/Linux 工具,用于管理和监视组播路由。 它支持 IPv4 和 IPv6 组播路由。SMCRoute 可用作动态组播路由器的替代方案,就像静态组播路由中的 mrouted 或 pimd 一样,应保持 和/或 不存在适当的 IGMP 或 MLD 信令。

  • 只要多播路由,UNIX 内核中就存在组播路由守护程序运行。在 Linux 上,多个组播路由器可以简单运行 使用不同的组播路由表。
  • 支持无源按需路由,又称基于 (*,G) 的静态路由
  • 在华为路由器上使用命令ping,能正常Ping通组播源地址。PING 225.1.2.3时记得设置 TTL >1!TTL 通常会让尝试组播路由的人感到厌烦。 TCP/IP 堆栈默认为组播帧的 TTL 为 1。此限制减少了意外淹没组播的风险。请记住,组播行为除非受到限制,否则就像广播一样。
$ ping -I eth0 -t 2 225.1.2.3    //只能在路由器上ping,linux上测试不行

——经测试,二所系统ADS-B组播的TTL(Time to Live)是4,MPDC的TTL(Time to Live)是1,mid的TTL(Time to Live)是32

  • SMCRoute 还有一个客户端接口,用于与守护程序进行交互:smcroutectl
  • 组播的分类模型
  • ASM(Any-Source Multicast)
  • SFM(Source-Filtered Multicast)
  • SSM(Source-Specific Multicast)

组播IP地址分类

  • 永久组地址,IANA为路由协议预留的组播地址,用于标识一组特定的网络设备(也称为保留组播组)。比如224.0.0.5 OSPF路由器,永久组地址保持不变,组成员的数量可以是任意的,甚至可以为零。
  • 临时组地址,为用户组播组临时分配的IP地址,组成员的数量一旦为零,即取消。

D 类地址范围 含义

  • 224.0.0.0~224.0.0.255 为路由协议预留的永久组地址。
  • 224.0.1.0~ 231.255.255.255\233.0.0.0~238.255.255.255用户可用的ASM临时组地址,全网范围内有效。
  • 232.0.0.0~232.255.255.255 用户可用的SSM临时组地址,全网范围内有效。
  • 239.0.0.0~239.255.255.255 用户可用的ASM临时组地址,仅在特定的本地管理域内有效,称为本地管理组播
  • 组播静态路由设置通过配置组播静态路由,可以为来自特定组播源的组播报文指定RPF接口或RPF邻居,主要应用于两个场景:
  • 改变RPF路由:如果设备希望特定组播源发来的数据报文从指定接口接收,但是RPF检查时发现该接口不是RPF接口,此时可配置组播静态路由,指定该接口为RPF接口。当设备接收到特定源发来的组播数据报文后,会以该路由为RPF路由来执行RPF检查,不是通过指定接口发来的报文在RPF检查时将不通过。
  • 衔接RPF路由:在单播路由被阻断的网段,比如相邻两台设备配置不同的路由协议,并且路由没有相互引入,设备上会由于没有RPF路由而无法进行报文转发。此时通过配置组播静态路由,指定RPF接口来完成RPF检查,便可实现组播报文的转发。

7、测试问题及通过mangle修改ttl解决问题的测试记录(MPDC的TTL为1),sdfp2迁移到pod后,由于rfp要从MPDC的组播获取雷达数据; afp要从ADS-B的组播源获取ADS-B数据。

  • afp获取ADS-B数据测试OK
  • rfp获取不到来自MPDC的组播雷达数据:原因是MPDC的TTL(Time to Live)是1导致的。测试现象是在运行POD:sdfp2的宿主机k8s-node07上(作为组播路由器,已运行smcrouted),在入网卡 enp4s0f0能抓到来自MPDC的组播包,下一跳的califf378127ba5网卡抓不到来自MPDC的组播包,就是由于组播源头的MPDC的TTL(Time to Live)为1导致的。(另验证,在enp4s0f0和califf378127ba5都能抓到来自ADS-B【196.168.2.224】的组播包56060)
[root@k8s-node07 home]# tcpdump  -nn  -i enp4s0f0  host 233.1.21.1 and port 56018  
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp4s0f0, link-type EN10MB (Ethernet), capture size 262144 bytes
10:20:01.526936 IP 192.168.11.20.54662 > 233.1.21.1.56018: UDP, length 13
[root@k8s-node07 home]#   tcpdump  -nn  -i  califf378127ba5 host 233.1.21.1 and port 56018
  • 路由器收到组播数据报文后,只有确认这个数据报文是从自身连接到组播源的接口上收到的,才进行转发,否则丢弃。与单播路由的方向相反,单播路由关心的目的地址ip,而组播是关心源ip,组播关心流量从哪里来!组播的路由相当于单播路由的反向路径,简称RPF(Reverse Path Forwarding逆向路径转发技术)这个RPF是针对于单播来说的。
  •  RPF检查:在单播路由表中查找到组播报文源地址的路由,如果该路由的出接口就是组播报文的入接口,RPF检查成功;否则RPF检查失败,报文丢弃。
  • k8s-node07节点修改mpdc组播数据的ttl值,解决组播数据能到node07的enp4网卡到不了sdfp2的calico网卡的问题(修改mangle规则):在k8s-node07修改mangle,在enp4s0f0上抓包未修改(说明tcpdump抓包位置在PREROUTING之前),在califf378127ba5抓包已生效。
iptables -t mangle -A PREROUTING -s 192.168.10.20/32 -j TTL --ttl-set 3
  iptables -t mangle -A PREROUTING -s 192.168.11.20/32 -j TTL --ttl-set 3
[root@k8s-node07 home]# iptables -n -v -L --line -t mangle  
Chain PREROUTING (policy ACCEPT 8385K packets, 3438M bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1      11M 6030M cali-PREROUTING  all  --  *    *   0.0.0.0/0            0.0.0.0/0            /* cali:6gwbT8clXdHdC1b1 */
2     150K   12M TTL        all  --  *      *       192.168.10.20        0.0.0.0/0            TTL set to 3
3     349K   30M TTL        all  --  *      *       192.168.11.20        0.0.0.0/0            TTL set to 3  
service iptables save
  --提示命令只支持lsb动作
yum install -y iptables-services
  --安装iptables-services
再次service iptables save
  --提示规则保存至/etc/sysconfig/iptables
--->测试,在k8s-node07修改mangle,在enp4s0f0上抓包未修改,在califf378127ba5抓包已生效。
[root@k8s-node07 home]# tcpdump -i enp4s0f0 -vv port 56007
tcpdump: listening on enp4s0f0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:58:06.382854 IP (tos 0x0, ttl 1, id 0, offset 0, flags [DF], proto UDP (17), length 44)
    192.168.10.20.42099 > 233.1.21.1.56007: [udp sum ok] UDP, length 16
14:58:06.399005 IP (tos 0x0, ttl 1, id 0, offset 0, flags [DF], proto UDP (17), length 97)
[root@k8s-node07 home]# tcpdump -i califf378127ba5  -vv port 56007
tcpdump: listening on califf378127ba5, link-type EN10MB (Ethernet), capture size 262144 bytes
14:58:48.523626 IP (tos 0x0, ttl 2, id 0, offset 0, flags [DF], proto UDP (17), length 66)
    192.168.10.20.42099 > 233.1.21.1.56007: [udp sum ok] UDP, length 38
14:58:48.539012 IP (tos 0x0, ttl 2, id 0, offset 0, flags [DF], proto UDP (17), length 44)

8、更新mnt程序,重新制作镜像。

  • 新版本mnt:v2.1.1,增加了udisk2的调用,监控硬盘状态,所以镜像需安装libudisks2-devel;运行mnt时日志提示sudo,所以安装sudo包。容器需要通过init作为服务运行udisk2。
FROM centos:centos7.9.2009
MAINTAINER  "mi_zy"
LABEL version="1.2" description="libudisks2-devel sudo,new-mnt" by="mi_zy"
USER root
RUN yum install libudisks2-devel sudo -y 
COPY lib64/*  /usr/lib64/
COPY ldconf/*  /etc/ld.so.conf.d/
# 临时使用旧版本mnt程序
#COPY mnt  /home/cdatc/AirNet/bin/
ADD  AirNet.tar.gz /usr/
ADD  AirNet-cdatc.tar.gz   /home/cdatc/
ADD  redis.tar.gz /usr/local
RUN  ldconfig
WORKDIR  /home/cdatc/AirNet/bin/
ENV HOSTNAME=msdp2
CMD ["/usr/bin/sleep  infinity"]
  • docker要运行systemd-udevd服务需加参数--privileged=true,且执行命令只能是唯一的/usr/sbin/init
docker run -itd  --privileged=true --hostname  msdp2 --name msdp2 msdp2:v1.2 /usr/sbin/init
  • 在k8s的pod运行,注意args: ["/usr/sbin/init"] 只能使用唯一这个命令(多个命令时,init就失效了,导致systemd异常,没有运行libudisks2-devel服务);且privileged: true  
---
apiVersion: v1
kind: Pod
metadata:
    name: msdp2
    namespace: vm-airnet
    annotations:
       cni.projectcalico.org/ipAddrs: "[\"172.29.115.154\"]"       
spec:
    nodeSelector:
       kubernetes.io/hostname: k8s-node04
    restartPolicy: OnFailure 
    containers:
        - image: msdp2:v1.2   
          name: msdp2
          imagePullPolicy: IfNotPresent
          securityContext:
            runAsUser: 0     
            privileged: true           
          workingDir: /home/cdatc/AirNet/bin/                       
          command: ["/bin/sh","-c","--"]   
          args: ["/usr/sbin/init"]  
---          
***:top命令显示运行了systemd,和systemd-udevd 、dbus-daemon 
    1 root      20   0   43176   4276   3292 S   0.0  0.0   0:00.22 systemd   
   20 root      20   0   39072   5940   5636 S   0.0  0.0   0:00.18 systemd-journal    
   33 root      20   0   35152   2696   2084 S   0.0  0.0   0:00.11 systemd-udevd       
   76 root      20   0   26396   1964   1672 S   0.0  0.0   0:00.04 systemd-logind     
   77 dbus      20   0   58100   3064   2560 S   0.0  0.0   0:00.08 dbus-daemon          
   79 root      20   0    9936   1304   1172 S   0.0  0.0   0:00.01 agetty
  • 容器中init未运行,执行systemctl会有如下提示
init未运行时   ./mnt报错: 
(process:129): libudisks2-CRITICAL **: 13:28:23.150: udisks_client_get_object_manager: assertion 'UDISKS_IS_CLIENT (client)' failed
[root@msdp2 bin]# sudo systemctl
Failed to get D-Bus connection: Operation not permitted
  • Tip信息:yum install smartmontools:用于执行 SMART 任务,如打印 SMART 自检和错误日志,启用和禁用 SMART 自动测试,设备自检。Smartctl 在物理 Linux服务器上很有用,可以检查智能磁盘的错误和坏扇区,并提取有关硬件 RAID 后面使用的磁盘的信息。

9、测试pod改为depoyment的问题:虽然yaml里是name: msdp2,但是pod的主机名是msdp2-7545fffb69-k9n5k,导致mnt启动报错找不到主机名。

ERROR]  can not find this hostname from network.xml