写点什么

自己动手写 Docker 系列 -- 6.3 手动配置容器网络 (上)

作者:
  • 2022 年 4 月 23 日
  • 本文字数:5690 字

    阅读完需:约 19 分钟

简介

网络部分较为复杂,本篇先利用之前写好的基础容器和网桥部分,加上手工给容器配置网络,让其容器与宿主机网络部分功能正常,为后面程序编写打下基础

源码说明

同时放到了 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 listNAME IpRange Drivertestbridge 162.16.0.1/24 bridge
复制代码


在宿主机上查看我们网桥,使用 ip 命令进行查看,可以看到我们网桥成功创建,并设置了 ip 为:162.16.0.1,这将作为我们容器的网关 IP


$ ip addr10: 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 showbridge name     bridge id               STP enabled     interfacesbr0             8000.ee3baaf9db1c       no              veth0docker0         8000.0242d4fb76d9       no              veth0cf8b9atestbridge              8000.000000000000       no
复制代码


ping 一下我们的网桥,可以看到可以接通,接下来开始生成容器


$ ping 162.16.0.1PING 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 cachedCPU: 0.0% usr 0.0% sys 0.0% nic 99.9% idle 0.0% io 0.0% irq 0.0% sirqLoad average: 0.00 0.00 0.00 1/1249 6 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
$ ./main exec bird env |grep birdbird=123
复制代码


如上所示,到此,基本准备工作完成,开始网络的配置

创建网卡,给容器配置

首先查看下我们容器目前的网卡情况,可以看到目前只有一个本地回环网卡 lo,而且 ping 127.0.0.1 不通,网络没有 ip 也没有启动


$ ./main exec bird ip addr1: 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.1PING 127.0.0.1 (127.0.0.1): 56 data bytesping: sendto: Network is unreachable
复制代码


目前使用 ip netns list 命令,没有办法看到我们容器的网络命名空间,需要采取一些手段,将其恢复


  • 查看我们容器的 PID

  • 运行命令将进程网络命名空间恢复到主机目录


$ ps -aux|grep toproot        2769  0.0  0.0 539820 10860 ?        Ssl  07:01   0:00 /usr/libexec/xdg-desktop-portalroot        2773  0.0  0.0 500052 29516 ?        Ssl  07:01   0:00 /usr/libexec/xdg-desktop-portal-gtkroot       39207  0.0  0.0   1328     4 pts/4    S    09:47   0:00 toproot       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是我们的容器PIDln -s /proc/39207/ns/net /var/run/netns/bird
# 查看网络命名空间列表看到我们的容器命名空间$ ip netns listbirdk8svip (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 addr1: lo: <LOOPBACK> mtu 65536 qdisc noop qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:0011: 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 addr1: 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 forever11: 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.1PING 127.0.0.1 (127.0.0.1): 56 data bytes64 bytes from 127.0.0.1: seq=0 ttl=64 time=0.057 ms64 bytes from 127.0.0.1: seq=1 ttl=64 time=0.100 ms64 bytes from 127.0.0.1: seq=2 ttl=64 time=0.103 ms64 bytes from 127.0.0.1: seq=3 ttl=64 time=0.099 ms64 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 lossround-trip min/avg/max = 0.057/0.092/0.103 ms
# 随便ping一下,发现网络不行$ ./main exec bird ping 162.16.0.1PING 162.16.0.1 (162.16.0.1): 56 data bytesping: 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 addr1: 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 forever11: 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.1PING 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 ad10: 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 forever12: 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.1PING 162.16.0.1 (162.16.0.1): 56 data bytes64 bytes from 162.16.0.1: seq=0 ttl=64 time=0.113 ms64 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 lossround-trip min/avg/max = 0.113/0.132/0.151 ms
# 但ping宿主机IP还是不行,需要进行路由的配置$ ./main exec bird ping 192.168.1.5PING 192.168.1.5 (192.168.1.5): 56 data bytesping: sendto: Network is unreachable
复制代码


到此为止,我们将网关部分的链路打通,接下来开始打通宿主机和容器的网络

设置路由,使容器与宿主机网络互通

我们先查看下容器内容的路由


$ ./main exec bird ip route162.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.5PING 192.168.1.5 (192.168.1.5): 56 data bytes64 bytes from 192.168.1.5: seq=0 ttl=64 time=0.082 ms64 bytes from 192.168.1.5: seq=1 ttl=64 time=0.156 ms64 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 lossround-trip min/avg/max = 0.082/0.130/0.156 ms
$ ping 162.16.0.2PING 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
复制代码

总结

经过上面的折腾,我们将我们的容器和宿主机网络进行打通,下篇中将继续打通容易与外部网络,让容器能与外网进行访问

参考链接

发布于: 刚刚阅读数: 2
用户头像

关注

还未添加个人签名 2018.09.09 加入

代码是门手艺活,也是门艺术活

评论

发布
暂无评论
自己动手写Docker系列 -- 6.3 手动配置容器网络(上)_Go_萧_InfoQ写作社区