openvpn 和 keepalived 能一起用 ?

最近在尝试 openvpn 和 keepalived 能一起用,尝试了一下,发现 openvpn 启动的时候即使监听在全 0.0.0.0, 但是回包的时候依然会用默认路由的网卡的主 ip 回包,即使我是基于 vip 访问的。 所以这个现象我感觉还是 特别的离谱。 虽然 openvpn 可以指定 监听 vip,但是 keepalived 维护的 vip 如果不在当前节点,服务都起不来。

小结: 总感觉这个现象应该是个 bug。这个bug 导致,openvpn 即使要用 vip, 也只能等 keepalived 漂移过来的时候才能用。

也就是说:在部分等待时间和服务启动的时间,都是在冷备。

以下是实际测试步骤,基于 kube-ovn pod 测试的。 vip 绑定到 fip。

ssl vpn gw 测试

之前是用 pod fip 直接测的, 现在用的是 vip fip, (用fip 直接复测下?) 确实如此, vip 的 fip 根本就无法建立连接

bash 复制代码
➜  ~ nc -uvz 192.168.7.4 1194
Connection to 192.168.7.4 port 1194 [udp/openvpn] succeeded!  可以连上
➜  ~
➜  ~ nc -uvz 192.168.7.3 1194
Connection to 192.168.7.3 port 1194 [udp/openvpn] succeeded! fip-vip 连不上

➜  ~ nc -uvz 192.168.7.5 1194
Connection to 192.168.7.5 port 1194 [udp/openvpn] succeeded!




2023-12-06 12:08:09 192.168.7.100:60141 peer info: IV_GUI_VER="net.tunnelblick.tunnelblick_5860_4.0.0beta06__build_5860)"
2023-12-06 12:08:09 192.168.7.100:60141 WARNING: 'link-mtu' is used inconsistently, local='link-mtu 1300', remote='link-mtu 1541'
2023-12-06 12:08:09 192.168.7.100:60141 WARNING: 'tun-mtu' is used inconsistently, local='tun-mtu 1179', remote='tun-mtu 1500'
2023-12-06 12:08:09 192.168.7.100:60141 WARNING: 'auth' is used inconsistently, local='auth [null-digest]', remote='auth SHA1'
2023-12-06 12:08:09 192.168.7.100:60141 WARNING: 'keysize' is used inconsistently, local='keysize 256', remote='keysize 128'

处理掉这些告警
--tun-mtu or --link-mtu may be defined (note that --ifconfig implies --link-mtu 1500) 两者只能存其一

可能是掩码的问题,因为配置中写了掩码, (实际上根本不是, keepalived 最佳实践掩码就是 /32)

bash 复制代码
root@keepalived01-0:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1279 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none
    inet 10.240.0.1 peer 10.240.0.2/32 scope global tun0
       valid_lft forever preferred_lft forever
293: eth0@if294: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue state UP group default
    link/ether 00:00:00:c5:58:24 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.1.0.35/24 brd 10.1.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 10.1.0.2/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::200:ff:fec5:5824/64 scope link
       valid_lft forever preferred_lft forever

这种 keepalived (跑了 vpn gw)维护的 ip ping不通

  1. 手动配在其他 pod 里面试试
bash 复制代码
root@empty:~# k exec -it -n ns1            vpc1-nginx -c netshoot -- bash
vpc1-nginx:~#
vpc1-nginx:~#
vpc1-nginx:~#
vpc1-nginx:~#
vpc1-nginx:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
202: eth0@if203: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue state UP group default
    link/ether 00:00:00:69:a8:1a brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.1.0.6/24 brd 10.1.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::200:ff:fe69:a81a/64 scope link
       valid_lft forever preferred_lft forever
vpc1-nginx:~# ip addr add 10.1.0.2/32 dev eth0
vpc1-nginx:~#
vpc1-nginx:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
202: eth0@if203: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue state UP group default
    link/ether 00:00:00:69:a8:1a brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.1.0.6/24 brd 10.1.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 10.1.0.2/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::200:ff:fe69:a81a/64 scope link
       valid_lft forever preferred_lft forever

root@empty:~/kubecombo/docs/docs/guide/ssl-vpn/03-ssl-vpn-gw# ping 192.168.7.3
PING 192.168.7.3 (192.168.7.3) 56(84) bytes of data.

vpc1-nginx:~#  tcpdump -i eth0 icmp -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes



^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel
vpc1-nginx:~#  tcpdump -i eth0 arp -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes

实际测试 32 位掩码 确实不通

换个 vip 试试

