docker与物理网络互通

警告
本文最后更新于 2023-05-05,文中内容可能已过时。

微服务的流行推动着容器技术的发展,伴随着新技术的应用产生了新的问题。比如开发人员本机无法运行诸多的微服务,如何保障开发正常进行。本文将介绍如何打通开发环境网与docker环境之间的网络。

由于Kubernetes集群会使用CNI插件创建Pod/Service内部子网,外面一般无法访问内部IP和域名,给开发、测试、 联调带来了很大的麻烦,因此打通开发测试环境Kubernetes集群内部子网和办公室的局域网、实现互联互通是经常遇到的问题。

选一台docker节点做路由转发,连接办公室网络和 docker 集群服务

  • 节点 IP 地址 192.168.1.90
  • 容器网段 10.42.0.0/16
  • 办公网段 192.168.0.0/24

image-20210303144129408

我的网络整体结构本身不复杂,所以相对来说配置简单。

节点,做snat:

开启转发

1
2
3
vim /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
sysctl -p

来自办公室访问docker service snat

iptables命令是Linux上常用的防火墙软件,是netfilter项目的一部分。可以直接配置,也可以通过许多前端和图形界面配置。

语法

1
iptables(选项)(参数)

选项

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
-t<表>:指定要操纵的表;
-A:向规则链中添加条目;
-D:从规则链中删除条目;
-i:向规则链中插入条目;
-R:替换规则链中的条目;
-L:显示规则链中已有的条目;
-F:清楚规则链中已有的条目;
-Z:清空规则链中的数据包计算器和字节计数器;
-N:创建新的用户自定义规则链;
-P:定义规则链中的默认目标;
-h:显示帮助信息;
-p:指定要匹配的数据包协议类型;
-s:指定要匹配的数据包源ip地址;
-d:指定要匹配的数据包目的ip地址;
-j<目标>:指定要跳转的目标;
-i<网络接口>:指定数据包进入本机的网络接口;
-o<网络接口>:指定数据包要离开本机所使用的网络接口。

iptables命令选项输入顺序:

1
iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作

表名包括:

  • raw:高级功能,如:网址过滤。
  • mangle:数据包修改(QOS),用于实现服务质量。
  • net:地址转换,用于网关路由器。
  • filter:包过滤,用于防火墙规则。

规则链名包括:

  • INPUT链:处理输入数据包。
  • OUTPUT链:处理输出数据包。
  • PORWARD链:处理转发数据包。
  • PREROUTING链:用于目标地址转换(DNAT)。
  • POSTOUTING链:用于源地址转换(SNAT)。

动作包括:

  • [accept]:接收数据包。
  • DROP:丢弃数据包。
  • REDIRECT:重定向、映射、透明代理。
  • SNAT:源地址转换。
  • DNAT:目标地址转换。
  • MASQUERADE:IP伪装(NAT),用于ADSL。
  • LOG:日志记录。
1
iptables -t nat -A POSTROUTING -s 192.168.11.0/24 -d 10.42.0.0/16 -j MASQUERADE

POSTROUTING是源地址转换(SNAT),要把你内部网络上受防火墙保护的ip地址转换成你本地的公网地址才能让它们上网。 PREROUTING是目的地址转换(DNAT),要把别人的公网IP换成你们内部的IP,才让访问到你们内部受防火墙保护的服务器。 MASQUERADE,地址伪装,算是snat中的一种特例,可以实现自动化的snat

借用阿里云的一张图

NAT网关图解

多个内网段SNAT,就是多条SNAT语句即可

1
2
3
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -d 10.42.0.0/16 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.42.0.0/16 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.11.0/24 -d 10.42.0.0/16 -j MASQUERADE

在办公室的出口路由器上,设置静态路由,将docker的网段,路由到节点上

1
ip route 10.42.0.0 255.255.255.0 192.168.1.90

以上步骤操作后,我们就可以在本地电脑通过访问docker ip去访问服务。

image-20210303135329788

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
OVPN_DATA=/data/openvpn
SERVER_PUBLIC_URL=172.30.4.195
DNS_SERVER=180.168.255.118
SERVER_SUBNET=10.4.0.0/24

