0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

精通Docker网络:Bridge驱动深度解析

马哥Linux运维 来源:cnblogs 2024-03-31 15:58 次阅读

dokcer0 网桥

在 Ubuntn 上安装 docker 后,宿主机上默认被创建了一个名为 docker0 的网卡,其 IP 为 172.17.0.1/16:

5c788c4e-eea3-11ee-a297-92fbcf53809c.png

有了这个网卡,宿主机还会在内核的路由表中添加一条到达相应网络的静态路由记录:

5c87ca74-eea3-11ee-a297-92fbcf53809c.png

这条路由信息表示所有目的 IP 为 172.17.0.0/16 的数据包都会从 docker0 网卡发出。接下来我们创建一个名为 mycon 的容器,并观察其网络配置:

5c960cba-eea3-11ee-a297-92fbcf53809c.png

在 mycon 容器内可以看到两块网卡:lo 和 eth0。其中 lo 是容器的回环网卡,eth0 是容器与外界通信的网卡,eth0 的 IP 信息为 172.17.0.2/16,和宿主机上的网卡 bridge0 在同一网段中。查看 mycon 的路由信息:

5ca8cc06-eea3-11ee-a297-92fbcf53809c.png

mycon 容器的默认网关正是宿主机的 docker0 网卡。通过 ping 命令测试与外网的连通性,此时容器 mycon 是可以连通外网的,这就说明 mycon 的 eth0 网卡与宿主机的 docker0 网卡是连通的。

下面我们来查看宿主机的网络设备:

5cb6c766-eea3-11ee-a297-92fbcf53809c.png

发现多了一个以 "veth" 开头的网卡,这是一个 veth 设备。而 veth 设备总是成对出现的,那么与 veth7537a16 配对的就应该是 mycon 容器中的 eth0 了。既然 mycon 容器中的 eth0 是与 docker0 连通的,那么 veth7537a16 也应该是与 docker0 连通的。因此docker0 并不是一个简单的网卡设备,而是一个网桥!下图展示了 docker bridge 网络模式的拓扑图:

5cd3f322-eea3-11ee-a297-92fbcf53809c.png

事实上,docker 创建了 docker0 网桥,并以 veth pair 连接各个容器的网络,容器中的数据通过 eth0 发送到 docker0 网桥上,并由 docker0 网桥完成转发。这里网桥的概念等同于交换机,为连在其上的设备转发数据帧。网桥上的 veth 网卡设备相当于交换机上的端口,可以将多个容器连接在它们上面,这些端口工作在二层,所以是不需要配置 IP 信息的。上图中的 docker0 网桥就为连在其上的容器转发数据帧,使得同一台宿主机上的 docker 容器之间可以相互通信。既然 docker0 是二层设备,那么它为什么还需要 IP 呢?其实,docker0 是一个普通的 linux 网桥,是可以为它配置 IP 的,我们可以认为它的内部有一个可以用于配置 IP 的网卡。Docker0 的 IP 地址作为所连接的容器的默认网关地址

docker0 网桥是在 docker daemon 启动时自动创建的,其默认 IP 为 172.17.0.1/16,之后通过 bridge 驱动创建的容器都会在 docker0 的子网范围内选取一个未占用的 IP 使用,并连接到 docker0 网桥上。Docker daemon 提供了如下参数可以帮助用户自定义 docker0 的设置。

--bip=CIDR:设置 docker0 的 IP 地址和子网范围,使用 CIDR 格式,如 192.168.1.0/24。这个参数仅仅是配置 docker0 的,对用户自定义的网桥无效。

--fixed-cidr=CIDR:限制 docker 容器可以获取的 IP 地址范围。Docker 容器默认可以获取的 IP 范围为 docker 网桥的整个子网范围,此参数可以将其缩小到某个子网范围内,所以这个参数必须在 docker 网桥的子网范围内。

--mtu=BYTES:指定 docker0 网桥的最大传输单元(MTU)。

除了使用 docker0 网桥外,用户还可以使用自定义的网桥,然后通过 --bridge=BRIDGE 参数传递给 docker daemon。比如我们可以创建一个自定义网桥 br0:

$ sudo ip link add name br0 type bridge
$ sudo ifconfig br0 188.18.0.1

5cdf794a-eea3-11ee-a297-92fbcf53809c.png

然后在启动 docker daemon 时设置参数 --bridge=br0 即可。

iptables 规则

