一、前言

Docker作为目前最火的轻量级容器技术,有很多令人称道的功能,如Docker的镜像管理。然而,Docker同样有着很多不完善的地方,网络方面就是Docker比较薄弱的部分。因此,我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

我们在使用docker run创建Docker容器时,可以用--net选项指定容器的网络模式,Docker有以下4种网络模式:

  • host模式,使用--net=host指定。

容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。

  • container模式,使用--net=container:NAME_or_ID指定。

创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。

  • none模式,使用--net=none指定。

该模式关闭了容器的网络功能。

  • bridge模式,使用--net=bridge指定,默认设置。

此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。

注意:使用docker network ls命令列出这些docker内置的网络模式。

Docker 网络模型

二、host模式

众所周知,Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。

例如,我们在10.10.101.105/24的机器上用host模式启动一个含有web应用的Docker容器,监听tcp80端口。

当我们在容器中执行任何类似ifconfig命令查看网络环境时,看到的都是宿主机上的信息。而外界访问容器中的应用,则直接使用10.10.101.105:80即可,不用任何NAT转换,就如直接跑在宿主机中一样。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

下面关于网络命令空间的介绍来源:https://yq.aliyun.com/articles/53624

那么什么是网络名称空间?一般的说法是包括了Linux共享的一组网络接口和路由表条目的装置。您可以修改路由表条目使用策略路由。(这里有我写的介绍和可能的策略路由用例),但这并没有从根本上改变网络接口和路由表/条目共享整个操作系统。网络名字空间改变这一基本假设。通过网络名字空间,你能有不同并独立的网络接口和路由表,它们各自独立运作

这个概念通过一些例子来说明可能是最好的。沿途我会介绍一些新想法。首先,我需要提供一些假设。

假设

在这个例子中,我会使用Ubuntu Server 12.04. LTS.请注意不同的Linux发行版对网络名字空间支持上的不同。Ubuntu支持这个,但是RedHat不支持。(我不确定Fedora,如果你知道,可以在评论中说出来。)如果你想使用网络名字空间,请确保你的Linux发行版支持。

另外,我回假设你使用root账户运行,或者你会在必要的时候加上sudo来执行命令行。

创建和列出网络名字空间

创建一个网络名字空间是相当容易的。仅仅需要使用这个命令:

ip netns add <new namespace name>
打个比方,你想要创建一个名为“blue”的名字空间。你会使用这个命令: ip netns add blue
使用这个命令验证网络名字空间是否创建: ip netns list
你应该能看到你的网络名字空间被列出,你可以使用它们了。 给网络名字空间分配接口 创建网络名字空间仅仅是个开始,接下来的部分是给名字空间指定接口。然后为网络连接配置这些接口。有一个注意,就是在我之前探索网络名字空间的时候发现,你无法把物理接口分配给一个名字空间。到底怎样才呢个使用它们呢,然后呢? 原来你只能分配虚拟以太网接口(veth)到网络名称空间。虚拟以太网接口是一个有趣的结构。它总是一对一对的,他们像一个相连的管道——无论什么从其中一个veth接口进去,就会从另一个等同的接口出来。因此,您可以使用veth接口把一个网络名名字空间链接到存在物理接口的“默认”或“全局”网络名字空间。 让我们来看看这是如何实现的。首先,您要创建一对veth: ip link add veth0 type veth peer name veth1
我发现一些站点重复这个命令去创建veth1然后链接到veth0,但是我的测试表明,只要使用上面这个命令,会创建一对端口,并且自动建立连接。当然,你可以用其它名字代替veth0和veth1,如果你需要的话。 你可以使用这个命令验证veth对被创建。 ip link list
你应该看到一对veth接口(使用你在上面的命令中指定的名称)列出。现在它们都属于”默认”或“全局”名字空间,和物理接口一道。 假设你想把全局名字空间链接到blue名字空间。这样做,你需要移动一个veth接口道blue名字空间中,可以使用这个命令。 ip link set veth1 netns blue
如果你再次运行ip link list 命令,你会看到veth1接口从列表中消失了。现在它在blue名字空间中,因此你需要运行下面的命令来看。 ip netns exec blue ip link list
哇哦!这是一个有点复杂的命令,让我们慢慢讲: 在第一部分,ip nets exec,这是在不同网络名字空间执行命令的方法。
接下来是这个命令应该运行在的特定名称空间。(在这个例子中,是blue名字空间)
最后,你需要实际的命令在远程名字空间中执行。在这个例子中,你想要查看在blue名字空间的接口,因此你运行 ip link list。
当你运行那个命令,你就能看到一个回环接口和你刚才移入的veth1接口。 在网络名字空间配置接口 现在,veth1已经移动到蓝色的名称空间,我们需要去实际配置那个接口。再一次,我们会使用 ip netns exec 命令,这一次在blue名字空间中配置veth1接口。 ip netns exec blue ifconfig veth1 10.1.1.1/ up
和之前一样,这个命令的格式如下: ip netns exec <network namespace> <command to run against that namespace>
在这个例子里,你使用ifconfig给veth1接口指定了一个IP地址,并且开启了这个接口。(注解:你可以使用 ip addr , ip route ,以及 ip link 命令来完成相同的事情) 一旦veth1接口开启,你能仅仅通过一些不同的命令验证blue名字空间中的网络设置是完全隔离的。打个比方,让我们确定你的”全局”名字空间有物理接口在 172.16.1.0/ 范围,你的veth1接口在一个隔离的名字空间,并且分配了10.1.1./24范围。你可以使用这些命令验证网络名字空间是如何保证网络配置隔离的: ip addr list 在全局名字空间没有显示任何10.1.1./24有关的接口或者地址。
ip netns exec blue ip addr list 将仅仅显示10.1.1./24有关的接口和地址,也不会显示任何来自全局名字空间的接口或地址。
同样的,ip route list 在每个名称空间将显示不同的路由表条目,包括不同的默认网关。
链接网络名字空间到物理网络 这部分花了我一些时间。我没法解释为什么,但是它这样运作了。一旦我搞懂了,一旦我搞懂了,它是显而易见的。让网络名字空间链接到物理网络的就是使用网桥。在我的例子中,我是用一个Open vSwitch(OVS)桥,但是一个标准Linux网桥也能工作的很好。把一个或多个物理接口和veth接口一样放到网桥中,然后,啪,它们就能用了。当然,如果你有不同的名字空间,你可能想要/需要将它们连接到不同的物理网络或不同的vlan。

