大量的互联网应用服务包括多个服务组件,这往往需要多个容器之间通过网络通信进行相互配合。

一、网络基础

        在了解Docker的网络之前,必须先认识Docker所依赖的几个linux技术,这对理解docker的网络有帮助。

        Docker的网络实现其实就是利用了 Linux上的网络命名空间和虚拟网络设备(特别是veth pair)。熟悉这两部分的基本概念,可以有助于理解 Docker网络的实现过程。

1.命名空间

        Linux Namespaces机制提供一种资源隔离方案。PID,IPC,Network等系统资源不再是全局性的,而是属于特定的Namespace。每个Namespace里面的资源对其他Namespace都不可见。

        一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器“通常”会分配一个独立的Network Namespace。这样每个docker容器就好像拥有了一套独立的网络环境,甚至以为自己霸占了全部的主机,也许这也是使人们经常认为容器就是虚机的原因之一吧。

现在我们就来演示一下:

1.1我们先运行两个busybox容器:

docker run -d --name test1 busybox /bin/sh -c "while true; do sleep 3600; done"

docker run -d --name test2 busybox /bin/sh -c "while true; do sleep 3600; done"

1.2 查看2个容器网络

docker exec -it test1 ip adocker exec -it test2 ip a


我们可以看到test1和test2是两个不同的网络环境。

1.3添加namespace

ip netns add test1ip netns add test2

1.4查看本机的namespace

ip netns exec test1 ip aip netns exec test2 ip a


namespace默认是DOWN的状态

2.Veth设备对

        Veth设备对可以在不同的网络命名空间之间通信,用他们可以连接两个网络命名空间。一对veth设备就像网线的两头一样。

1.把namespace变成up状态

ip netns exec test1 ip link set dev lo up

状态变成了 unknown,为什么是unknown呢,因为当前的test1没有被连通。

2.创建并查看link

ip link add veth-test1 type veth peer name veth-test2 查看linkip link

3.添加veth-test1 到namespace

ip link set veth-test1 netns test1

4.添加并查看veth-test2

ip link set veth-test2 netns test2ip netns exec test2 ip link

3.网桥

        简单来说,桥接就是把一台机器上的若干个网络接口“连接”起来。其结果是,其中一个网口收到的报文会被复制给其他网口并发送出去。以使得网口之间的报文能够互相转发。类似交换机。

        linux内核支持网口的桥接与交换机有一点点不同不同,交换机只是一个二层设备,对于接收到的报文,要么转发、要么丢弃。而运行着linux内核的机器本身就是一台主机,有可能就是网络报文的目的地。其收到的报文除了转发和丢弃,还可能被送到网络协议栈的上层(网络层),从而被自己消化。

        在docker启动时,会在主机上创建一个docker0网桥。通过docker0在同一个主机上的容器之间都可以通信,外部的消息也可以经过docker0进入容器。

1.为test1和test2分配IP地址

ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1ip netns exec test2 ip addr add 192.168.1.1/24 dev veth-test2

2.link并启动

ip netns exec test1 ip link set dev veth-test1 upip netns exec test2 ip link set dev veth-test2 up

3.两个namespace可以ping通了

ip netns exec test1 ping 192.168.1.2

二、网络创建过程

        Docker创建一个容器的时候,会具体执行如下操作:

  • 创建一对虚拟接口,分别放到本地主机和新容器的命名空间中。
  • 本地主机一端的虚拟接口连接到默认的 docker0网桥或指定网桥上,并具有一个以veth开头的唯一名字,如veth1234。
  • 容器一端的虚拟接口将放到新创建的容器中,并修改名字作为eth0。这个接口只在容器的命名空间可见。
  • 从网桥可用地址段中获取一个空闲地址分配给容器的eth0(例如172.17.0.2/16),并配置默认路由网关为 docker网卡的内部接口 docker的IP地址(例如172.17.42./16)。

        完成这些之后,容器就可以使用它所能看到的eth0虚拟网卡来连接其他容器和访问外部网络。

三、端口映射

        在启动容器的时候,如果不指定对应参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。
        当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-P或-p参数来指定端口映射。当使用-P标记时, Docker会随机映射一个

我们先演示下没有映射端口的情况:
1.启动一个nginx容器

docker run --name web -d nginx

2.查看桥接网络状态

docker network inspect bridge


获得IP:172.17.0.4

  1. 在容器内访问

curl http://172.17.0.4

  1. 在容器外访问

curl http://172.17.0.4


访问被拒绝

现在我们添加端口演示:
1.先停止并删除容器

docker stop webdocker rm web

2.重新创建容器,并指定端口映射

docker run --name web -d -p 80:80 nginx

3.再来测试外部访问,为了能更好的感受到,我们使用浏览器访问

四、默认网络


安装Docker时,它会自动创建三个网络:bridge NetWork(桥接网络)、Host NetWork (主机网络)、None NetWork (无网络)

这三个网络都是用于单机。

        这三个网络内置于Docker中。运行容器时,可以使用 --network或者-- net标志指定容器应连接到的网络。

        bridge网络代表docker0所有Docker安装中存在的网络。除非你使用该docker run --network=<NETWORK>选项指定,否则Docker守护程序默认将容器连接到此网络。。

        我们可以使用docker network inspect <net> 来查看某个网络信息。

例:docker network inspect bridge

五、Docker网络模式

Docker有以下4种网络模式:

  • Bridge模式:使用–net=bridge指定,默认设置;
  • Host模式:使用–net=host指定;
  • Container模式:使用–net=container:NAME_or_ID指定;
  • None模式:使用–net=none指定。

你可以使用以docker network ls命令列出这些网络:

1.Bridge

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

在Bridge模式下:

  • 主机上面会有一个docker0的网桥;
  • 每个容器都与docker0连通,所以同主机上的容器之间也连通;
  • 每个主机上容器的地址都是从172.17.0.2开始往后分。

安装brctl

yum -y install brige-utils

查看本机的veth

brctl show

2.Host

        相当于Vmware中的桥接模式,与宿主机在同一个网络中,但没有独立IP地址。如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。

3.None

        在这种模式下,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。以下情况下是有用的:容器并不需要网络。

4.Container

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