在IDC跨机房,或者docker集群的使用中,经常会有这样的需求:
本地办公网络可以直接访问远程IDC集群的内网。
有两种方案:
- 双向建立路由表
- iptables搞定NAT
路由表是最稳妥的做法,但是双向设置比较繁琐,而且容易出错。
本文介绍的是iptables + openvpn方案。
1、方案:
本地LAN <-- iptables+NAT --> 带openvpn的中转软路由 <-- openvpn --> 远程idc内网(本文是两个内网的docker容器模拟)
2、实验环境:
- vbox-tmp-1 enp0s3连接外网 enp0s8临时内网选internal net,tmpnet,也就是方案中提到的软路由,打开openvpn后,会增加tun0这个网络设备
- vbox-tmp-2 临时内网选internal net,tmpnet,模拟本地LAN网络
- docker-openvpn 远程idc集群上docker容器,暴露接口到公网ip上
- docker-test 远程idc集群上docker容器,和上面的docker在同样内网环境,仅仅用来测试联通性
vbox我用的是virtual box ,可以参考 《Ubuntu通过双网卡+NAT实现共享上网》
3、物理连接
(1) 配置openvpn
#!/bin/bash VOLUME="/home/coder4/docker_data/openvpn" dns_ip="8.8.8.8" vpn_ip="vpn.coder4.com" # init for first time only sudo rm -rf $VOLUME sudo mkdir -p $VOLUME sudo chown -R 777 $VOLUME docker run -v $VOLUME:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://$vpn_ip docker run -v $VOLUME:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki
(2) 创建openvpn
#!/bin/bash # submit to tool node NAME="openvpn" VOLUME="/home/coder4/docker_data/openvpn" dns_ip="8.8.8.8" # stop & run server (should call init_open_vpn_test.sh before) docker ps -q -a --filter "name=$NAME" | xargs -I {} docker rm -f {} docker run \ --name $NAME \ --network camp \ --dns $dns_ip \ -d \ -v $VOLUME:/etc/openvpn \ -p 1194:1194/udp \ --cap-add=NET_ADMIN \ --restart always \ kylemanna/openvpn \ ovpn_run --cipher AES-128-CBC
上面启动后,对外暴露了1194的udp端口,如果你有防火墙,需要开一下端口。
(3) 生成openvpn证书
#!/bin/bash if [ x"$#" != x"1" ];then echo "Usage: $0 <username>" exit -1 fi USERNAME="$1" OVPN_FILE="$USERNAME.ovpn" CIPHER="AES-128-CBC" DNS_IP="8.8.8.8" SWARM_ROUTE_CMD="route 10.18.0.0 255.255.0.0" VOLUME="/home/coder4/docker_data/openvpn" # generate client cert for username docker run -v $VOLUME:/etc/openvpn --rm -it kylemanna/openvpn easyrsa build-client-full $USERNAME nopass docker run -v $VOLUME:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient $USERNAME > $OVPN_FILE # post process sed -i 's/redirect-gateway.*$//' $OVPN_FILE cat >> $OVPN_FILE <<EOF # add this line, the swarm network route $SWARM_ROUTE_CMD # dns update dhcp-option DNS $DNS_IP script-security 2 up /etc/openvpn/update-resolv-conf down /etc/openvpn/update-resolv-conf # security cipher $CIPHER EOF
上面要说明的是:10.18.0.0是我配置的docker network内网,如果你的环境不同,请自行更改
生成命令:
./gen_openvpn_cert.sh coder4
搞好后得到coder4.ovpn
4、本地启动openvpn
在vbox-tmp-1上,启动openvpn
sudo openvpn vpn.coder4.com coder4.opvn
可以尝试ping一下docker-test的内网ip,能ping通就说明openvpn配置对了。
5、配置iptables
还是vbox-tmp-1上
sudo iptables -F sudo iptables -A FORWARD -o tun0 -i enp0s8 -s 192.168.88.0/24 -d 10.18.0.0/16 -m conntrack --ctstate NEW -j ACCEPT sudo iptables -A FORWARD -o enp0s3 -i enp0s8 -s 192.168.88.0/24 -m conntrack --ctstate NEW -j ACCEPT sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT sudo iptables -t nat -F POSTROUTING sudo iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE sudo iptest_doctables -t nat -A POSTROUTING -o tun0 -j MASQUERADE sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
主要是根据不同dst ip 做不同nat,默认是走公网ip,如果发现是10.18.0.0,走openvpn的tun0
6、vbox-tmp-2连上vbox-tmp-1作为网关
不写了,具体可以参考《Ubuntu通过双网卡+NAT实现共享上网》
现在vbox-tmp-2上ping一下docker-test的内网ip,应该可以成功了。
这个方案的优点:配置简单,自带了专线加密隧道。
缺点也很明显:没法区分来源ip,只是单向连通
区分ip的事情,可以考虑iptable上做伪装src和dst包,感兴趣的朋友,欢迎分享你们的iptables配置