容器的网络默认与宿主机及其他容器都是相互隔离, 但同时我们也要考虑下面的一些问题, 比如:
上述的这些问题都需要我们对容器的网络进行合理的管理才能解决,这就体现出了容器网络管理的重要性。
Docker 容器网络
是为应用程序所创造的虚拟环境的一部分,它能让应用从宿主机操作系统的网络环境中独立出来,形成容器自有的网络设备、 IP 协议栈、端口套接字、 IP路由表、防火墙等等与网络相关的模块。
Docker 为实现容器网络,主要采用的架构由三部分组成:CNM
、 Libnetwork
和驱动
。
Docker 网络架构采用的设计规范是 CNM(Container Network Model)。 CNM 中规定了 Docker 网络的基础组成要素: Sandbox
、 Endpoint
、 Network
。
Sandbox
:提供了容器的虚拟网络栈,也即端口、套接字、 IP 路由表、防火墙、DNS 配置等内容。主要用于隔离容器网络与宿主机网络,形成了完全独立的容器网络环境。Network
: Docker 内部的虚拟子网,使得网络内的参与者能够进行通讯。Endpoint
:就是虚拟网络的接口,就像普通网络接口一样, Endpoint 的主要职责是负责创建连接。 Endpoint 类似于常见的网络适配器,那也就意味着一个 Endpoint 只能接入某一个网络, 当容器需要接入到多个网络,就需要多个 Endpoint。如上图所示,容器 B 有两个 Endpoint 并且分别接入 Networkd A 和 Network B。那么容器 A 和容器 B 之间是可以实现通信的,因为都接入了 NetworkA。但是容器 A 和容器 C 不可以通过容器 B 的两个 Endpoint 通信。
Libnetwork
是 CNM 的一个标准实现。 Libnetwork 是开源库,采用 Go 语言编写(跨平台的),也是 Docker 所使用的库, Docker 网络架构的核心代码都在这个库中。Libnetwork 实现了 CNM 中定义的全部三个组件,此外它还实现了本地服务发现、基于 Ingress 的容器负载均衡,以及网络控制层和管理层等功能。
驱动
主要负责实现数据层相关内容,例如网络的连通性和隔离性是由驱动来处理的。驱动通过实现特定网络类型的方式扩展了 Docker 网络栈,例如桥接网络和覆盖网络。
Docker 内置了若干驱动,通常被称作原生驱动或者本地驱动。例如 Bridge Driver、Host Driver、 Overlay Driver、 MacVLan Driver、 IPVLan Driver、 None Driver 等等。每个驱动负责创建其上所有网络资源的创建和管理。
bridge
网络host
网络container
网络none
网络overlay
网络另外,在 Docker 安装时,会自动安装一块 Docker 网卡称为 docker0
,它是一个网桥设备,主要用于 Docker 各容器及宿主机的网络通信。
docker network create [OPTIONS] NETWORK
-d, --driver
: 网络驱动--gateway
: 网关地址--subnet
: 表示网段的 CIDR 格式的子网--ipv6
: 启用 ipv6#创建自定义网络
docker network create mynet1 --subnet=192.168.0.0/16
#查看网络列表
docker network ls
#查看网络详细信息
docker network inspect mynet1
docker network inspect [OPTIONS] NETWORK [NETWORK...]
-f,--format
:指定格式#查看mynet1、mynet2网络详情
docker network inspect mynet1 mynet2
我们创建的容器默认使用的是桥接网络
docker network inspect bridge
docker network connect [OPTIONS] NETWORK CONTAINER
--ip
: 指定 IP 地址--ip6
: 指定 IPv6 地址#创建自定义网络mynet3
docker network create mynet3 --subnet=10.2.0.0/16
#运行一个容器busybox
docker run -dit --name busybox1 busybox:1.36.0
docker network connect mynet3 busybox1
docker network inspect mynet3
docker network disconnect [OPTIONS] NETWORK CONTAINER
-f
:强制退出docker network inspect mynet3
docker network disconnect mynet3 busybox1
docker exec -it busybox1 sh
docker network prune [OPTIONS]
-f, --force
: 不提示docker network prune
docker network rm NETWORK [NETWORK...]
-f
:强制退出docker network create mynet1
docker network create mynet2
docker network create mynet3
docker run -itd --name busybox2 busybox:1.36.0
docker network connect mynet3 busybox2
docker inspect mynet3
docker network rm mynet1 mynet2 mynet3
docker network ls [OPTIONS]
docker network list
-f, --filter
:指定过滤条件--format
:指定格式--no-trunc
:不截断-q, --quiet
:仅仅显示 id#返回名字为host的网络
docker network ls -f name=host
#以json形式返回网络列表
docker network ls --format json
#不截断返回列表
docker network ls --no-trunc
#仅仅返回网络id
docker network ls -q
docker network create mynet6 --subnet=10.15.0.0/16
docker run -itd --name busybox3 --network mynet6 busybox:1.36.0
docker inspect busybox3
docker inspect mynet6
docker run -itd --name busybox4 busybox:1.36.0
docker network connect mynet6 busybox4
Docker Bridge 网络采用内置的 bridge 驱动, bridge 驱动底层采用的是 Linux 内核中Linux bridge 技术。就网络而言, bridge 网络是在网络段之间转发流量的链路层设备,而网桥可以是在主机内核中运行的硬件设备或软件设备;就 Docker 而言,桥接网络使用软件网桥 docker0,它允许连接到同一网桥网络的容器进行通信,同时提供与未连接到该网桥网络容器的隔离。
Docker Container 的 bridge
桥接模式 可以参考下图:
默认情况下,创建的容器在没有使用 --network
参数指定要加入的 docker 网络时,默认都是加入 Docker 默认的单机桥接网络,即下面的 name 为 bridge
的网络。
默认的 bridge 网络会被映射到内核中为 docker0
的网桥上。Docker 默认的 bridge 网络和 Linux 内核中的 docker0 网桥是一一对应的关系。bridge 是 Docker 对网络的命名,而 docker0 是内核中网桥的名字。
生活案例
bridge 就像一个立交桥一样,有很多条路可以四通八达,每条路都连接了 2 个方向的通道。
#创建两个容器
docker run -itd --name b1 busybox:1.36.0
docker run -itd --name b2 busybox:1.36.0
#分别进入两个容器
docker exec -it b1 sh
docker exec -it b2 sh
在默认情况下, 我们创建的容器都会连接在 docker0 这个 bridge 上。那其实我们也可以创建一些自定义的 bridge,让运行的容器通过自定义 bridge 进行通信。
docker network create mynet4
docker run -itd --name b3 --network mynet4 busybox:1.36.0
docker run -itd --name b4 --network mynet4 busybox:1.36.0
Docker 自定义桥接网络是支持通过 Docker DNS 服务进行域名解析的, 也就是说我们可以直接使用容器名进行通信,因为 DNS 服务可以解析容器名到 IP 地址的映射, 但是默认的 bridge 网络是不支持 DNS 的。
docker run -itd --name b51 busybox:1.36.0
docker run -itd --name b52 busybox:1.36.0
因此,这里我们可以得出结论:默认的bridge网络不支持DNS域名解析,而自己创建的自定义bridge网络则支持。
-P
暴露所有端口,一种是-p
,暴露指定端口
-P
-p :
docker run -d --name mynginx1 -p 8060:80 nginx:1.24.0
docker port mynginx1
Docker 容器运行默认都会分配独立的 Network Namespace
隔离子系统, 但是如果基于 host 网络模式,容器将不会获得一个独立的 Network Namespace, 而是和宿主机共用同一个 Network Namespace,容器将不会虚拟出自己的网卡, IP 等,而是直接使用宿主机的 IP 和端口。
连接到 host 网络的容器共享宿主机的网络栈,容器的网络配置与宿主机完全一样。我们可以通过 --network=host
指定使用 host 网络。
docker run -itd --name b61 busybox:1.36.0
docker run -itd --name b62 --network host busybox:1.36.0
这里我们需要注意一下,host网络的缺点就是宿主机的端口如果被占用,那么容器将不能使用该端口。
docker run -d --name mynginx2 --network host nginx:1.24.0
#查看容器日志信息
docker logs mynginx2
Docker Container
的 other container 网络模式是 Docker 中一种较为特别的网络的模式。之所以称为“other container 模式”,是因为这个模式下的 Docker Container,会使用其他容器的网络环境。之所以称为“特别”,是因为这个模式下容器的网络隔离性会处于 bridge 桥接模式与 host 模式之间。 Docker Container 共享其他容器的网络环境,则至少这两个容器之间不存在网络隔离,而这两个容器又与宿主机以及除此之外其他的容器存在网络隔离。
Docker Container 的 other container 网络模式实现逻辑如下:
docker run -itd --name b71 busybox:1.36.0
docker run -itd --name b72 --network container:b71 busybox:1.36.0
在这种模式下的 Docker Container 可以通过 localhost 来访问 namespace 下的其他容器,传输效率较高。但是两个容器之间存在依赖,如果依赖容器重启了,会导致另外一个服务的网络不可用。
none 网络
就是指没有网络。挂在这个网络下的容器除了 lo(本地回环),没有其他任何网卡。
在运行容器的时候,可以通过 --network=none
参数来指定容器使用 none 网络。
docker run -itd --name b8 --network none busybox:1.36.0