docker run \
-v ${OVPN_DATA}:/etc/openvpn \
--rm \
kylemanna/openvpn:2.4 \
ovpn_genconfig -u udp://${SERVER_PUBLIC_URL} -n ${DNS_SERVER} -p "route 10.42.0.0 255.255.0.0" -s ${SERVER_SUBNET}

参数说明

-u SERVER_PUBLIC_URL # vpn所在服务器的公网ip -n DNS_SERVER # dns服务器地址 -p PUSH # 推送路由 -s SERVER_SUBNET # vpn内网范围,一定要注意,不要和已有物理网络、Kubernetes网络冲突。

image-20210731141857240

修改配置

注释push "block-outside-dns"一行,我这里不注释 dns 解析异常

1
2
3
4
5
6
7
OVPN_DATA=/data/openvpn

docker run \
-v ${OVPN_DATA}:/etc/openvpn \
--rm -it \
kylemanna/openvpn:2.4 \
ovpn_initpki

在此要输入ca的密码,需要输入两次。

1
2
Enter New CA Key Passphrase:
Re-Enter New CA Key Passphrase:

image-20210723095326974

此处要输入组织,可直接回车跳过。

1
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:

输入之前设置的私钥密码,需要输入两次

1
Enter pass phrase for /etc/openvpn/pki/private/ca.key:

image-20210723095711430

1
2
3
4
5
6
7
8
OVPN_DATA=/data/openvpn

docker run -d \
--name openvpn \
-v ${OVPN_DATA}:/etc/openvpn \
-p 1194:1194/udp \
--cap-add=NET_ADMIN \
kylemanna/openvpn:2.4

CLIENTNAME可以是你想要的名字

1
2
3
4
5
6
7
8
OVPN_DATA=/data/openvpn
CLIENTNAME=docker

docker run \
-v ${OVPN_DATA}:/etc/openvpn \
--rm -it \
kylemanna/openvpn:2.4 \
easyrsa build-client-full ${CLIENTNAME} nopass

输入之前设置的密码

1
Enter pass phrase for /etc/openvpn/pki/private/ca.key:

image-20210723100324352

1
2
3
4
5
6
7
8
9
OVPN_DATA=/data/openvpn
CLIENTNAME=docker

mkdir -p /data/openvpn/conf
docker run \
-v ${OVPN_DATA}:/etc/openvpn \
--rm \
kylemanna/openvpn:2.4 \
ovpn_getclient ${CLIENTNAME} > /data/openvpn/conf/${CLIENTNAME}.ovpn

参考之前的Cenos7搭建OpenVPN

服务端配置文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
server 10.4.0.0 255.255.255.0
verb 3
key /etc/openvpn/pki/private/192.168.1.91.key
ca /etc/openvpn/pki/ca.crt
cert /etc/openvpn/pki/issued/192.168.1.91.crt
dh /etc/openvpn/pki/dh.pem
#tls-auth /etc/openvpn/pki/ta.key
key-direction 0
keepalive 10 60
persist-key
persist-tun

proto udp
# Rely on Docker to do port mapping, internally always 1194
port 1194
dev tun0
status /tmp/openvpn-status.log

user nobody
group nogroup
comp-lzo no

### Route Configurations Below
route 192.168.254.0 255.255.255.0

### Push Configurations Below
#push "block-outside-dns"
push "dhcp-option DNS 180.168.255.118"
push "comp-lzo no"
push "route 10.42.0.0 255.255.0.0"

client-cert-not-required
auth-user-pass-verify /etc/openvpn/checkpsw.sh via-env
username-as-common-name
script-security 3

客户端配置文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
client
nobind
dev tun
auth-user-pass
remote-cert-tls server
remote 192.168.1.91 1194 udp

<ca>
-----BEGIN CERTIFICATE-----

-----END CERTIFICATE-----
</ca>

参考链接:

打通Kubernetes内网与局域网的N种方法

办公环境下 Kubernetes 网络互通方案

OpenVPN访问Kubernetes集群内网