《跟唐老师学习云网络》 - Docker网络实现
本机容器网络大概生成过程:首先每个容器对应创建一个network namespace;然后将所有的容器的network namespace连接到Bridge网桥(docker0)上,使得容器间互相处于一个局域网内,方便连通。
1 Docker的网络命名空间
docker使用namespace实现容器网络,但是我们使用ip netns命令却无法在主机上看到任何network namespace,这是因为默认docker把创建的网络命名空间链接文件隐藏起来了。
有2种进入这个“空间”的命令,我们以前的课都讲过。
1.1 通过ip netns exec
启动一个容器
docker run -tid ubuntu:18.04
这个时候,查询 network namespace,却发现是空的。
因为 ip netns 是去检查 /var/run/netns 目录的。而Docker这个软件,故意把容器对应的ns信息记录到了 /var/run/docker/netns 目录。所以ip netns查出来就是空的,我们想办法把ns信息翻出来就行。
(1)恢复关联-方式1
所以我们,把这2个目录关联一下:
ln -s /var/run/docker/netns /var/run/netns
接下来再敲:
ip netns
就可以看到容器的 network namespace 了。
不过可以发现列出来的ns的ID,和对应容器的ID,不是同一个。 它两有一个映射值,可以通过 docker inspect 的结果查到对应关系:
docker inspect 070044b2738f
(2)恢复关联-方式2
找到容器主pid:
pid=$(docker inspect -f '{{.State.Pid}}' ${container_id})
创建对应的ns记录:
mkdir -p /var/run/netns/
ln -sfT /proc/$pid/ns/net /var/run/netns/$container_id
1.2 通过 nsenter
找到容器里app的主pid。
docker inspect ecf8689d3297
跑到这个pid对应的世界(namespace)里去。
nsenter -n -t 25977
这个时候,就是在容器里面的网络空间角度敲命令啦。
例如:
(1)查询网卡:
ifconfig
(2)抓包:
tcpdump -i eth0 -n
2 Docker 使用的Linux Bridge
关于Docker为什么要加个Bridge来连通所有的容器?其实不加Bridge,网络也能通。只是说有了Bridge,就有了覆盖更多复杂场景的能力。
这里直接引用Docker自己的描述:通过Bridge,可以使得连到这个Bridge的容器互相通信;同时和没有连到这个Bridge的容器保持网络隔离。(大意就是:容器可以按网络分组)
3 我怎么和本机Host主机通信
假设我就是那个Docker容器,那么我是如何与主机Host通信的呢。
3.1 本机Host怎么访问我
主机Host访问自己节点上的容器,答案是:直接访问就行了。
咱们先来看Host主机的路由表:
因为根据路由信息:
所有发往Docker容器的地址(即目标为 172.17.* )的报文,---> 统统走给 ---> docker0 网卡。而根据上面Bridge章节可以知道,这个docker0就是Bridge网桥,它是连着所有容器的Veth网线的。所以这个报文会发送到所有容器里面,那么目标容器就会应答你。
3.2 我怎么访问所在的Host主机
容器访问自己的Host主机,答案也是直接访问。
Docker容器里面,网络很简单,就一个eth0。所以你往外发报文,都是经过eth0网卡。而这个网卡是一个veth网线的一头,所以这个报文就会到达Bridge网桥(即docker0)。而这个网桥就是Host主机的一个网卡,所以就到达了目的地。
综上,Docker容器和Host主机,是可以自由通信的。
3.3 本机其他容器怎么访问我
这个问题,直接去Bridge章节看一下就行了。大家都通过docker0这个Bridge焊在一起,所以直接互访就行了。
4 我怎么和别的Host主机通信
别的Host主机,就是“爸爸(所在节点)的兄弟”。
4.1 别的Host怎么访问我
跨节点访问容器时,由于不知道目标容器是住在哪台Host主机上(要访问那个容器,必须经过它所在的Host),所以为了访问一个目标容器专门设置一条路由规则(当我访问xxx容器时,请经过yyy虚拟机,这种规则),并不方便。所以一般直接用端口映射来访问。
即:目标容器所在的Host主机IP + 指定端口。然后当报文到达指定目标的Host主机时,通过指定端口Nat进入容器。
举例:
(1) 在192.168.1.9这台机器上启动一个Nginx容器:注意这里-p参数告诉Host,请将主机上面的80端口,作为进入我的NAT入口。
docker run -rm -p 80:80 nginx
(2) 然后咱们再另外找一台机器(与刚才192.168.1.9 这一台能连通)。
跨节点访问刚才那个容器:
curl -vvv 192.168.1.9:80
这里可以看到,主机跨节点访问容器时,必须通过指定端口NAT进入到目标容器。
直接访问IP是不通的(没有路由信息)
4.2 我怎么访问别的Host
这个答案比较简单:只要我所在的Host能通的地方,我就也能与它连通。
你看主机上有一条:源地址NAT规则。
iptables -t nat –nL
意思是容器里面发出的报文,把源地址改成主机的,然后往外发。意思是跟主机一样往外发报文就完了(不理解的参见以前的NAT课程)。
4.3 别的Host上的容器怎么访问我
也就跨节点的2个容器怎么互相通信。一般是2种方式:
4.3.1 NAT端口映射。
即通过指定目标端口,穿到容器中。
根据4.2章节可知:容器-》目标 == 容器所在Host节点 –》目标。
根据4.1章节可知:访问目标容器 == 指定IP+Port
所以容器里面直接用:指定IP+Port访问目标容器就行了。
举例:
(1) 在192.168.1.9这台机器上启动一个Nginx容器:注意这里-p参数告诉Host,请将主机上面的80端口,作为进入我的NAT入口。
docker run -rm -p 80:80 nginx
(2) 然后咱们再另外找一台机器(与刚才192.168.1.9 这一台能连通)。
进入一个容器,然后跨节点访问刚才那个容器:
docker exec -it ea60d3290dd5 /bin/bash
curl -vvv 192.168.1.9:80
4.3.2 隧道网络打通所有容器。
这种就稍微复杂一点,就是让所有容器处于同一个局域网中。
隧道模式,实现方式基本是各显神通了。除了新版本Docker有自己的实现,各大厂商也都有不一样的实现,比如现在各种flannel,weave,calico等现实。
原理嘛,请参考早期的 隧道课程。(可以照着物理世界去考虑,好比为很多物理机里面的所有VM创建虚拟局域网类似)
- 点赞
- 收藏
- 关注作者
评论(0)