近期工作中出现了一个问题:某个旧服务中用到了redis
,但是在前期项目容器化改造部署阶段研发同事并没有说明需要用到redis
,直至部署生产prod
环境出现问题。
那么疑问来了,为什么在qa
环境没有问题呢?经沟通排查发现,源码中也就是qa
环境连接的是一个古老的虚拟机运行的redis
,所以自然研发测试环境都没问题,至于为什么会连接到这个地址,不得而知!
第一想法:关掉这个redis
服务,让研发“被迫”主动告知;规范要求,在k8s
集群内部部署该项目的redis服务集群,保证环境一致性,减少不必要麻烦。
项目多数属于微服务应用模块,研发本地无法完整运行全部依赖,希望在本地运行某个服务后,能够注册到qa
容器环境的依赖服务中进行调试。
例如在k8s
中运行的redis
、rabbitmq
等服务,研发在当前环境下无法直接通过客户端工具连接进行访问,给研发测试进行联调带来了很大麻烦,且k8s
内部通过cni
插件创建pod
和service
的内部网络,这类服务无法通过ingress
进行7层暴露,如果通过NodePort
模式暴露给研发,不仅使用有限而且会导致端口管理困难从而工作量加大。因此打通开发和测试环境k8s
集群内网和办公局域网络是有很大必要性的。
相关网络拓扑如下
ip
地址情况如下
DMZ
区域服务器子网:172.16.1.0/24、172.16.2.0/24k8s pod
子网:172.20.0.0/16k8s service
子网:10.68.0.0/16其他涉及到的相关服务及ip
说明
k8s
网络插件:flannel
,对应网络模式为host-gw
k8s kube-dns service ip
:10.68.0.2
dns
服务:ms(windows) server dns
dns ip
:172.16.2.3
FortiGate ip
:172.16.2.254
k8s
集群部署在测试机房,整个局域网链路、外网、防火墙由飞塔防火墙FortiGate
设备统一控制,除k8s
集群内部网络外,其他网络均已通过FortiGate
打通,所以目前面临的问题就是网络打通和dns
解析打通。
k8s
的Pod
和Service
的子网IP
包全转给其中某个k8s node
节点,这样访问pod ip
和service ip
这样的IP
,网络包会到达某个集群物理节点,而集群内的物理节点或虚拟机,k8s
网络cni
插件都会与这些目的地址互通。
dns
解析打通
网络打通后,就可以在办公网络通过pod
或service
的ip
进行连通了。但是每次更新服务,ip
通常都会发生变化,我们想通过服务名称(域名)而不是ip
进行通信,解决dns
问题主要有以下两个方向
k8s
的coredns
作为本地的dns
服务器k8s
中的服务(域名)的记录从内网dns
服务器转发到k8s
的coredns
上述两种方式都可以实现dns
的互联互通。综合考虑,为了保证两处dns
服务的稳定性,只将经过k8s
内部服务的dns
请求通过coredns
,且减少了PC
客户端dns
服务器地址的配置工作,选择方案二。
在本地pc
电脑上操作
➜ ~ ping 172.16.1.106 -c 4
PING 172.16.1.106 (172.16.1.106): 56 data bytes
64 bytes from 172.16.1.106: icmp_seq=0 ttl=63 time=1.621 ms
64 bytes from 172.16.1.106: icmp_seq=1 ttl=63 time=1.568 ms
64 bytes from 172.16.1.106: icmp_seq=2 ttl=63 time=1.221 ms
64 bytes from 172.16.1.106: icmp_seq=3 ttl=63 time=1.338 ms
--- 172.16.1.106 ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 1.221/1.437/1.621/0.164 ms
在k8s
任意一台node
上操作,通过nslookup
同时检查网络和dns
功能是否正常,这里以172.16.1.106
这台node
为例
[root@k8s-qa-node-02 ~]# nslookup -q=A kubernetes.default.svc.cluster.local 10.68.0.2
Server: 10.68.0.2
Address: 10.68.0.2#53
Name: kubernetes.default.svc.cluster.local
Address: 10.68.0.1
查看node
的路由
[root@k8s-qa-node-02 ~]# ip route
default via 172.16.1.254 dev eth0
169.254.0.0/16 dev eth0 scope link metric 1002
172.16.1.0/24 dev eth0 proto kernel scope link src 172.16.1.106
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.20.0.0/24 via 172.16.1.100 dev eth0
172.20.1.0/24 via 172.16.1.101 dev eth0
172.20.2.0/24 via 172.16.1.110 dev eth0
172.20.3.0/24 dev cni0 proto kernel scope link src 172.20.3.1
172.20.4.0/24 via 172.16.1.107 dev eth0
172.20.5.0/24 via 172.16.1.108 dev eth0
172.20.6.0/24 via 172.16.1.109 dev eth0
# ...省略部分条目
网络打通主要在网关和路由器设备上进行操作,这里仅以FortiGate
为例进行记录。
为了配置流程清晰,通过终端命令行进行配置而不是web
界面操作,首先通过console
或者ssh
连接上FortiGate
的终端
添加k8s pod
和k8s service
两个子网的地址
FortiGate # config firewall address
FortiGate (address) # edit k8s_SERVICE_CIDR
new entry 'k8s_SERVICE_CIDR' added
FortiGate (clientnet) # set subnet 10.68.0.0 255.255.0.0
FortiGate (clientnet) # next
FortiGate (address) # edit k8s_POD_CIDR
new entry 'k8s_POD_CIDR' added
FortiGate (clientnet) # set subnet 172.20.0.0 255.255.0.0
FortiGate (clientnet) # next
FortiGate (address) # end
FortiGate #
配置到达k8s svc
子网的路由
FortiGate # config router static
# 新增一条静态路由,id尽量大,不与已有的冲突
FortiGate (static) # edit 10
new entry '10' added
# 配置目标地址和掩码
FortiGate (2) # set dst 10.68.0.0 255.255.0.0
# 配置网关(下一跳)
FortiGate (2) # set gateway 172.16.1.106
# 配置接口名
FortiGate (2) # set device Test
FortiGate (2) # next
FortiGate (static) # end
FortiGate #
同理,配置到达k8s pod
子网的路由
FortiGate # config router static
FortiGate (static) # edit 11
FortiGate (2) # set dst 172.20.0.0/16 255.255.0.0
FortiGate (2) # set gateway 172.16.1.106
FortiGate (2) # set device Test
FortiGate (2) # next
FortiGate (static) # end
FortiGate #
检查配置的静态路由
FortiGate # get router info routing-table static
# ...省略部分条目
S 10.68.0.0/16 [10/0] via 172.16.1.106, Test
S 172.20.0.0/16 [10/0] via 172.16.1.106, Test
配置到达k8s service
网络放行策略
FortiGate # config firewall policy
# 新增一条网络策略,id尽量大,不与已有的冲突
FortiGate (policy) # edit 100
# 配置源接口
FortiGate (100) # set srcintf internal
# 配置目的接口
FortiGate (100) # set dstintf Test
# 配置源地址
FortiGate (100) # set srcaddr 172.16.0.0/24
# 配置目的地址
FortiGate (100) # set dstaddr k8s_SERVICE_CIDR
# 配置动作类型
FortiGate (100) # set action accept
# 配置动作时间
FortiGate (100) # set schedule always
# 配置服务(协议类型)
FortiGate (100) # set service ALL_TCP
# 配置是否开启日志
FortiGate (100) # set logtraffic disable
# 配置是否开启nat
FortiGate (100) # set nat disable
end
同理,配置到达k8s pod
网络放行策略
FortiGate # config firewall policy
FortiGate (policy) # edit 101
FortiGate (100) # set srcintf internal
FortiGate (100) # set dstintf Test
FortiGate (100) # set srcaddr 172.16.0.0/24
FortiGate (100) # set dstaddr k8s_POD_CIDR
FortiGate (100) # set action accept
FortiGate (100) # set schedule always
FortiGate (100) # set service ALL_TCP
FortiGate (100) # set logtraffic disable
FortiGate (100) # set nat disable
end
登录到FortiGate
界面,查看配置的静态路由
网络策略
在pc
端检查pod
网络是否可达并在上文中选取的网关node
上抓包
上面已经将网络进行了打通,dns
解析的打通在内网dns服务器上设置dns
转发即可。
打开ms(windows) server
类型的dns
管理器配置界面,新增条件转发器,如下所示,dns
域填写k8s
集群中兼容所有命名空间的搜索域。当然,为了安全,建议单独设置允许可达的命名空间下的服务,例如default
,则填为default.svc.cluster.local
。
在本地终端上测试解析k8s service
域名,成功解析
➜ ~ nslookup redis-abc-gns.default.svc.cluster.local
Server: 172.16.2.3
Address: 172.16.2.3#53
Non-authoritative answer:
Name: redis-dkj-gns.default.svc.cluster.local
Address: 172.20.4.222
至此,就成功的将办公网络和k8s
内网进行打通,研发以后就可以在开发机器上利用和qa
环境一样配置的svc name
连接对应依赖的redis
等组件了。
此方案主要利用局域网静态路由,在网关进行配置。透明且高效,且开发测试环境无须再部署其他组件。