关于网络名称空间的一段介绍

三、container模式

在理解了host模式后,这个模式也就好理解了。这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。

联盟式容器是指使用某个已存在容器的网络接口的容器,接口被联盟内的各容器共享使用;因此,联盟式容器彼此间完全隔离,例如:
联盟式容器彼此虽然共享同一个网络名称空间,但其它名称空间如User、Mount等还是隔离的。
联盟式容器彼此间存在端口冲突的可能性,因此,通常只会在多个容器上的程序需要程序loopback接口互相通信,或对已存的容器的网络属性进行监控时才使用此模式的网络模型。

bridge模式:(默认没有设置网络模式工作在bridge模式),我们启动两个容器,两个容器之间互相隔离,并拥有自己的私有IP,并可以互相通信,等会会介绍:

docker run --name b1 -it --rm busybox

docker run --name b2 -it --rm busybox

container模式:

docker run --name b1 -it --rm busybox

docker run --name b2 -it --rm --network container:b1 busybox

此时我们在b2中使用ifconfig命令,可以看到b2与b1IP相同,彼此之间也可以通信,效果如同一个主机上的两个进程。

四、none模式

此模式下容器不参与网络通信,运行于此类容器中的进程仅能访问本地环回接口,仅适用于进程无须网络通信的场景中,例如备份,进程诊断及各种离线任务等。

--network none:设置模式容器工作在none模式下。
在此模式下使用ifconfig -a 显示只有lo网卡。

五、Bridge模式(默认网络模式)

桥接式容器一般拥有两个接口:一个环回接口和一个连接至主机上某桥设备的以太网接口,在上面的图片就可以看到。

docker daemon启动时默认会创建一个名为docker0的网络桥,docker0网卡扮演二层交换机与网卡设备,不给IP就是交换机,给了IP即可以当交换机也可以当网卡。

并且我们以后在此模式下创建的容器为桥接式容器,我们每次启动一个容器,就会为这个容器分配一对网卡设备,其中一个网卡在容器上,另外一个网卡在宿主机上,在宿主机上的网卡接口桥接至docker0。

--network bridge:设置容器工作在bridge模式下,即为将容器接口添加至docker0桥。
docker0桥为NAT桥,因此,桥接式容器可通过此桥接口访问外部网络,但防火墙规则阻止一切从外部网络访问桥接式容器的请求,当然也有解决办法,后面会介绍外部访问容器。

这里容器使用独立network Namespace,并连接到docker0虚拟网卡(默认模式)。通过docker0网桥以及Iptables nat表配置与宿主机通信;bridge模式是Docker默认的网络设置,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥上。

常用参数的用法

