docker 指定网卡_Docker网络实现

我们来详细观察&理解Docker容器是如何实现它的网络的,以及解析一个容器是如何与本机、本机中的容器、其他Host、其他Host中的容器等场景下分别进行通信的。

本机容器网络大概生成过程:

  • 首先每个容器对应创建一个network namespace;

  • 然后将所有的容器的network namespace连接到Bridge网桥(docker0)上,使得容器间互相处于一个局域网内,方便连通。

Docker的网络命名空间

docker使用namespace实现容器网络,但是我们使用ip netns命令却无法在主机上看到任何network namespace,这是因为默认docker把创建的网络命名空间链接文件隐藏起来了。

有2种进入这个“空间”的命令。

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

58437d32293d6ed404b476a8e588eeb9.png

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

78677bb3db250971588d0ed3143ef793.png

2、通过 nsenter

找到容器里app的主pid。

docker inspect ecf8689d3297

833f2d16cb6340d0f9ea622f8ebe86bc.png

跑到这个pid对应的世界(namespace)里去。

nsenter -n -t 25977

这个时候,就是在容器里面的网络空间角度敲命令啦。

例如:

1)查询网卡:

ifconfig

23116323524ff08f5237aac23d8ddbb8.png

(2)抓包:

tcpdump -i eth0 -n

b62af4310e6e66de4a73f9c0fd0e480f.png

Docker 使用的Linux Bridge

关于Docker为什么要加个Bridge来连通所有的容器?其实不加Bridge,网络也能通。只是说有了Bridge,就有了覆盖更多复杂场景的能力。

这里直接引用Docker自己的描述:通过Bridge,可以使得连到这个Bridge的容器互相通信;同时和没有连到这个Bridge的容器保持网络隔离。(大意就是:容器可以按网络分组)

7ff6aa9f85ba18155b88b4e1179ef184.png

我怎么和本机Host主机通信

假设我就是那个Docker容器,那么我是如何与主机Host通信的呢。

1、本机Host怎么访问我

主机Host访问自己节点上的容器,答案是直接访问就行了。

咱们先来看Host主机的路由表:

8082675b805ed44120518c7c04eafbe6.png

因为根据路由信息:所有发往Docker容器的地址(即目标为 172.17.* )的报文,---> 统统走给 ---> docker0 网卡。而根据上面Bridge章节可以知道,这个docker0就是Bridge网桥,它是连着所有容器的Veth网线的。所以这个报文会发送到所有容器里面,那么目标容器就会应答你。

e9511b43ab47d6a4b65843677d39c4ac.png

2、我怎么访问所在的Host主机

容器访问自己的Host主机,答案也是直接访问。

Docker容器里面,网络很简单,就一个eth0。所以你往外发报文,都是经过eth0网卡。而这个网卡是一个veth网线的一头,所以这个报文就会到达Bridge网桥(即docker0)。而这个网桥就是Host主机的一个网卡,所以就到达了目的地。

dad9f9fa4eef49c9657aa9cc49e90460.png

3、本机其他机器怎么访问我

大家都通过docker0这个Bridge焊在一起,所以 直接互访就行了。

我怎么和别的Host主机通信

别的Host主机,就是“爸爸(所在节点)的兄弟”。

1、别的Host怎么访问我

跨节点访问容器时,由于不知道目标容器是住在哪台Host主机上(要访问那个容器,必须经过它所在的Host),所以为了访问一个目标容器专门设置一条路由规则(当我访问xxx容器时,请经过yyy虚拟机,这种规则),并不方便。所以一般直接用端口映射来访问。  

即:目标容器所在的Host主机IP + 指定端口。然后当报文到达指定目标的Host主机时,通过指定端口Nat进入容器。

2e86944f4b19871ff8f33bd2bf0f9b43.png

举例:

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

7b4e0f5dd51d4419cb0d6f708389d3b5.png

这里可以看到,主机跨节点访问容器时,必须通过指定端口NAT进入到目标容器。

6fd2e84f7d17ba680c3630dc4e4403a8.png

直接访问IP是不通的(没有路由信息)

2、我怎么访问别的Host

这个答案比较简单:只要我所在的Host能通的地方,我就也能与它连通。

6e1a2ab5fca0d05b559ebb4c97b3efde.png

你看主机上有一条:源地址NAT规则。

iptables -t nat –nL

意思是容器里面发出的报文,把源地址改成主机的,然后往外发。意思是跟主机一样往外发报文就完了。

78677bb3db250971588d0ed3143ef793.png

3、别的Host上的容器怎么访问我

也就跨节点的2个容器怎么互相通信。一般是2种方式:

1)NAT端口映射

即通过指定目标端口,穿到容器中。

根据上面章节可知:容器-》目标  == 容器所在Host节点 –》目标。

根据上面章节又可知:访问目标容器 == 指定IP+Port

所以容器里面直接用:指定IP+Port访问目标容器就行了。

举例:

A. 在192.168.1.9这台机器上启动一个Nginx容器:注意这里-p参数告诉Host,请将主机上面的80端口,作为进入我的NAT入口。

docker run -rm  -p 80:80 nginx

然后咱们再另外找一台机器(与刚才192.168.1.9 这一台能连通)。

进入一个容器,跨节点访问刚才的容器:

docker exec -it ea60d3290dd5 /bin/bash

curl -vvv 192.168.1.9:80

4d7283af36b4602a586080bb3a0d5c59.png

2)隧道网络打通所有容器

这种就稍微复杂一点,让所有容器处于同一个局域网中。

隧道模式,实现方式基本是各显神通了。除了新版本Docker有自己的实现,各大厂商也都有不一样的实现,比如现在各种flannel,weave,calico等现实。

1ce8aa2afe7b9b6e56d4d86777e21229.png

END

搭载鲲鹏920处理器

提供更高性能、易获取、易运维的算力平台

点击

b067a8c39ebddeb6a153d03652b2654d.png 827f2de941bb6f1430bb924e1aeee31d.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值