Docker容器与容器云 - 网络基础学习总结

很多人可能在项目中已经使用docker很长时间,但是却很少有人知道docker的网络是如何实现的。我应该就算是很多人中的一个。

开始前有一点需要注意的是:如果你现在正使用的是docker for mac,建议你还是在mac上安装vagrant,然后使用vagrant开启一台linux虚拟机,然后在这台虚拟机上安装docker for linux。这样我们的学习环境也更加的贴近生产环境。

docker0网桥

当在一台未经特殊网络配置的ubuntu机器上安装完docker之后,在宿主机上通过使用ifconfig命令可以看到多了一块名为docker0的网卡:

vagrant@vagrant-ubuntu-trusty-64:~$ ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:b6:12:b7:33
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:b6ff:fe12:b733/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:45 errors:0 dropped:0 overruns:0 frame:0
          TX packets:18 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:3044 (3.0 KB)  TX bytes:1460 (1.4 KB)

eth0      Link encap:Ethernet  HWaddr 08:00:27:36:92:90
          inet addr:10.0.2.15  Bcast:10.0.2.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe36:9290/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:503098 errors:0 dropped:0 overruns:0 frame:0
          TX packets:236748 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:397962985 (397.9 MB)  TX bytes:14862746 (14.8 MB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

可以看到此docker0网卡的IP为172.17.0.1/16。有了这样一块网卡,宿主机也会在内核路由表上添加一条到达相应网络的静态路由,可以通过route -n查看。

vagrant@vagrant-ubuntu-trusty-64:~$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.0.2.2        0.0.0.0         UG    0      0        0 eth0
10.0.2.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0

当一宿主机要发送数据时,它会查自己的内核路由表,找到一条最精确匹配目标主机IP地址的路由来转发数据。

我们知道,同一网段内发送数据是不需要经过网关的,而不同网段之间发送数据必需经过网关。

我们的宿主机有三张网卡:

lo(127.0.0.1),本机回环网卡;

eth0(10.0.2.15)在10.0.2.0/24网段;

docker0(172.17.0.1)在172.17.0.0/16网段;

假如:

  • Destination IP是10.0.2.13,则会匹配到第二条路由。即所有目的IP为10.0.2.0/24网络的数据包从eth0网卡发出。Gateway为0.0.0.0表示不经过网关,这个很好理解,因为同一网段内发送数据不需要经过网关。

  • Destination IP是172.17.0.3,则会匹配到第三条路由。即所有目的IP为172.17.0.0/16网络的数据包从docker0网卡发出。

  • Destination IP是其它,比如32.10.2.0,则会匹配到第一条路由:默认路由。即数据包从eth0发出,而发往外网的数据包需要经过网关转发,所发配置了Gateway为10.0.2.2

现在使用docker run创建一个docker容器。

sudo docker run -it --name myubuntu ubuntu /bin/bash

然后在容器中执行ifconfig,如果你发现你的容器中没有ifconfig命令,可以执行以下命令安装net-tools:

root@bde36ed1f506:/# apt-get update

root@bde36ed1f506:/# apt-get install net-tools

// 顺带也把iputils-ping装了
root@bde36ed1f506:/# apt-get install iputils-ping

然后再执行ifconfig

root@bde36ed1f506:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:02
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11218 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11128 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:24859036 (24.8 MB)  TX bytes:606400 (606.4 KB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

在myubuntu容器中有两块网卡:eth0和lo。eth0为容器与外界通信的网卡。而且eth0(172.17.0.2)与宿主机中的docker0(172.17.0.1)在同一个网段。

现在我们查看myubuntu的路由表:

root@bde36ed1f506:/# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

可以发现myubuntu的默认网关正是宿主机的docker0网卡。我们刚才install了那么多package说明容器是可以访问到外网的,说明容器的eth0与宿主机的docker0网卡是互通的。

现在我们回到宿主机的console,执行ifconfig

vagrant@vagrant-ubuntu-trusty-64:~$ ifconfig

...
vethee89fa0 Link encap:Ethernet  HWaddr 36:32:c3:bf:5e:78
          inet6 addr: fe80::3432:c3ff:febf:5e78/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11330 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11422 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:619186 (619.1 KB)  TX bytes:26177038 (26.1 MB)

会发现有一块以"veth"开头的网卡,如上:vethee89fa0。我们可以猜测这块网卡是veth设备,而veth pair总是成对出现的,很多人可能不知道veth设备是什么。

veth pair是用于不同network namespace间进行通信的方式,veth pair将一个network namespace数据发往另一个network namespace的veth。

如下:

如果多个network namespace需要进行通信,则需要借助bridge:

想知道更多>>

现在我们知道, veth pair通常用来连接两个network namespace,那么另一个应该就是docker容器中的eth0了。之前我们已经知道myubuntu容器的eth0和宿主机的docker0是相连的,那么vethee89fa0也应该是与docker0相连的。那么,现在来看docker0就不只是一个简单的网卡设备了,而是一个网桥。

真实情况正是如此,下图即为docker默认网络模式(bridge模式)下的网络环境拓扑图:

我们在宿主机上安将docker时会添加一个docker0的网卡,当我们使用docker run创建一个容器,并且没有指定网络模式的时候,会使用默认网络模式,创建出一个docker0网桥,并以veth pair连接各容器的网络,容器中的数据通过docker0网桥转发到宿主机的eth0网卡上。

在linux中,可以使用brctl命令查看和管理网桥(需要安装bridge-utils软件包),如查看本机上的linux网桥以及其上的端口:

vagrant@vagrant-ubuntu-trusty-64:~$ sudo brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242b612b733 no vethee89fa0

如果我再使用docker run再创建一个docker容器后再查看linux网桥以及其上的端口:

vagrant@vagrant-ubuntu-trusty-64:~$ sudo brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242b612b733 no vethee89fa0
veth0c3e53a

会发现又多了一双veth pair连接到了docker0网桥。

现在我们再来看这个网桥,我们会觉得它就像是一个交换机,为连在其上的设备转发数据帧。网桥上的veth网卡设备相当于交换机上的端口,可以将多个容器或虚拟机连接在其上,这些端口工作在二层,所以是不需要配置IP信息的。图中docker0网桥变为连在其上的容器转发数据帧,使得同一台宿主机上的docker容器之间可以相互通信。也许你应该已经注意到docker0既然是二层设备,其上怎么也配置了IP呢? docker0是普通的Linux网桥,它是可以在上面配置IP的,可以认为其内部有一个可以用于配置IP信息的网卡接口。那么为什么要为它配置IP呢?在Docker的桥接网络模式中,docker0的IP地址作为连接于之上的容器的默认网关存在

iptables规则

Docker安装完成后,默认会在宿主机上增加一些iptables规则,以用于docker容器和容器之间以及和外界有通信,可以使用iptables-save命令查看规则。

vagrant@vagrant-ubuntu-trusty-64:~$ sudo iptables-save
# Generated by iptables-save v1.4.21 on Sun Jun 18 08:24:03 2017
*nat
:PREROUTING ACCEPT [4:1276]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [480:28821]
:POSTROUTING ACCEPT [480:28821]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 172.17.0.3/32 -d 172.17.0.3/32 -p tcp -m tcp --dport 3306 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 3306 -j DNAT --to-destination 172.17.0.3:3306
COMMIT
# Completed on Sun Jun 18 08:24:03 2017
# Generated by iptables-save v1.4.21 on Sun Jun 18 08:24:03 2017
*filter
:INPUT ACCEPT [2374:4027249]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [1986:129221]
:DOCKER - [0:0]
:DOCKER-ISOLATION - [0:0]
-A FORWARD -j DOCKER-ISOLATION
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 172.17.0.3/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 3306 -j ACCEPT
-A DOCKER-ISOLATION -j RETURN
COMMIT
# Completed on Sun Jun 18 08:24:03 2017

可以看到nat表上的POSTROUTING链有这么一条规则:

-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

这条规则关系着docker容器和外界的通信,含义是将源地址为172.17.0.0/16的数据包(即Docker容器发出的数据),当不是从docker0网卡发出时做SNAT(源地址转换,将IP包的数据地址替换为相应网卡的地址)。这样一来,从Docker容器访问外网的流量,在外部看来就是从宿主机上发出的,外部感觉不到Docker容器的存在。

在iptables中可以灵活的做各种网络地址换(NAT),我想很多人可能不是太了解NAT(Network address translation)。

网络地址转换主要有两种: SNAT(source NAT)和DNAT(destination NAT)。

SNAT,即源地址目标转换。比如,多个PC机使用ADSL路由器共享上网。每个PC机都配置了内网IP,PC机访问外部网络的时候,路由器将数据包的报头中的源地址替换成路由器的IP,当外部网络的服务器,比如,网站web服务器接到访问请求的时候,他的日志记录下来的是路由器的IP地址,而不是PC机的内网IP。

这是因为,这个服务器收到的数据包的报头里边的源地址已经被换了,所以叫做SNAT,基于源地址的地址转换。

DNAT,即目标地址转换。典型的应用是,有个web服务器放在内网,前端有个防火墙配置公网IP。互联网上的访问者使用公网IP来访问这个网站。当访问的时候,客户端发出一个数据包,这个数据包的报头里边,目标地址写的是防火墙的公网IP。防火墙会把这个数据包的报头改写一次,将目标地址改写成web服务器的内网IP,然后再把这个数据包发送到内网的web服务器上。

MASQUERADE,地址伪装,在iptables中有着和SNAT相近的效果,但也有一些区别。

使用SNAT的时候,即可以NAT成一地址也可以NAT成多个地址,但是,对于SNAT,不管是几个地址,必须明确的指定要SNAT的IP。假如当前系统用的是ADSL动态拨号方式,那么每次拨号,出口IP都会改变,这个时候如果按照现在的方式来配置iptables就会出现问题。因为每次拨号后,服务器地址都会变化,而iptables规则内的ip是不会随着自动变化的。每次地址变化后都必须手工修改一次iptables,把规则里边的固定IP改成新的IP,这样很不方便。

MASQUERADE就是针对这种场景而设计的,他的作用是,从服务器的网卡上,自动获取当前IP地址来做NAT。

比如下边的命令:

iptables -t nat -A POSTROUTING -s 10.8.0.0/255.255.255.0 -o eth0 -j MASQUERADE

如此配置的话,不用指定SNAT的目标IP了。不管现在eth0的出口获得了怎样的动态IP,MASQUERADE会自动读取eth0现在的IP地址然后做SNAT。这样就很好的实现了动态SNAT地址转换。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • 转载自 http://blog.opskumu.com/docker.html 一、Docker 简介 Docke...
    极客圈阅读 10,473评论 0 120
  • 本文整理了在实践过程中使用的Linux网络工具,这些工具提供的功能非常强大,我们平时使用的只是冰山一角,比如lso...
    老夫刘某阅读 3,502评论 0 7
  • 关于docker网络模式有四种,内容如下,至于内容从来哪的,我也不知道,反正网上找的 前言:我们在使用docker...
    撸大师阅读 12,967评论 3 9
  • 五、Docker 端口映射 无论如何,这些 ip 是基于本地系统的并且容器的端口非本地主机是访问不到的。此外,除了...
    R_X阅读 1,738评论 0 7
  • 概述 自从docker容器出现以来,容器的网络通信就一直是大家关注的焦点,也是生产环境的迫切需求。而容器的网络通信...
    糙老爷们儿吃什么樱桃阅读 3,611评论 1 5