--name:设置容器名
docker run --name t1 -it busybox:latest --rm:退出容器即刻删除容器
docker run --name Nginx -it --network bridge --rm nginx --network:设置网络模式,默认bridge模式
docker run --name t1 -it --network bridge --rm busybox:latest --hostname:为容器设置指定主机名
docker run --name t1 -it --network bridge --hostname t1.magedu.com --rm busybox:latest
注意:使用hostname命令查看主机名 --dns:设置dns服务器
docker run --name t1 -it --network bridge --hostname t1.magedu.com --dns 114.114.114.114 --rm busybox:latest --dns-search:设置dns搜索域
docker run --name t1 -it --network bridge --hostname t1.magedu.com --dns 114.114.114.114 --dns-search ilinux.io --rm busybox:latest --add-host:在/etc/hosts文件中添加主机与ip的解析记录
docker run --name t1 -it --network bridge --hostname t1.magedu.com --dns 114.114.114.114 --dns-search ilinux.io --rm --add-host "docker.com:172.16.0.100" busybox:latest

六、 bridge模式的拓扑

当Docker server启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。接下来就要为容器分配IP了,Docker会从RFC1918所定义的私有IP网段中,选择一个和宿主机不同的IP地址和子网分配给docker0,连接到docker0的容器就从这个子网中选择一个未占用的IP使用。如一般Docker会使用172.17.0.0/16这个网段,并将172.17.42.1/16分配给docker0网桥(在主机上使用ifconfig命令是可以看到docker0的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)。单机环境下的网络拓扑如下,主机地址为10.10.101.105/24。

Docker完成以上网络配置的过程大致是这样的:

1. 在主机上创建一对虚拟网卡veth pair设备。veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备。

2. Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0。另一端放在主机中,以veth65f9这样类似的名字命名,并将这个网络设备加入到docker0网桥中,可以通过brctl show命令查看。

3. 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。

七、bridge模式下容器的通信

在bridge模式下,连在同一网桥上的容器可以相互通信(若出于安全考虑,也可以禁止它们之间通信,方法是在DOCKER_OPTS变量中设置–icc=false,这样只有使用–link才能使两个容器通信)。

Docker可以开启容器间通信(意味着默认配置--icc=true),也就是说,宿主机上的所有容器可以不受任何限制地相互通信,这可能导致拒绝服务攻击。进一步地,Docker可以通过--ip_forward和--iptables两个选项控制容器间、容器和外部世界的通信。

容器也可以与外部通信,我们看一下主机上的Iptable规则,可以看到这么一条(查看规则:iptables -t nat -vnL):

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

这条规则会将源地址为172.17.0.0/16的包(也就是从Docker容器产生的包),并且不是从docker0网卡发出的,进行源地址转换,转换成主机网卡的地址。这么说可能不太好理解,举一个例子说明一下。假设主机有一块网卡为eth0,IP地址为10.10.101.105/24,网关为10.10.101.254。从主机上一个IP为172.17.0.1/16的容器中ping百度(180.76.3.151)。IP包首先从容器发往自己的默认网关docker0,包到达docker0后,也就到达了主机上。然后会查询主机的路由表,发现包应该从主机的eth0发往主机的网关10.10.105.254/24。接着包会转发给eth0,并从eth0发出去(主机的ip_forward转发应该已经打开)。这时候,上面的Iptable规则就会起作用,对包做SNAT转换,将源地址换为eth0的地址。这样,在外界看来,这个包就是从10.10.101.105上发出来的,Docker容器对外是不可见的。

上面添加规则来实现外部访问略为麻烦,我们还有一种更好的方法,端口映射:
为docker run命令使用-p选项即可实现端口映射,无须手动添加规则

-p选项的使用格式
-p <containerPort>
---将指定的容器端口映射至主机所有地址的一个动态端口(随机端口)
-p <hostPort>:<containerPort>
---将容器端口<containerPort>映射至指定的主机端口<hostPort>
-p <ip>::<containerPort>
---将指定的容器端口<containerPort>映射至主机指定<ip>的动态端口
-p <ip>:<hostPort>:<containerPort>
---将指定的容器端口<containerPort>映射至主机指定<ip>的端口<hostPort>
"动态端口"指随机端口,具体的映射结果可使用docker port命令查看

那么,外面的机器是如何访问Docker容器的服务呢?我们首先用下面命令创建一个含有web应用的容器,将容器的80端口映射到主机的80端口。

docker run --name=nginx_bridge --net=bridge -p : -d nginx

然后查看Iptable规则的变化,发现多了这样一条规则:

-A DOCKER ! -i docker0 -p tcp -m tcp --dport  -j DNAT --to-destination 172.17.0.2:

此条规则就是对主机eth0收到的目的端口为80的tcp流量进行DNAT转换,将流量发往172.17.0.2:80,也就是我们上面创建的Docker容器。所以,外界只需访问10.10.101.105:80就可以访问到容器中的服务。

除此之外,我们还可以自定义Docker使用的IP地址、DNS等信息,甚至使用自己定义的网桥,但是其工作方式还是一样的。

参考:

https://www.cnblogs.com/zuxing/articles/8780661.html