在安装 docker 时,会默认在宿主机中添加一些 iptables 规则,用于 docker 容器之间已经容器与外界的通信。我们可以通过 iptables-save 命令查看到 nat 表上 POSTROUTING 链上的有这么一条规则:

-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
这条规则关系着 docker 容器与外界的通信,其含义是将不是从网卡 docker0 发出的且源地址为 172.17.0.0/16 的数据包(容器中发出的数据包)做 SNAT。这样一来,从 docker 容器中访问外网的流量,在外部看来就是从宿主机上发出的,外部感觉不到 docker 容器的存在。

当外界想要访问 docker 容器运行的服务时该怎么办呢?接下来我们将启动一个简单的 web 服务器:

$ docker run -d -p 3000:3000 --name=myweb ljfpower/nodedemo
然后观察 iptables 规则的变化:
$ sudo iptables-save
…
*nat
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 3000 -j DNAT --to-destination 172.17.0.3:3000
…
*filter
-A DOCKER -d 172.17.0.3/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 3000 -j ACCEPT
…

可以看到,在 nat 表和 filter 表中的 DOCKER 链中分别增加来一条规则,这两条规则将访问宿主机 3000 端口的请求转发到 172.17.0.3 的 3000 端口上(提供服务的 docker 容器的 IP 和端口),所以外界访问 docker 容器是通过 iptables 做 DNAT 实现的。

Docker 默认的 forward 规则允许所有的外部 IP 访问容器,我们可以通过在 filter 的 DOCKER 链上添加规则来对外部的 IP 访问做出限制,比如只允许源 IP 为 192.168.21.212(笔者是在局域网内演示的)的数据包访问容器,添加的规则如下:

$ sudo iptables -I DOCKER -i docker0 ! -s 192.168.21.212 -j DROP

不仅仅是与外界通信,docker 容器之间相互通信也受到 iptables 规则的限制。同一台宿主机上的 docker 容器默认都连在 docker0 网桥上,它们属于同一个子网,这是满足通信的第一步。同时,docker daemon 会在 filter 表的 FORWARD 链中增加一条 ACCEPT 的规则(--icc=true):
-A FORWARD -i docker0 -o docker0 -j ACCEPT
这是满足容器间相互通信的第二步。当 docker daemon 的启动参数 -icc(icc 参数表示是否允许容器间相互通信) 设置为 false 时,上面的规则被设置为 DROP,容器间的相互通信就被禁止了,这时如果想让两个容器通信就需要在 docker run 命令中使用 --link 选项。

在 docker 容器和外界的通信过程中,还涉及了数据包在多个网卡之间的转发(比如从 docker0 网卡到宿主机 eth0 网卡),这需要内核将 ip forward 功能打开,就是把内核参数 ip_forward 设置为 1。Docker daemon 在启动的时候会执行这个操作,我们可以通过下面的命令进行检查:

$ cat /proc/sys/net/ipv4/ip_forward


5cef6170-eea3-11ee-a297-92fbcf53809c.png

返回的结果为 1,表示内核的 ip forward 功能已经打开。

容器的 DNS 和主机名(hostname)

使用同一个 docker 镜像可以创建很多个 docker 容器,但是这些容器的 hostname 并不相同,也就是说 hostname 并没有被写入到镜像中。实际上容器中的 /etc 目录下有 3 个文件是在容器启动后被虚拟文件覆盖掉的,分别是 /etc/hostname、/etc/hosts 和 /etc/resolv.conf,通过在容器中运行 mount 命令可以看到它们:

# mount
…
/dev/mapper/ubuntu--vg-root on /etc/resolv.conf type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/mapper/ubuntu--vg-root on /etc/hostname type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/mapper/ubuntu--vg-root on /etc/hosts type ext4 (rw,relatime,errors=remount-ro,data=ordered)
…

这种方式既能解决主机名的问题,同时也能让 DNS 及时更新(改变 resolv.conf)。由于这些文件的维护方法会随着 docker 版本的升级而不断变化,所以尽量不要修改这些文件,而是通过 docker 提供的相关参数进行设置,其参数配置方式如下。

-h HOSTNAME 或者 --hostname=HOSTNAME:设置容器的 hostname,此名称会写入到 /etc/hostname 和 /etc/hosts 文件中,也可以在容器的 bash 提示符中看到。

--dns=IP_ADDRESS…:为容器配置 DNS,会被写入到 /etc/resolv.conf 文件中。

这两个参数都是针对容器的需要在创建容器时进行设置。比如下面的 demo:

$ docker run -it --name mycon -h lion --dns=8.8.8.8 ubuntu:14.04