ruby 复制代码
root@empty:~/kubecombo/docs/docs/guide/ssl-vpn/03-ssl-vpn-gw# k get ofip
NAME             VPC    V4EIP           V4IP        READY   IPTYPE   IPNAME
keepalived-fip   vpc1   192.168.7.3     10.1.0.2    true    vip      keepalived-vip
keepalived01-0   vpc1   192.168.7.4     10.1.0.35   true             keepalived01-0.ns1
keepalived01-1   vpc1   192.168.7.5     10.1.0.36   true             keepalived01-1.ns1
nginx            vpc1   192.168.7.110   10.1.0.6    true             vpc1-nginx.ns1
test-vip         vpc1   192.168.7.9     10.1.0.29   true    vip      test-vip
root@empty:~/kubecombo/docs/docs/guide/ssl-vpn/03-ssl-vpn-gw# k get vip
NAME             V4IP        V6IP   MAC                 PMAC   SUBNET         READY   TYPE
keepalived-vip   10.1.0.2           00:00:00:9C:54:D7          vpc1-subnet1   true
test-vip         10.1.0.29          00:00:00:05:90:F7          vpc1-subnet1   true


root@empty:~/kubecombo/docs/docs/guide/ssl-vpn/03-ssl-vpn-gw# ping 192.168.7.9
PING 192.168.7.9 (192.168.7.9) 56(84) bytes of data.
64 bytes from 192.168.7.9: icmp_seq=1 ttl=63 time=2.43 ms
64 bytes from 192.168.7.9: icmp_seq=2 ttl=63 time=0.823 ms
^C
--- 192.168.7.9 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.823/1.627/2.431/0.804 ms
root@empty:~/kubecombo/docs/docs/guide/ssl-vpn/03-ssl-vpn-gw#


vpc1-nginx:~# ip addr add 10.1.0.29/32 dev eth0
vpc1-nginx:~#
vpc1-nginx:~#
vpc1-nginx:~#  tcpdump -i eth0 icmp -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
08:43:46.665606 IP 192.168.7.200 > 10.1.0.29: ICMP echo request, id 56035, seq 1, length 64
08:43:46.665653 IP 10.1.0.29 > 192.168.7.200: ICMP echo reply, id 56035, seq 1, length 64
08:43:47.666542 IP 192.168.7.200 > 10.1.0.29: ICMP echo request, id 56035, seq 2, length 64
08:43:47.666592 IP 10.1.0.29 > 192.168.7.200: ICMP echo reply, id 56035, seq 2, length 64
^C
4 packets captured
4 packets received by filter
0 packets dropped by kernel
vpc1-nginx:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
202: eth0@if203: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue state UP group default
    link/ether 00:00:00:69:a8:1a brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.1.0.6/24 brd 10.1.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 10.1.0.2/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet 10.1.0.29/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::200:ff:fe69:a81a/64 scope link
       valid_lft forever preferred_lft forever

这两个 ip 没有任何区别, 说明 inet 10.1.0.2/32 这个 vip 经过使用后,确实出现了一些"隐晦"的问题

目前测试的pod fip 和 vip 都不要固定,感觉固定之后的一段时间里, pod 的 fip 和 vip 的 fip 都会出现一定的网络问题

目前问题

bash 复制代码
root@keepalived01-0:/# tcpdump -i eth0 host 192.168.7.200 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
09:14:22.884804 IP 192.168.7.200.31801 > 10.1.0.40.1194: UDP, length 14
09:14:22.885071 IP 10.1.0.41.1194 > 192.168.7.200.31801: UDP, length 26

从 vip 40 进来,但是从 41 回包


root@keepalived01-0:/# ip route list
default via 10.1.0.1 dev eth0
10.1.0.0/24 dev eth0 proto kernel scope link src 10.1.0.41 # 跟这个路由有关系
10.240.0.0/16 via 10.240.0.2 dev tun0
10.240.0.2 dev tun0 proto kernel scope link src 10.240.0.1




ip route replace 10.1.0.0/24 dev eth0 src 10.1.0.40



root@keepalived01-0:/# ip route replace 10.1.0.0/24 dev eth0 src 10.1.0.40
root@keepalived01-0:/#
root@keepalived01-0:/#
root@keepalived01-0:/# ip route list
default via 10.1.0.1 dev eth0
10.1.0.0/24 dev eth0 scope link src 10.1.0.40
10.240.0.0/16 via 10.240.0.2 dev tun0
10.240.0.2 dev tun0 proto kernel scope link src 10.240.0.1



但是没有效果

root@keepalived01-0:/#
root@keepalived01-0:/# tcpdump -i eth0 host 192.168.7.200 -nn
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
09:23:52.715172 IP 192.168.7.200.14333 > 10.1.0.40.1194: UDP, length 14
09:23:52.715400 IP 10.1.0.41.1194 > 192.168.7.200.14333: UDP, length 26


