简介
网络部分较为复杂,本篇先利用之前写好的基础容器和网桥部分,加上手工给容器配置网络,让其容器与宿主机网络部分功能正常,为后面程序编写打下基础
源码说明
同时放到了 Gitee 和 Github 上,都可进行获取
本章节对应的版本标签是:5.8,防止后面代码过多,不好查看,可切换到标签版本进行查看
思路梳理
在以前的文章中,我们完成了基础容器的功能,在单机情况下基本可用,但没有网络那就不完善
网络部分目前就写了一个 IP 分配管理工具,和 network 命令,用于创建网桥
在本人尝试过程中,如果不对网络配置部分有一定的了解,对应后面网络部分的编写和理解会感到很懵
所以我们需要进行一定的热身,先手工给我们的容器配置上网络,后面再用代码完成这部分的功能
关于如何手工进行配置,在《自己动手写 Docker》和文章:好文 Linux Network Namespace 与 Bridge 网桥中,都有了很好的描述
跟着上面的链接走一遍了,基本上就通了(PS:如果在 ping 114.114.114.114 始终不行,可能是之前的网络配置过于乱了,将 iptables 规则进行清理或者重启下主机)
对于手动创建网络和配置网络,这里就不再重复,本文的重点放到如果应用上面的知识给目前的容器配置网络
准备工作
实验环境基于代码的标签:6.2
该部分代码,完成了基本的容器功能和网桥的创建,基于这个基础,我们要做的事情如下:
单容器:
容器能访问宿主机网络
容器能访问外网
多容器-同局域网能访问
多容器-不同局域网能访问
手动网络配置
容器启动与网桥创建
创建网桥,将我们的网段设置为:162.16.0.0/24
$ ./main network create --driver bridge --subnet 162.16.0.1/24 testbridge
{"level":"info","msg":"allocate subnet: 162.16.0.1/24, ip: 162.16.0.1","time":"2022-04-23T09:37:13+08:00"}
{"level":"info","msg":"dump ipam file from: /var/run/mydocker/network/ipam/","time":"2022-04-23T09:37:13+08:00"}
{"level":"info","msg":"BridgeNetworkDriver creat network subnet: 162.16.0.1/24, gateway ip: 162.16.0.1","time":"2022-04-23T09:37:13+08:00"}
{"level":"info","msg":"createBridgeInterface success","time":"2022-04-23T09:37:13+08:00"}
{"level":"info","msg":"setInterfaceIp success","time":"2022-04-23T09:37:13+08:00"}
{"level":"info","msg":"crsetInterfaceUp success","time":"2022-04-23T09:37:13+08:00"}
{"level":"info","msg":"setInterfaceUp success","time":"2022-04-23T09:37:13+08:00"}
{"level":"info","msg":"create network success","time":"2022-04-23T09:37:13+08:00"}
$ ./main network list
NAME IpRange Driver
testbridge 162.16.0.1/24 bridge
复制代码
在宿主机上查看我们网桥,使用 ip 命令进行查看,可以看到我们网桥成功创建,并设置了 ip 为:162.16.0.1,这将作为我们容器的网关 IP
$ ip addr
10: testbridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether 4e:83:e8:ca:fd:f2 brd ff:ff:ff:ff:ff:ff
inet 162.16.0.1/24 brd 162.16.0.255 scope global testbridge
valid_lft forever preferred_lft forever
inet6 fe80::4c83:e8ff:feca:fdf2/64 scope link
valid_lft forever preferred_lft forever
复制代码
使用 brctl 命令查看网桥,可以看到之前我自己试验和 docker 的网桥,还有我们刚刚创建的网桥,它并没挂载任务的网卡,所以目前 interfaces 为空
$ brctl show
bridge name bridge id STP enabled interfaces
br0 8000.ee3baaf9db1c no veth0
docker0 8000.0242d4fb76d9 no veth0cf8b9a
testbridge 8000.000000000000 no
复制代码
ping 一下我们的网桥,可以看到可以接通,接下来开始生成容器
$ ping 162.16.0.1
PING 162.16.0.1 (162.16.0.1) 56(84) bytes of data.
64 字节,来自 162.16.0.1: icmp_seq=1 ttl=64 时间=0.068 毫秒
64 字节,来自 162.16.0.1: icmp_seq=2 ttl=64 时间=0.102 毫秒
64 字节,来自 162.16.0.1: icmp_seq=3 ttl=64 时间=0.102 毫秒
^C
--- 162.16.0.1 ping 统计 ---
已发送 3 个包, 已接收 3 个包, 0% 包丢失, 耗时 2034 毫秒
rtt min/avg/max/mdev = 0.068/0.090/0.102/0.016 ms
复制代码
使用我们编程的 docker demo 启动容器
./main run -d -e bird=123 -name bird top
./main logs bird
Mem: 5858364K used, 26416068K free, 99272K shrd, 126360K buff, 2733672K cached
CPU: 0.0% usr 0.0% sys 0.0% nic 99.9% idle 0.0% io 0.0% irq 0.0% sirq
Load average: 0.00 0.00 0.00 1/1249 6
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
$ ./main exec bird env |grep bird
bird=123
复制代码
如上所示,到此,基本准备工作完成,开始网络的配置
创建网卡,给容器配置
首先查看下我们容器目前的网卡情况,可以看到目前只有一个本地回环网卡 lo,而且 ping 127.0.0.1 不通,网络没有 ip 也没有启动
$ ./main exec bird ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
$ ./main exec bird ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
ping: sendto: Network is unreachable
复制代码
目前使用 ip netns list 命令,没有办法看到我们容器的网络命名空间,需要采取一些手段,将其恢复
查看我们容器的 PID
运行命令将进程网络命名空间恢复到主机目录
$ ps -aux|grep top
root 2769 0.0 0.0 539820 10860 ? Ssl 07:01 0:00 /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:00 top
root 39469 0.0 0.0 12132 2600 pts/4 S+ 09:58 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
# 上面的39207是我们的容器PID
ln -s /proc/39207/ns/net /var/run/netns/bird
# 查看网络命名空间列表看到我们的容器命名空间
$ ip netns list
bird
k8svip (id: 1)
复制代码
下面创建一对 Veth,给容器和网桥进行装配
# 创建一对veth,birdveth0 放到宿主机、birdveth1放到容器内
ip link add birdveth0 type veth peer name birdveth1
# 将birdveth1放到容器网络命名空间内
ip link set birdveth1 netns bird
复制代码
在容器内查看,可以看到我们的容器装配了 bridveth1
$ ./main exec bird ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
11: birdveth1@if12: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop qlen 1000
link/ether de:ae:81:2c:df:9a brd ff:ff:ff:ff:ff:ff
复制代码
下面我们配置启动相关的网络
# 启动本地回环网卡
./main exec bird ip link set dev lo up
# 启动我们装备的bridveth1网卡
./main exec bird ip link set dev birdveth1 up
# 查看相关的配置,发现两个网卡都起来了(有UP标识),并且lo网卡有了自己的ip 127.0.0.1
$ ./main exec bird ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
11: birdveth1@if12: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue qlen 1000
link/ether de:ae:81:2c:df:9a brd ff:ff:ff:ff:ff:ff
# ping下本地,发现也正常了
$ ./main exec bird ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: seq=0 ttl=64 time=0.057 ms
64 bytes from 127.0.0.1: seq=1 ttl=64 time=0.100 ms
64 bytes from 127.0.0.1: seq=2 ttl=64 time=0.103 ms
64 bytes from 127.0.0.1: seq=3 ttl=64 time=0.099 ms
64 bytes from 127.0.0.1: seq=4 ttl=64 time=0.101 ms
^C
--- 127.0.0.1 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.057/0.092/0.103 ms
# 随便ping一下,发现网络不行
$ ./main exec bird ping 162.16.0.1
PING 162.16.0.1 (162.16.0.1): 56 data bytes
ping: sendto: Network is unreachable
复制代码
讲过上面的配置,我们使用 lo 网卡恢复了正常,虽然 birdveth1 网卡功能不正常,但也装配上了
下面开始,我们开始分配相关的 ip
宿主机网卡挂载网桥,使连接网关正常
我们在创建网桥的时候,已经分配了网关 ip:162.16.0.1
下面我们需要给我们的容器配置同局域网内的 IP:162.16.0.2
$ ./main exec bird ip addr add 162.16.0.2/24 dev birdveth1
$ ./main exec bird ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
11: birdveth1@if12: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue qlen 1000
link/ether de:ae:81:2c:df:9a brd ff:ff:ff:ff:ff:ff
inet 162.16.0.2/24 scope global birdveth1
valid_lft forever preferred_lft forever
# root @ lw-Code-01-Series-PF5NU1G in ~/code/go/dockerDemo on git:main x [10:25:39]
$ ./main exec bird ping 162.16.0.1
PING 162.16.0.1 (162.16.0.1): 56 data bytes
--- 162.16.0.1 ping statistics ---
4 packets transmitted, 0 packets received, 100% packet loss
复制代码
分配 IP 后,我们看到 birdveth1 有了自己的 ip 地址,ping 网关 ip 162.16.0.1 没有报网络错误,只是没有响应,这个是宿主机的网络还没有配置完成,继续进行配置
# 将birdveth0设置到网桥上
$ ip link set dev birdveth0 master testbridge
# 启动birdveth0
$ ip link set dev birdveth0 up
# 查看相关的信息,看到birdveth0已经启动
$ ip ad
10: testbridge: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 32:ec:92:ab:76:8f brd ff:ff:ff:ff:ff:ff
inet 162.16.0.1/24 brd 162.16.0.255 scope global testbridge
valid_lft forever preferred_lft forever
inet6 fe80::4c83:e8ff:feca:fdf2/64 scope link
valid_lft forever preferred_lft forever
12: birdveth0@if11: <BROADCAST,MULTICAST> mtu 1500 qdisc noop master testbridge state DOWN group default qlen 1000
link/ether 32:ec:92:ab:76:8f brd ff:ff:ff:ff:ff:ff link-netns bird
# 从容器内ping我们的网关,OK
$ ./main exec bird 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.113 ms
64 bytes from 162.16.0.1: seq=1 ttl=64 time=0.151 ms
^C
--- 162.16.0.1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.113/0.132/0.151 ms
# 但ping宿主机IP还是不行,需要进行路由的配置
$ ./main exec bird ping 192.168.1.5
PING 192.168.1.5 (192.168.1.5): 56 data bytes
ping: sendto: Network is unreachable
复制代码
到此为止,我们将网关部分的链路打通,接下来开始打通宿主机和容器的网络
设置路由,使容器与宿主机网络互通
我们先查看下容器内容的路由
$ ./main exec bird ip route
162.16.0.0/24 dev birdveth1 scope link src 162.16.0.2
复制代码
根据教程,我们添加下默认路由配置(博主现在也没完全掌握这部分知识,后面补补这部分知识)
# 添加路由配置
$ ./main exec bird ip route add default via 162.16.0.1
# ping 宿主机网络已经通了
$ ./main exec bird ping 192.168.1.5
PING 192.168.1.5 (192.168.1.5): 56 data bytes
64 bytes from 192.168.1.5: seq=0 ttl=64 time=0.082 ms
64 bytes from 192.168.1.5: seq=1 ttl=64 time=0.156 ms
64 bytes from 192.168.1.5: seq=2 ttl=64 time=0.154 ms
^C
--- 192.168.1.5 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.082/0.130/0.156 ms
$ ping 162.16.0.2
PING 162.16.0.2 (162.16.0.2) 56(84) bytes of data.
64 字节,来自 162.16.0.2: icmp_seq=1 ttl=64 时间=0.161 毫秒
64 字节,来自 162.16.0.2: icmp_seq=2 ttl=64 时间=0.108 毫秒
^C
--- 162.16.0.2 ping 统计 ---
已发送 2 个包, 已接收 2 个包, 0% 包丢失, 耗时 1020 毫秒
rtt min/avg/max/mdev = 0.108/0.134/0.161/0.026 ms
复制代码
总结
经过上面的折腾,我们将我们的容器和宿主机网络进行打通,下篇中将继续打通容易与外部网络,让容器能与外网进行访问
参考链接
评论