5cfcecf0-eea3-11ee-a297-92fbcf53809c.png

总结

本文主要通过演示 docker0 网桥相关的功能来探索 docker 网络中的 bridge 驱动的实现机制。从本文中不难看出,linux 系统中,docker 的 bridge 驱动是依赖于系统的 ip forward 以及 iptables 等核心功能的。因此在学习 docker 的过程中,适当的补充 linux 相关的知识也是十分必要的!

审核编辑:黄飞

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 网桥
    +关注

    关注

    0

    文章

    130

    浏览量

    16972
  • 容器
    +关注

    关注

    0

    文章

    495

    浏览量

    22061
  • Bridge
    +关注

    关注

    0

    文章

    15

    浏览量

    11894
  • Docker
    +关注

    关注

    0

    文章

    458

    浏览量

    11854

原文标题:拿捏Docker 网络 bridge 驱动

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Docker网络选型和日志监控选型

    Docker容器化网络和日志的选型和落地
    发表于 05-06 07:58

    docker的四种网络模式

    docker网络模式
    发表于 10-16 08:11

    解析深度学习:卷积神经网络原理与视觉实践

    解析深度学习:卷积神经网络原理与视觉实践
    发表于 06-14 22:21

    AUTOSAR架构深度解析 精选资料推荐

    AUTOSAR架构深度解析本文转载于:AUTOSAR架构深度解析目录AUTOSAR架构深度解析A
    发表于 07-28 07:40

    AUTOSAR架构深度解析 精选资料分享

    AUTOSAR架构深度解析本文转载于:AUTOSAR架构深度解析AUTOSAR的分层式设计,用于支持完整的软件和硬件模块的独立性(Independence),中间RTE(Runtime
    发表于 07-28 07:02

    C语言深度解析

    C语言深度解析,本资料来源于网络,对C语言的学习有很大的帮助,有着较为深刻的解析,可能会对读者有一定的帮助。
    发表于 09-28 07:00

    Docker五种存储驱动原理详解

    问题,在Docker 0.7版本中引入了存储驱动, 目前,Docker支持AUFS、Btrfs、Device mapper、OverlayFS、ZFS五种存储驱动
    发表于 05-13 10:33 2708次阅读
    <b class='flag-5'>Docker</b>五种存储<b class='flag-5'>驱动</b>原理详解

    docker存储驱动的工作原理

    Docker的存储驱动官方有介绍其工作原理,这里只是简单概括一下。Docker使用了层的概念,docker在构建镜像的时候,会逐行执行我们的Dockerfile中的每一行,每执行一行的
    的头像 发表于 06-26 11:49 4588次阅读

    嵌入式Linux与物联网软件开发C语言内核深度解析书籍的介绍

    嵌入式Linux与物联网软件开发——C语言内核深度解析 C语言是嵌入式Linux领域的主要开发语言。对于学习嵌入式、单片机、Linux驱动开发等技术来说,C语言是必须要过的一关。C语言学习的特点是入门容易、深入理解难、
    发表于 05-15 18:10 9次下载
    嵌入式Linux与物联网软件开发C语言内核<b class='flag-5'>深度</b><b class='flag-5'>解析</b>书籍的介绍

    详解docker的四种网络模式

    使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息,
    的头像 发表于 01-21 09:21 6620次阅读

    docker的4种网络模式

    Docker 使用 Linux 桥接,在宿主机虚拟一个 Docker 容器网桥(docker0),Docker 启动一个容器时会根据 Docker
    的头像 发表于 08-14 11:50 1826次阅读

    Docker容器的四种网络模式

    Docker 在安装后自动提供 3 种网络,可以使用 docker network ls 命令查看。
    的头像 发表于 10-17 14:53 1648次阅读

    Docker容器网络的数据链路是什么

    单主机容器网络可能存在多个docker,分属于不同的bridge,它们之间有通信的需求。
    的头像 发表于 02-15 09:56 899次阅读
    <b class='flag-5'>Docker</b>容器<b class='flag-5'>网络</b>的数据链路是什么

    docker常用基础命令

    作为嵌入式开发工程师,需要用到的docker命令基础解析与使用。
    发表于 09-18 17:54 2次下载

    Docker网络的基本概念和原理与用法

    桥接网络Bridge Network):这是 Docker 容器默认使用的网络类型。每个独立的容器都会连接到一个内部网络的私有网桥。
    发表于 03-18 12:26 758次阅读
    <b class='flag-5'>Docker</b><b class='flag-5'>网络</b>的基本概念和原理与用法