感觉是 openvpn 的业务使用了 优先级最高的那个 ip


把主 ip 删掉,看是否会变

root@keepalived01-0:/# ip addr del 10.1.0.41/24 dev eth0
root@keepalived01-0:/#
root@keepalived01-0:/# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.240.0.0      10.240.0.2      255.255.0.0     UG    0      0        0 tun0
10.240.0.2      0.0.0.0         255.255.255.255 UH    0      0        0 tun0

但是这样的话,因为vip 的掩码是 32 位的,所以默认路由没了



所以如果采取把 vip 当做主ip的方式,起码  掩码应该和主ip保持一致
换了个掩码测试
bash 复制代码
root@empty:~# k exec -it -n ns1            keepalived01-0 -- bash
Defaulted container "ssl" out of: ssl, keepalived
root@keepalived01-0:/#
root@keepalived01-0:/#
root@keepalived01-0:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1279 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none
    inet 10.240.0.1 peer 10.240.0.2/32 scope global tun0
       valid_lft forever preferred_lft forever
309: eth0@if310: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue state UP group default
    link/ether 00:00:00:07:47:55 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.1.0.44/24 brd 10.1.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 10.1.0.43/24 scope global secondary eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::200:ff:fe07:4755/64 scope link
       valid_lft forever preferred_lft forever
root@keepalived01-0:/#
root@keepalived01-0:/#
root@keepalived01-0:/# ip route list
default via 10.1.0.1 dev eth0
10.1.0.0/24 dev eth0 proto kernel scope link src 10.1.0.44
10.240.0.0/16 via 10.240.0.2 dev tun0
10.240.0.2 dev tun0 proto kernel scope link src 10.240.0.1
root@keepalived01-0:/# ip addr del 10.1.0.44/2 dev eth0
RTNETLINK answers: Cannot assign requested address
root@keepalived01-0:/# ip addr del 10.1.0.44/24 dev eth0
root@keepalived01-0:/#
root@keepalived01-0:/# ip route list
10.240.0.0/16 via 10.240.0.2 dev tun0
10.240.0.2 dev tun0 proto kernel scope link src 10.240.0.1
root@keepalived01-0:/# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.240.0.0      10.240.0.2      255.255.0.0     UG    0      0        0 tun0
10.240.0.2      0.0.0.0         255.255.255.255 UH    0      0        0 tun0

即使这样,掩码一致,但是路由还是丢了,路由丢了, keepalived 就把 vip切走了。

这里是一个 keepalived 和 openvpn 结合使用的示例

github.com/mrbobbytabl...

bash 复制代码
# 主
#!/bin/bash
docker run -d --net=host --cap-add NET_ADMIN \
-e ENVIRONMENT=production \
-e PARENT_HOST=$(hostname) \ # 这个就是vip, 这个不是openvpn的配置
-e OVPN_LOCAL=172.16.1.20 \ # 这个在文档中时可选的
-e OVPN_PUSH_1="route 10.10.0.0 255.255.255.0" \
-e OVPN_PUSH_2="dhcp-option DNS 10.10.0.111" \
-e OVPN_PUSH_3="dhcp-option DNS 10.10.0.112" \
-e OVPN_NET_1="eth0:10.10.0.0/24" \ # 这个虽然特殊,但是我找不到具体的配置
-e KEEPALIVED_STATE=MASTER \
-e KEEPALIVED_INTERFACE=eth0 \
-e KEEPALIVED_VIRTUAL_ROUTER_ID=2 \
-e KEEPALIVED_VRRP_UNICAST_BIND=10.10.0.21 \
-e KEEPALIVED_VRRP_UNICAST_PEER=10.10.0.22 \
-e KEEPALIVED_TRACK_INTERFACE_1=eth0 \
-e KEEPALVED_TRACK_INTERFACE_2=eth1 \
-e KEEPALIVED_VIRTUAL_IPADDRESS_1="10.10.0.3 dev eth0" \
-e KEEPALIVED_VIRTUAL_IPADDRESS_EXCLUDED_1="172.16.1.20 dev eth1" \
openvpn-ldap

