Docker网络详解

     当 Docker 启动时,会自动在主机上建立一个 docker0 虚拟网桥,其实是 Linux 的一个 bridge,能够理解为一个软件交换机。它会在挂载到它的网口之间进行转发。
     同时,Docker 随机分配一个本地未占用的私有网段(在 RFC1918 中定义)中的一个地址给 docker0 接口。好比典型的 172.17.42.1 ,掩码为 255.255.0.0 。此后启动的容器内的网口也会自动分配一个同一网段( 172.17.0.0/16 )的地址。
     当建立一个 Docker 容器的时候,同时会建立了一对 veth pair 接口(当数据包发送到一个接口时,另一个接口也能够收到相同的数据包)。这对接口一端在容器内,即 eth0 ;另外一端在本地并被挂载到docker0 网桥,名称以 veth 开头(例如 vethAQI2QT )。经过这种方式,主机能够跟容器通讯,容器之间也能够相互通讯。Docker 就建立了在主机和全部容器之间一个虚拟共享网络。

 

 
 
配置 DNS

     Docker 没有为每一个容器专门定制镜像,那么怎么自定义配置容器的主机名和 DNS 配置呢? 秘诀就是它利用虚拟文件来挂载到来容器的 3 个相关配置文件。
在容器中使用 mount 命令能够看到挂载信息:
 
$ mount
...
/dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ...
/dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ...
tmpfs on /etc/resolv.conf type tmpfs ...
...
     这种机制可让宿主主机 DNS 信息发生更新后,全部 Docker 容器的 dns 配置经过 /etc/resolv.conf 文件马上获得更新。
 
若是用户想要手动指定容器的配置,能够利用下面的选项。
      -h HOSTNAME or --hostname=HOSTNAME 设定容器的主机名,它会被写到容器内的 /etc/hostname 和 /etc/hosts 。但它在容器外部看不到,既不会在 docker ps 中显示,也不会在其余的容器的 /etc/hosts 看到。
     --link=CONTAINER_NAME:ALIAS 选项会在建立容器的时候,添加一个其余容器的主机名到 /etc/hosts 文件中,让新容器的进程可使用主机名 ALIAS 就能够链接它。
     --dns=IP_ADDRESS 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析全部不在 /etc/hosts 中的主机名。
     --dns-search=DOMAIN 设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的 主机时,DNS 不只搜索host,还会搜索 host.example.com 。 注意:若是没有上述最后 2 个选项, Docker 会默认用主机上的 /etc/resolv.conf 来配置容器。
 
 
容器访问控制

     容器的访问控制,主要经过 Linux 上的 iptables 防火墙来进行管理和实现。 iptables 是 Linux 上默认的防火墙软件,在大部分发行版中都自带。
 
容器访问外部网
     容器要想 访问 外部网 ,须要本地系 转发 支持。在 Linux 中, 检查转发 是否打开。
 
[root@master ~]# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
  若是为 0,说明没有开启转发,则须要手动打开。
   
  $sysctl -w net.ipv4.ip_forward=1
 
 
容器之间访问

容器之间相互访问,须要两方面的支持
  • 容器的网络拓扑是否已经互联。默认状况下,全部容器都会被链接到 docker0 网桥上。
  • 本地系统的防火墙软件 -- iptables 是否容许经过。
 
访问全部端口
     当启动 Docker 服务时候,默认会添加一条转发策略到 iptables 的 FORWARD 链上。策略为经过( ACCEPT )仍是禁止( DROP )取决于配置 --icc=true (缺省值)仍是 --icc=false 。固然,若是手 动指定 --iptables=false 则不会添加 iptables 规则。
     可见,默认状况下,不一样容器之间是容许网络互通的。若是为了安全考虑,能够在 /etc/default/docker文件中配置 DOCKER_OPTS=--icc=false 来禁止它
访问指定端口
     在经过 -icc=false 关闭网络访问后,还能够经过 --link=CONTAINER_NAME:ALIAS 选项来访问容器的开 放端口。
例如,在启动 Docker 服务时,能够同时使用 icc=false --iptables=true 参数来关闭容许相互的网络 访问,并让 Docker 能够修改系统中的 iptables 规则。
此时,系统中的 iptables 规则多是相似
 
$ sudo iptables -nL
...
Chain FORWARD (policy ACCEPT)
target prot opt source destination
DROP all -- 0.0.0.0/0 0.0.0.0/0
...

    以后,启动容器( docker run )时使用 --link=CONTAINER_NAME:ALIAS 选项。Docker 会在 iptable 中为 两个容器分别添加一条 ACCEPT 规则,容许相互访问开放的端口(取决于 Dockerfile 中的 EXPOSE 行)。docker

     当添加了 --link=CONTAINER_NAME:ALIAS 选项后,添加了 iptables 规则
 