https://yq.aliyun.com/articles/53624

https://www.cnblogs.com/jsonhc/p/7823286.html

docker 网络模式详解的更多相关文章

  1. Docker网络模式详解

    一.Docker四种工作模式 安装Docker时,它会自动创建三个网络,bridge(创建容器默认连接到此网络). none .hosthost:容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用 ...

  2. Docker 网络模式详解及容器间网络通信

    当项目大规模使用 Docker 时,容器通信的问题也就产生了.要解决容器通信问题,必须先了解很多关于网络的知识.Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜 ...

  3. Docker:网络模式详解

    Docker作为目前最火的轻量级容器技术,牛逼的功能,如Docker的镜像管理,不足的地方网络方面. Docker自身的4种网络工作方式,和一些自定义网络模式 安装Docker时,它会自动创建三个网络 ...

  4. docker 网络概述及网络模式详解

    docker 网络概述及网络模式详解 1.网络概述 2.网络模式详解 1.网络概述: Docker 网络实现原理 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0) ...

  5. Docker系列04—Docker的网络模式详解

    本文收录在容器技术学习系列文章总目录 1.Docker的四种网络模式 (1)docker四种网络模式如下: Bridge contauner   桥接式网络模式 Host(open) containe ...

  6. vmware虚拟机三种网络模式详解_转

    原文来自http://note.youdao.com/share/web/file.html?id=236896997b6ffbaa8e0d92eacd13abbf&type=note 由于L ...

  7. Vmware虚拟机三种网络模式详解

    原文来自http://note.youdao.com/share/web/file.html?id=236896997b6ffbaa8e0d92eacd13abbf&type=note 我怕链 ...

  8. 四、Vmware虚拟机三种网络模式详解

    转载自: http://note.youdao.com/share/web/file.html?id=236896997b6ffbaa8e0d92eacd13abbf&type=note 1. ...

  9. 【转】VMware虚拟机三种网络模式详解

    由于Linux目前很热门,越来越多的人在学习Linux,但是买一台服务放家里来学习,实在是很浪费.那么如何解决这个问题?虚拟机软件是很好的选择,常用的虚拟机软件有VMware Workstations ...

随机推荐

  1. 开机自动挂载ISO文件

    开机自动挂载ISO文件 Table of Contents 1. 概述 1.1. 通过fstab 1.2. 通过rc.local 1 概述 开机自动挂载ISO 文件有两种途径 .一种是通过配置fsta ...

  2. 排错:Unable to create a new session key. It is likely that the cache is unavailable.

    排错:Unable to create a new session key. It is likely that the cache is unavailable. 问题 登录openstack页面, ...

  3. mysql 如何给大表添加字段

    1. 能不加字段就不要加, 能不修改字段就不要修改, 能不删除字段就不要删除, 等等为什么要删除字段呢? 如果没事,不要蛋疼的找事. 实际上,我们那次更新失败后, 我们并没有增加那个字段, 然后我们一 ...

  4. pycharm建立django工程

    1.windows上安装了python 用pycharm建立django工程,必须要连接本地的python,也就是windows上的pyhton,不能连接linux上的pyhton,否则报错:plea ...

  5. 英特尔®oneAPI简介及动手实验研讨会召集令

    Intel Developer Zone 2019年超级计算大会英特尔正式发布了oneAPI软件行业计划及其beta产品,在上篇文章中我们已为您介绍了oneAPI的基本含义,本文将继续为您介绍oneA ...

  6. sqlalchemy 的操作

    使用PyMySQL的前提: 1. 先建好表 2. 自己动手需要手动去写多条SQL语句 改进: 类 ------>  表 实例化 -> 数据 这种思想叫:ORM(Object Relatio ...

  7. 条件DCGAN(2019/09/10)

    最近看到keras的官方GAN代码中有CGAN(全连接层)和卷积GAN(DCGAN),但他并没有给出“条件卷积GAN”,预测就把这两者结合了一下.虽然很多人用其他框架(e.g.TensorFlow)写 ...

  8. shell-常用命令,重定向和文件包含

    shell的知识点并不多,这里简单介绍一下常用的一些东西 常用命令 echo 显示普通字符串 echo "test" 显示转义字符 echo "\"test\& ...

  9. SpringBoot消息队列之-rabbitMQ

    一.概述 1.在大多应用中,我们系统之间需要进行异步通信,即异步消息. 2.异步消息中两个重要概念:消息代理(message broker)和目的地(destination) 当消息发送者发送消息以后 ...

  10. C++命名建议

    如果想要有效的管理一个稍微复杂一点的体系,针对其中事物的一套统一.带层次结构.清晰明了的命名准则就是必不可少而且非常好用的工具. 活跃在生物学.化学.军队.监狱.黑社会.恐怖组织等各个领域内的大量有识 ...