# 备
#!/bin/bash
docker run -d --net=host --cap-add NET_ADMIN \
-e ENVIRONMENT=production \
-e PARENT_HOST=$(hostname) \
-e OVPN_LOCAL=172.16.1.20 \ # 这个就是vip
-e OVPN_PUSH_1="route 10.10.0.0 255.255.255.0" \
-e OVPN_PUSH_2="dhcp-option DNS 10.10.0.111" \
-e OVPN_PUSH_3="dhcp-option DNS 10.10.0.112" \
-e OVPN_NET_1="eth0:10.10.0.0/24" \
-e KEEPALIVED_STATE=BACKUP \
-e KEEPALIVED_INTERFACE=eth0 \
-e KEEPALIVED_VIRTUAL_ROUTER_ID=2 \
-e KEEPALIVED_VRRP_UNICAST_BIND=10.10.0.22 \
-e KEEPALIVED_VRRP_UNICAST_PEER=10.10.0.21 \
-e KEEPALIVED_TRACK_INTERFACE_1=eth0 \
-e KEEPALVED_TRACK_INTERFACE_2=eth1 \
-e KEEPALIVED_VIRTUAL_IPADDRESS_1="10.10.0.3 dev eth0" \
-e KEEPALIVED_VIRTUAL_IPADDRESS_EXCLUDED_1="172.16.1.20 dev eth1" \
openvpn-ldap

github.com/OpenVPN/ope...

yaml 复制代码
2023-12-07 10:10:07 TCP/UDP: Socket bind failed on local address [AF_INET]10.1.0.49:1194: Cannot assign requested address (errno=99)
2023-12-07 10:10:07 Exiting due to fatal error
2023-12-07 10:10:07 net_route_v4_del: 10.240.0.0/16 via 10.240.0.2 dev [NULL] table 0 metric -1
2023-12-07 10:10:07 Closing TUN/TAP interface
2023-12-07 10:10:07 net_addr_ptp_v4_del: 10.240.0.1 dev tun0

可以看到 如果 keepalived vip 不存在 , openvpn 就起不来。 所以 没有 vip 的 openvpn要有个逻辑一直等 vip。

最后成功基于 vip 的 配置:

bash 复制代码
root@keepalived01-0:/# cat /etc/openvpn/
cat: /etc/openvpn/: Is a directory
root@keepalived01-0:/# cat /etc/openvpn/openvpn.conf
ca /etc/openvpn/certs/pki/ca.crt
cert /etc/openvpn/certs/pki/issued/server.crt
key /etc/openvpn/certs/pki/private/server.key
dh /etc/openvpn/certs/pki/dh.pem

dev tun0
persist-key
persist-tun
duplicate-cn
link-mtu 1400
keysize 256
user nobody
group nogroup
key-direction 0
keepalive 10 120
status /openvpn-status.log
verb 3

local 10.1.0.49
server 10.240.0.0 255.255.0.0
cipher AES-256-GCM
auth SHA1
proto udp
port  1194
push "route 10.1.0.0 255.255.255.0"
push "dhcp-option DOMAIN-SEARCH ns1.svc.cluster.local"
push "dhcp-option DOMAIN-SEARCH svc.cluster.local"
push "dhcp-option DOMAIN-SEARCH cluster.local"

root@keepalived01-0:/# ss -tunlp
Netid                     State                      Recv-Q                     Send-Q                                          Local Address:Port                                           Peer Address:Port                     Process
udp                       UNCONN                     0                          0                                                   10.1.0.49:1194                                                0.0.0.0:*                         users:(("openvpn",pid=55,fd=5))
root@keepalived01-0:/#

总结:

目前确认该现象就是一个 bug, 除非我再加个 haproxy 基于 vip 再转发一下。 但是我是不愿意再加个 haproxy。 还不如去社区提个 issue,或者研究下怎么提 PR。

如果短时间内 fip eip 不变,但是内网 ip 或者 vip 一直变,pod 的 fip 首包会丢十个以上, vip 的 fip 甚至都不通。

这个只是不开启安全组情况下使用 vip fip 的情况,流表中没有维护。 全靠 arp 广播和缓存。可能 arp 确实会国企没清理导致乱掉。

相关推荐
yuuki2332338 小时前
【C语言】文件操作(附源码与图片)
c语言·后端
IT_陈寒8 小时前
Python+AI实战:用LangChain构建智能问答系统的5个核心技巧
前端·人工智能·后端
无名之辈J9 小时前
系统崩溃(OOM)
后端
码农刚子9 小时前
ASP.NET Core Blazor简介和快速入门 二(组件基础)
javascript·后端
间彧9 小时前
Java ConcurrentHashMap如何合理指定初始容量
后端
catchadmin9 小时前
PHP8.5 的新 URI 扩展
开发语言·后端·php
少妇的美梦9 小时前
Maven Profile 教程
后端·maven
白衣鸽子9 小时前
RPO 与 RTO:分布式系统容灾的双子星
后端·架构
Jagger_9 小时前
SOLID原则与设计模式关系详解
后端
间彧9 小时前
Java: HashMap底层源码实现详解
后端