$ sudo iptables -nL
...
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 172.17.0.2 172.17.0.3 tcp spt:80
ACCEPT tcp -- 172.17.0.3 172.17.0.2 tcp dpt:80
DROP all -- 0.0.0.0/0 0.0.0.0/0

 

     注意: --link=CONTAINER_NAME:ALIAS 中的 CONTAINER_NAME 目前必须是 Docker 分配的名字,或使用 --name 参数指定的名字。主机名则不会被识别
 
 
映射容器端口到宿主主机的实现

 
容器访问外部实现
 
     容器全部到外部网络的链接,源地址都会被NAT成本地系统的IP地址。这是使用 iptables 的源地址假装 操做实现的。
查看主机的 NAT 规则。
 
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0
......

 

其中,上述规则将全部源地址在 172.17.0.0/16 网段,目标地址为其余网段(外部网络)的流量动态伪 装为从系统网卡发出。MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址.
 
外部访问容器实现
 
     容器容许外部访问,能够在 docker run 时候经过 -p 或 -P 参数来启用。 无论用那种办法,其实也是在本地的 iptable 的 nat 表中添加相应的规则。
使用 -p80:80 时:
 
Chain DOCKER (2 references)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:80 to:172.17.0.15:80
使用 -P 时:
 
$ iptables -t nat -nL
Chain DOCKER (2 references)
target prot opt source destination
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49153 to:172.17.0.2

 

 
端口映射实现
     IP:host_port:container_port 或 -p IP::port 来指定容许访问容器的主机上的 IP、接口等,以制 定更严格的规则。
     若是但愿永久绑定到某个固定的 IP 地址,能够在 Docker 配置文件 /etc/default/docker 中指定 DOCKER_OPTS="--ip=IP_ADDRESS" ,以后重启 Docker 服务便可生效。
 
 
配置 docker0

     Docker 服务默认会建立一个 docker0 网桥(其上有一个 docker0 内部接口),它在内核层连通了其余 的物理或虚拟网卡,这就将全部容器和本地主机都放到同一个物理网络。
     Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间能够经过网桥相互通讯,它还给出了 MTU(接口容许接收的最大传输单元),一般是 1500 Bytes,或宿主主机网络路由上支持的默认值。这些值均可以在服务启动的时候进行配置。
  • --bip=CIDR -- IP 地址加掩码格式,例如 192.168.1.5/24
  • --mtu=BYTES -- 覆盖默认的 Docker mtu 配置
也能够在配置文件中配置 DOCKER_OPTS,而后重启服务。 因为目前 Docker 网桥是 Linux 网桥,用户可 以使用 brctl show 来查看网桥和端口链接信息。
 
[root@master ~]# brctl show
bridge name    bridge id        STP enabled    interfaces
docker0        8000.56847afe9799    no        veth6278b4d
                            veth9321eba
                            vethc12c3b4
                            vethe54ad11

     每次建立一个新容器的时候,Docker 从可用的地址段中选择一个空闲的 IP 地址分配给容器的 eth0 端口。 使用本地主机上 docker0 接口的 IP 做为全部容器的默认网关.安全

 
自定

     除了默认的 docker0 网桥,用户也能够指定网桥来链接各个容器。 在启动 Docker 服务的时候,使用 -b BRIDGE 或 --bridge=BRIDGE 来指定使用的网桥。
若是服务已经运行,那须要先中止服务,并删除旧的网桥。
$ sudo service docker stop
$ sudo ip link set dev docker0 down
$ sudo brctl delbr docker0
而后建立一个网桥 bridge0
 
$ sudo brctl addbr bridge0
$ sudo ip addr add 192.168.5.1/24 dev bridge0
$ sudo ip link set dev bridge0 up
查看确认网桥建立并启动
 
ip addr show bridge0
4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default
link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff
inet 192.168.5.1/24 scope global bridge0
valid_lft forever preferred_lft forever

 

  配置 Docker ,默 认桥 接到 建的网
 
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker
$ sudo service docker start

     启动 Docker 服务。 新建一个容器,能够看到它已经桥接到了 bridge0 上。 能够继续用 brctl show 命令查看桥接的信息。另外,在容器中可使用 ip addr 和 ip route 命令来 查看 IP 地址配置和路由信息。服务器

相关文章
相关标签/搜索