简介
网络部分较为复杂,本篇先利用之前写好的基础容器和网桥部分,加上手工给容器配置网络,让其容器与外部网络部分功能正常,为后面程序编写打下基础
源码说明
同时放到了 Gitee 和 Github 上,都可进行获取
本章节对应的版本标签是:5.8,防止后面代码过多,不好查看,可切换到标签版本进行查看
思路梳理
在以前的文章中,我们完成了基础容器的功能,在单机情况下基本可用,但没有网络那就不完善
网络部分目前就写了一个 IP 分配管理工具,和 network 命令,用于创建网桥
在本人尝试过程中,如果不对网络配置部分有一定的了解,对应后面网络部分的编写和理解会感到很懵
所以我们需要进行一定的热身,先手工给我们的容器配置上网络,后面再用代码完成这部分的功能
关于如何手工进行配置,在《自己动手写 Docker》和文章:好文 Linux Network Namespace 与 Bridge 网桥中,都有了很好的描述
跟着上面的链接走一遍了,基本上就通了(PS:如果在 ping 114.114.114.114 始终不行,可能是之前的网络配置过于乱了,将 iptables 规则进行清理或者重启下主机)
对于手动创建网络和配置网络,这里就不再重复,本文的重点放到如果应用上面的知识给目前的容器配置网络
手动配置容器网络
实验环境基于代码的标签:6.2
该部分代码,完成了基本的容器功能和网桥的创建,基于这个基础,我们要做的事情如下:
单容器:
[x] 容器能访问宿主机网络(上篇中已完成)
[ ] 容器能访问外网
[ ] 多容器-同局域网能访问
[ ] 多容器-不同局域网能访问
下面我们继续来完善配置
添加 Iptables 规则,让容器能访问外网
上篇中我们完成了宿主机与容器的网络连通,但容器目前还是不能访问外网,我们需要添加如下的 iptables 规则
iptables -t nat -A POSTROUTING -s 162.16.0.0/24 -j MASQUEREAD
复制代码
目前宿主机的 iptables 规则如下,看到 docker 也配置了这样的一条命令
$ iptables -t nat -nL --line-numbers
Chain PREROUTING (policy ACCEPT)
num target prot opt source destination
1 DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
num target prot opt source destination
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
1 DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
# 下面看到docker也添加了一条这样的规则
Chain POSTROUTING (policy ACCEPT)
num target prot opt source destination
1 MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
2 MASQUERADE all -- 182.18.0.0/24 0.0.0.0/0
3 MASQUERADE all -- 162.16.0.0/24 0.0.0.0/0
Chain DOCKER (2 references)
num target prot opt source destination
1 RETURN all -- 0.0.0.0/0 0.0.0.0/0
复制代码
下面我们从容器内访问下:114.114.114.114,看到成功访问
$ ./main exec bird ping 114.114.114.114
PING 114.114.114.114 (114.114.114.114): 56 data bytes
64 bytes from 114.114.114.114: seq=0 ttl=77 time=32.301 ms
64 bytes from 114.114.114.114: seq=1 ttl=72 time=33.687 ms
64 bytes from 114.114.114.114: seq=2 ttl=75 time=33.727 ms
64 bytes from 114.114.114.114: seq=3 ttl=84 time=34.131 ms
64 bytes from 114.114.114.114: seq=4 ttl=82 time=35.087 ms
64 bytes from 114.114.114.114: seq=5 ttl=95 time=33.474 ms
^C
--- 114.114.114.114 ping statistics ---
6 packets transmitted, 6 packets received, 0% packet loss
round-trip min/avg/max = 32.301/33.734/35.087 ms
复制代码
新增同局域网内的容器,进行访问
和上篇基本一样的操作,将新起动的容器分配同上一个容器一样的局域网 ip:162.16.0.3
# 新启动容器2
$ ./main run -d -e bird=123 -name bird2 top
{"level":"info","msg":"memory cgroup path: /sys/fs/cgroup/memory/mydocker-cgroup","time":"2022-04-23T14:38:34+08:00"}
{"level":"info","msg":"memory cgroup path: /sys/fs/cgroup/memory/mydocker-cgroup","time":"2022-04-23T14:38:34+08:00"}
{"level":"info","msg":"all command is : top","time":"2022-04-23T14:38:34+08:00"}
{"level":"info","msg":"parent process run","time":"2022-04-23T14:38:34+08:00"}
# 新建veth,设置宿主机端的veth
$ ip link add birdveth2 type veth peer name birdveth3
$ ip link set dev birdveth2 master testbridge
$ ip link set dev birdveth2 up
# 设置容器2内部的veth
$ ps -aux|grep top
root 2769 0.0 0.0 539820 10860 ? Ssl 07:01 0:01 /usr/libexec/xdg-desktop-portal
root 2773 0.0 0.0 500052 29516 ? Ssl 07:01 0:00 /usr/libexec/xdg-desktop-portal-gtk
root 39207 0.0 0.0 1328 4 pts/4 S 09:47 0:01 top
root 64560 0.0 0.0 1328 4 pts/4 S 14:38 0:00 top
root 64749 0.0 0.0 12132 724 pts/4 R+ 14:47 0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox top
$ ln -s /proc/64560/ns/net /var/run/netns/bird2
$ ip netns list
bird2
bird (id: 2)
k8svip (id: 1)
$ ip link set birdveth3 netns bird2
$ ./main exec bird2 ip link set dev lo up
$ ./main exec bird2 ip link set dev birdveth3 up
$ ./main exec bird2 ip addr add 162.16.0.3/24 dev birdveth3
# 成功ping通网关
$ ./main exec bird2 ping 162.16.0.1
PING 162.16.0.1 (162.16.0.1): 56 data bytes
64 bytes from 162.16.0.1: seq=0 ttl=64 time=0.135 ms
64 bytes from 162.16.0.1: seq=1 ttl=64 time=0.152 ms
^C
--- 162.16.0.1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.135/0.143/0.152 ms
# 容器2能成功联通容器1
$ ./main exec bird2 ping 162.16.0.2
PING 162.16.0.2 (162.16.0.2): 56 data bytes
64 bytes from 162.16.0.2: seq=0 ttl=64 time=0.138 ms
64 bytes from 162.16.0.2: seq=1 ttl=64 time=0.154 ms
^C
--- 162.16.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.138/0.146/0.154 ms
# 容器1能成功联通容器2
$ ./main exec bird ping 162.16.0.3
PING 162.16.0.3 (162.16.0.3): 56 data bytes
64 bytes from 162.16.0.3: seq=0 ttl=64 time=0.090 ms
64 bytes from 162.16.0.3: seq=1 ttl=64 time=0.154 ms
^C
--- 162.16.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.090/0.122/0.154 ms
$ ./main exec bird2 ip route add default via 162.16.0.1
$ ./main exec bird2 ping 114.114.114.114
PING 114.114.114.114 (114.114.114.114): 56 data bytes
64 bytes from 114.114.114.114: seq=0 ttl=82 time=32.376 ms
64 bytes from 114.114.114.114: seq=1 ttl=92 time=37.692 ms
^C
--- 114.114.114.114 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 32.376/35.034/37.692 ms
复制代码
经过试验,我们处于同一个局域网的容器是能够联通的
配置 DNAT,让外部能够访问内部服务
首先我们在容器内监听 95 端口,然后在宿主机内访问 95 端口是能正常访问的
# 在容器内监听95端口,能收到相关指令
$ ./main exec bird nc -lp 95
jkjfdks
kfjskd
��������
quit
exit
exit()
quit()
# 在宿主机中进行telnet并发送指令,如上可以进行显示(ctrl + ],后输入quit,退出telnet)
$ telnet 162.16.0.2 95
Trying 162.16.0.2...
Connected to 162.16.0.2.
Escape character is '^]'.
jkjfdks
kfjskd
^C^C
quit
exit
exit()
quit()
^]
telnet> quit
Connection closed.
复制代码
但是如同我们在使用 docker 的过程中,我们是映射了端口的,如:docker run -tid --name centos8-2 -p 90:90 centos:8 bash
在上面的示例中,我们访问容器所在宿主机 90 端口,就能访问到容器的 90 端口,下面我们就通过配置来达到这个目的
进行下面的配置,下面会将宿主机 95 端口上的请求,都转到容器 162.16.0.2 的 95 端口上
# 配置规则
$ iptables -t nat -A PREROUTING -p tcp -m tcp --dport 95 -j DNAT --to-destination 162.16.0.2:95
# 查看规则,看到docker也是通过相关配置达到这个目的的
$ iptables -t nat -nL --line-numbers
Chain PREROUTING (policy ACCEPT)
num target prot opt source destination
1 DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
2 DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:95 to:162.16.0.2:95
Chain INPUT (policy ACCEPT)
num target prot opt source destination
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
1 DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
num target prot opt source destination
1 MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
2 MASQUERADE all -- 182.18.0.0/24 0.0.0.0/0
3 MASQUERADE all -- 162.16.0.0/24 0.0.0.0/0
4 MASQUERADE tcp -- 172.17.0.3 172.17.0.3 tcp dpt:90
Chain DOCKER (2 references)
num target prot opt source destination
1 RETURN all -- 0.0.0.0/0 0.0.0.0/0
2 DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:90 to:172.17.0.3:90
复制代码
# 在宿主机上监听95端口
nc -lp 95
# 新开shell或者在和宿主机同一个局域网的主机上进行telnet连接
telnet 192.168.1.5 95
复制代码
重新启动容器监听后,看到相关的输出,证明外部也访问容器服务了
$ ./main exec bird nc -lp 95
jkjfdskfjs
复制代码
总结
不同局域网的互通,尝试了下,有点难度,目前本人的知识理解还不能做到,只能后面再补上了,先通过实现这部分的功能
评论