Docker 网络简介
Docker 网络为容器提供了强大的通信能力,实现了容器间以及容器与外部网络的连接。不同的网络模式为各种应用场景提供了灵活的解决方案。
Docker 网络在现代容器化技术中起着至关重要的作用。它就像是容器世界中的交通枢纽,确保各个容器能够高效地进行通信,同时也能与外部网络建立连接。
不同的网络模式为各种应用场景提供了灵活的解决方案。比如,默认的桥接网络模式适用于单机部署的容器,它为容器提供了一个相对独立的网络环境,同时又能通过虚拟网桥实现容器间的通信。在该模式中,Docker 守护进程创建了一个虚拟以太网桥 docker0,新建的容器会自动桥接到这个接口,实现容器间的通信以及与外部网络的交互。
此外,还有主机网络模式、无网络模式和容器网络模式等。主机网络模式下,容器共享宿主机的网络命名空间,性能较高但网络隔离性较差。无网络模式则完全禁用网络功能,适用于特定的开发场景。容器网络模式可以让新创建的容器与一个已运行的容器共享网络栈,实现高效快速通信。
总的来说,Docker 网络的多种模式为开发者和运维人员提供了丰富的选择,能够满足不同应用场景下的通信需求。
主要网络模式
- Bridge 模式
Bridge 模式是 Docker 的默认网络模式,为容器分配独立 IP 地址,通过虚拟网桥连接到宿主机,容器间可通过 IP 地址或容器名通信。优点是简单易用,适合大多数场景;缺点是跨主机通信需额外配置,网络性能可能受影响。
Docker 的网络子系统是可插拔驱动式的,默认存在或支持多种网络接口,其中 bridge 模式是默认的网络模式。如果不指定类型,新建的网络类型就是 bridge 模式。在这种模式下,bridge 模式会为每一个容器分配一个 Network Namespace、IP 等,并将容器的网络连接到一个网桥(docker0)上。
同一个宿主机上所有容器默认会在同一个网段(默认网段:172.17.0.0/16)下,且相互之间可以通信以及访问外部网络(前提是宿主机可以访问外部网络)。网桥就是在多个网段之间转发流量的链路层设备,可以是运行在主机内核中的软件或者硬件设备。Docker 使用的是软件网桥,允许连接在同一网桥的容器间进行通信,同时提供与未连接到网桥网络的容器进行隔离。Docker 网桥会自动设置相关规则(用 iptables),不同网桥上的容器不能直接相互通信。网桥适用于在同一个 Docker 守护程下的容器。对于在不同 Docker 守护进程下运行的容器之间的通信,可以在宿主机上添加路由,也可以使用 overlay 网络。
当启动 Docker daemon 时,会自动创建默认的网桥网络(docker0)并且还会启动 iptables 来设置访问规则。用户可以创建用户自定义的网桥网络,用户自定义的网桥网络优于默认的网桥(docker0),具有以下特点:
用户自定义的网桥在容器化应用程序之间提供了更好的隔离性和互操作性。连接在同一网桥下的容器同属一个网络,因此所有端口可以互访,但对外部网络是不公开的,这使得容器化应用程序可以轻松地相互通信,同时提高了安全性。例如一个带有 web 前端和后端,另外还有数据库的应用架构(用户 <—>web 入口 <—> 后端应用 <—> 数据库)。外部网络只需要访问 web 前端(如 80 端口),但只有后端应用需要访问数据库。若使用用户自定义的网桥,只需要对外开放 web 端口,数据库不需要对外开放任何端口,前后端都可以通过用户自定义的网桥来访问数据库。
用户自定义的网桥提供了容器之间的自动 DNS 解析。在默认网桥上创建的容器,相互访问时只能通过 IP 地址,除非使用 --link 选项,但 --link 是需要在容器的两个方向上创建,对于需要通信的两个以上的容器,这会变得复杂。而在用户自定义的网桥网络上,容器间可以通过名称或别名相互解析。在使用物理主机或者 VM 主机时,应用程序的配置文件中一般用 hosts 中的主机名称或者 IP,而现在在容器中,使用自定义网络,只要改写成容器名就好了,不需要太关注主机名称或者 IP。
使用用户自定义网桥的容器,支持随时断开或连接到不同的(用户自定义)网络。在容器的生命周期中,可以动态切换容器间的网络连接,比如创建了自定义 my-net01 和 my-net02 桥接网络,这两个网络中的容器可以互相动态切换的。如果是通过默认网桥创建的容器,也可以切换到自定义网桥中,而不必删除容器重建。
每个用户自定义的网络都是创建了一个可配置的网桥。如果所有容器都使用默认网桥网络,虽说可以修改配置,但所有容器都使用相同的设置,例如 MTU 和 iptables 规则。此外,配置默认网桥网络需要重启 Docker 进程。若是使用 docker network create 创建和配置用户自定义的网桥网络。如果不同的应用程序组有不同的网络需求,则可以在创建每个用户定义的网桥时分别对其进行配置。
使用默认网桥的容器之间可共享环境变量。起初,在两个容器之间共享环境变量的唯一方法是使用 --link。这种类型的变量共享在用户自定义的网络中是不可能的。然而,现在却有更好的方法来共享环境变量。(1)多个容器可以使用 Docker 的卷 (Volume) 来装载包含共享信息的文件或目录。(2)多个容器可以使用 docker compose 来一起启动,compose 文件中可以定义共享变量。(3)可以使用 swarm 服务来代替独立的容器,并共享密钥和配置。
管理自定义网桥网络:
使用 docker network ls 查看默认支持网络:
docker network ls
NETWORK ID NAME DRIVER SCOPE
e22a6ab223fe bridge bridge local
15b417347346 host host local
5926c0bd11d0 none null local
使用 docker network create 创建自定义网桥网络:
docker network create my-web-net01
docker network ls
NETWORK ID NAME DRIVER SCOPE
e22a6ab223fe bridge bridge local
15b417347346 host host local
899362727b48 my-web-net01 bridge local
5926c0bd11d0 none null local
可以看到,我们并没有指定 --driver=bridge 来创建,因为默认就是 bridge 模式,当然,也可以指定自定义网桥的子网、IP 范围、网关和其他项,例如:
docker network create --driver=bridge --subnet=172.23.10.0/24 my-web-net02
或者再细化一点
docker network create \\
--driver=bridge \\
--subnet=172.24.0.0/16 \\
--ip-range=172.24.10.0/24 \\
--gateway=172.24.10.254 \\
my-web-net03
删除自定义网桥网络:
docker network ls
NETWORK ID NAME DRIVER SCOPE
e22a6ab223fe bridge bridge local
15b417347346 host host local
899362727b48 my-web-net01 bridge local
49352768c5dd my-web-net02 bridge local
7e29b5afd1be my-web-net03 bridge local
5926c0bd11d0 none null local
docker network rm my-web-net01
或者指量删除
- Host 模式
Host 模式下容器共享宿主机网络栈,网络性能高,容器可直接使用宿主机端口,但安全性低,端口冲突风险增加。
Host 模式下容器与主机共享同一个网络命名空间,容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace,容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样。可以通过 --network=host 指定使用 host 网络。
在容器中可以看到 host 的所有网卡,并且连 hostname 也是 host 的。直接使用 Docker host 的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择 host 网络。当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host 上已经使用的端口就不能再用了。Docker host 的另一个用途是让容器可以直接配置 host 网路。比如某些跨 host 的网络解决方案,其本身也是以容器方式运行的,这些方案需要对网络进行配置,比如管理 iptables 等。 - None 模式
None 模式下容器无网络接口,不可进行网络通信,适用于需要完全隔离的环境,减少网络攻击面。
在 none 模式下的容器具有独立的网络命名空间,但不包含任何网络配置,只能通过 Local Loopback 网卡进行通信,即容器只能使用 localhost 或者 127.0.0.1。None 模式具有最少的网络模式,需要手动进行网络的配置,例如使用 pipwork 指定容器的 IP 地址等。
Docker none 网络模式下,虽然 Docker 容器拥有自己的 Network Namespace,但是 Docker 容器不会进行任何网络配置,即:Docker 容器没有网卡,IP 地址等信息,只有 lo 回环网络。由于这种类型的网络没有办法联网,所以封闭的网络能很好的保证 Docker 容器的安全性。 - Overlay 模式
Overlay 模式用于跨主机的容器网络,支持微服务架构,提供网络隔离,但配置和管理相对复杂,性能可能受影响。
Overlay 网络模式,在多个 docker daemon 主机之间创建一个分布式的网络,该网络(overlay)位于 docker 主机层次之上,允许容器(同一集群服务的容器)之间加密通讯,因此,docker 需要处理每一个主机(docker daemon)和每个分布的容器之间的包路由。
每当初始化一个集群或者添加一个 docker 主机到集群时,则在该主机上创建两个网络,一个称为覆盖网络的 ingress,该网络处理集群服务间的控制和数据信息。当创建一个集群服务、但未指定用户自定义网络时,该服务上的节点默认连接到 ingress 网络。一个桥接网络(docker_gwbridge),该网络连接单个主机的守护进程(docker daemon)与其他主机的守护进程,参与集群服务。
覆盖网络(overlay network)的创建,与用户自定义网络(used-defined nework)创建方式一致,采用指令 docker network create. 服务和容器,可同时连接多个网络,服务或者容器他们之间通讯的通讯前提是,他们都连接在同一个网络上。
docker network create -d overlay my-overlay
尽管我们可以使用覆盖网络(overlay network)连接集群服务的容器,和单个独立的容器,但是,针对这两种不同的容器,默认的行为和配置关注点是不同的。
创建覆盖网络(overlay network)的之前,必须调用 docker swarm init 将当前的 docker 主机初始化成一个管理结点,或者将当前主机通过 docker swarm join 添加到一个已存在的集群中,上述两操作都会使得集群服务默认创建覆盖网络 ingress. 即使不从不打算使用集群服务,他们都会默认执行这些操作(默认创建一个覆盖网络 ingress)。后续,我们可用创建自动定义的覆盖网络。
查看当前网络:
[root@localhost hadoop]# docker network ls
NETWORK ID NAME DRIVER SCOPE
722e7f4ef7f3 bridge bridge local
44f25836fb69 docker_gwbridge bridge local
168341f8d4c7 host host local
ijcf9vo1wn50 ingress overlay swarm
39aff7551ffa my-net bridge local
5f7c097a7d11 none null local
[root@localhost hadoop]#
- Macvlan 模式
Macvlan 模式允许容器拥有独立 MAC 地址,直接连接到物理网络,提供更好的网络性能和灵活配置,但配置复杂,可能有兼容性问题。
一些程序,特别是应用程序或者网络流量监控程序,期望直接连接到物理网络,这种情况下,可使用 Macvlan 网络模式,给每个容器的虚拟网络接口配置一个 mac 地址,使得连接容器,看起来是直接到一个物理主机上。这种情况下,需要在主机上为 macvlan 驱动,指定一个物理接口,一起子网与默认网关,甚至使用不同的物理网络接口,隔离 navlan 网络。
Macvlan 网络驱动程序提供了三种模式:bridge、passthru 和 host。
Bridge 模式(默认模式):在这种模式下,Macvlan 创建一个新的虚拟网络接口,并与宿主机的物理网络接口(通常是以太网接口)连接到一个 Linux 网桥上。容器将通过这个虚拟网络接口与宿主机和其他物理设备进行通信。
Passthru 模式:在这种模式下,Macvlan 直接将容器连接到宿主机上的物理网络接口上,而不需要使用网桥。容器将直接使用宿主机的 MAC 地址,并与其他物理设备在同一网络上进行通信。这种模式可能需要一些额外的网络配置,如 VLAN 的设置。
Host 模式:在这种模式下,Macvlan 将容器直接连接到宿主机的物理网络接口上,但容器将获得一个独立的 MAC 地址。容器可以与其他物理设备进行通信,但与宿主机共享相同的网络接口。这种模式通常用于需要直接访问宿主机网络的特殊情况,例如网络嗅探。
使用 Macvlan 网络驱动程序创建容器时,你可以指定以下参数:
--driver macvlan:指定使用 Macvlan 网络驱动程序。
--subnet=<subnet>:指定容器的子网,即容器将分配的 IP 地址所属的子网。
--gateway=<gateway>:指定容器的网关,即容器将使用的默认网关。
--ip-range=<range>:指定容器 IP 地址的范围,即容器可以分配的 IP 地址范围。
--mac-address=<mac>:指定容器的 MAC 地址。
下面是使用 Macvlan 网络驱动程序创建容器的示例命令:
docker network create -d macvlan \\
--subnet=192.168.1.0/24 \\
--gateway=192.168.1.1 \\
--ip-range=192.168.1.128/25 \\
-o parent=<physical_interface> \\
mymacvlan123456
然后,你可以通过将容器连接到 Macvlan 网络来创建容器:
docker run -d --net=mymacvlan --ip=<container_ip> --mac-address=<container_mac> <image>
网络实战案例
1、Bridge 模式案例
通过创建一个 Web 应用容器,展示 Bridge 模式下容器的 IP 分配和通信方式,以及端口映射到宿主机的过程。
首先,我们创建一个基于 Nginx 的 Web 应用容器,命令如下:
docker run --name my_web_app -d nginx
查看容器的 IP 分配情况可以使用 docker inspect 命令。通过 docker network inspect bridge 可以查看 Bridge 模式下的网络详细信息,其中包括容器的 IP 地址等信息。
假设容器分配到的 IP 地址为 172.17.0.2。
为了使外部能够访问这个 Web 应用容器,我们进行端口映射,使用 -p 参数。例如,将容器的 80 端口映射到宿主机的 8080 端口,命令如下:
docker run --name my_web_app -d -p 8080:80 nginx
这样,外部可以通过访问 http://localhost:8080 来访问容器中的 Web 应用。
2. 多个容器通信案例
创建自定义网络,连接 Web 服务器容器和数据库容器,展示容器间在同一网络下的通信能力。
首先创建一个自定义网络,命令如下:
docker network create my_custom_network
启动一个数据库容器并连接到自定义网络,假设使用 MySQL 数据库,命令如下:
docker run --name my_database --network my_custom_network -e MYSQL_ROOT_PASSWORD=root -d mysql
再启动一个 Web 服务器容器并连接到同一自定义网络,例如使用 Nginx,命令如下:
docker run --name my_web_server --network my_custom_network -d nginx
在这个自定义网络下,Web 服务器容器和数据库容器可以通过容器名称进行通信。比如在 Web 服务器的配置文件中,可以将数据库连接地址设置为 my_database(容器名),Docker 会自动进行 DNS 解析,实现容器间的通信。
3. docker link 设置网络别名案例
通过启动两个 Nginx 容器,使用 --link 参数设置网络别名,展示即使容器 IP 变化也能通过别名通信的功能。
首先启动一个 Nginx 容器并命名为 nginx1,命令如下:
docker run --name nginx1 -itd nginx:v1 /bin/bash
然后启动另一个 Nginx 容器 nginx2,并使用 --link 参数设置网络别名,命令如下:
docker run --name nginx2 -itd --link=nginx1:webtest nginx:v1 /bin/bash
当容器 nginx1 的 IP 发生变化时,容器 nginx2 仍然可以通过别名 webtest 来访问 nginx1。例如,在容器 nginx2 中执行 ping webtest,可以成功与 nginx1 进行通信。
Docker 网络的优势
轻量级快速,启动速度快,资源消耗低。
Docker 网络的轻量级特性使其启动速度非常快,相比传统的网络配置方式,它能够在短时间内为容器建立网络连接,大大减少了启动时间。同时,由于其资源消耗低,不会过多占用系统资源,使得系统能够更高效地运行其他任务。
跨平台,支持不同操作系统。
Docker 网络具有强大的跨平台能力,无论是 Windows、Linux 还是 macOS 等不同操作系统,都能很好地支持。这使得开发者可以在不同的平台上进行开发和部署,而无需担心网络配置的差异。例如,通过 Dockerfile 和镜像的使用,可以在不同平台上快速构建和运行相同的容器化应用,网络配置也能保持一致。
隔离性好,容器间相互独立。
Docker 网络为容器提供了良好的隔离性。每个容器都有自己独立的网络空间,容器之间相互独立,互不干扰。这不仅保证了容器内应用的安全性,还避免了不同容器之间的网络冲突。例如,在一个复杂的应用系统中,可能有多个不同的服务运行在不同的容器中,通过 Docker 网络的隔离性,可以确保每个服务都能独立运行,不受其他服务的影响。
易于管理,操作便捷。
Docker 网络的管理非常简单便捷。通过一系列的命令和工具,如 docker network 命令,可以轻松地创建、查看、删除网络,以及连接和断开容器与网络。同时,Docker 还提供了自动的 DNS 解析功能,使得容器之间的通信更加方便。例如,在创建自定义网络时,可以通过简单的命令指定子网、网关等参数,快速搭建适合特定应用场景的网络环境。
可移植性强,保证应用一致性。
Docker 网络的可移植性非常强。一旦在一个环境中配置好了容器的网络,就可以很容易地将这个配置移植到其他环境中,保证了应用在不同环境中的一致性。这对于持续集成和持续部署(CI/CD)流程非常重要,能够确保应用在不同阶段的开发、测试和生产环境中都能以相同的方式运行。例如,使用 Docker 镜像和容器,可以在不同的服务器或云平台上快速部署应用,网络配置也能保持一致。
五、Docker 网络的发展趋势
- 与 CI/CD 结合
Docker 与持续集成和持续部署流程结合,提高软件交付速度和质量。
随着 DevOps 文化的普及,Docker 与 CI/CD 流程的结合越发紧密。使用 Docker,开发人员可以将应用程序和其所有依赖项打包在一个镜像中,然后在 CI/CD 流程中自动构建和部署这个镜像。例如,在使用 Jenkins 作为 CI/CD 服务器时,可以配置一个 Jenkins Job,从 Git 仓库获取代码,使用 Dockerfile 构建镜像,使用 Docker 运行容器并执行测试,将测试结果报告到 Jenkins dashboard。如果测试通过,则将镜像推送到 Docker Hub。这样的结合使得软件开发的各个阶段能够更加快速和连贯,消除了 “在我机器上能运行” 的问题,极大地提升了软件交付速度和质量。 - 容器原生存储和网络解决方案需求增加
随着容器化应用增多,对更好性能、可扩展性和安全性的存储和网络解决方案需求增长。
随着容器化应用的不断增多,对容器原生存储和网络解决方案的需求也在日益增长。例如,OpenEBS、Portworx 等容器原生存储解决方案以及 Cilium、Calico 等网络解决方案应运而生。这些技术旨在提供更好的性能、更高的可扩展性和更强的安全性,特别是在大规模部署和复杂网络环境中。它们能够满足容器化应用对存储和网络的特殊需求,确保应用的稳定运行和高效性能。 - 与无服务器架构集成
Docker 可与无服务器平台集成,部署无服务器应用。
无服务器计算和容器技术密切相关,尤其是在运行短暂任务和微服务时。Docker 可以与无服务器平台(如 AWS Lambda、Google Cloud Functions 等)集成,使开发者能够以容器为基础,部署无服务器应用。在这种模式下,开发者无需管理底层服务器,只需关注代码和应用本身。例如,通过使用 Jenkins、Docker 和 CI/CD 构建无服务器应用程序,可以在 Docker 容器中运行 Jenkins pipelines,并用 pipelines 将无服务器应用程序部署到 AWS。这样的集成模式为开发者提供了更加便捷的开发和部署方式,提高了开发效率。 - 在多云和混合云环境中应用广泛
容器的可移植性使其在不同云提供商之间迁移应用更易。
容器的可移植性是其一大优势,使得应用在不同云提供商之间的迁移更加容易。无论是在公有云、私有云还是混合云环境中,Docker 容器都能够轻松运行。例如,在多云环境下,企业可以根据不同的业务需求和成本考虑,选择不同的云服务提供商,而 Docker 容器化的应用可以在不同的云平台上快速部署和运行,无需担心底层基础设施的差异。这种灵活性为企业提供了更多的选择和更好的成本效益。 - 与微服务架构相辅相成
为微服务提供理想运行环境,简化部署、扩展和管理。
Docker 与微服务架构相辅相成。微服务架构将应用程序拆分成多个小型、独立的服务,每个服务都可以独立部署和扩展。而 Docker 容器化技术为微服务提供了理想的运行环境,通过将每个微服务打包成一个独立的容器,可以实现快速部署、扩展和管理。例如,使用 Docker Compose 可以轻松定义和运行多容器的微服务应用,简化了管理流程。同时,Docker 的隔离性也确保了每个微服务的独立性和安全性,避免了不同服务之间的干扰。 - 安全性增强
安全问题受关注,安全工具和实践不断发展。
尽管 Docker 带来了许多便利,但安全问题仍然是用户和企业关注的焦点。因此,Docker 及其生态系统中的安全工具和实践正不断发展。例如,工具如 Aqua Security、Sysdig Secure 和 Twistlock 提供了全面的容器安全解决方案,帮助企业保护其容器化应用免受攻击。这些安全工具包括更加严格的容器扫描、运行时安全监控和自动化的漏洞管理等,确保容器化应用的安全性。 - 边缘计算中的应用
用于边缘设备和节点,处理分布式应用和服务。
Docker 在边缘计算中也有着广泛的应用。边缘设备和节点通常资源有限,需要轻量级的解决方案来处理分布式应用和服务。Docker 的容器化技术正好满足了这一需求,它可以将应用程序及其依赖项打包成一个轻量级的容器,在边缘设备上快速部署和运行。例如,在物联网领域,Docker 容器可以在资源有限的设备上部署微服务,实现数据的实时处理和分析,提高系统的响应速度和可靠性。 - 生态系统扩展
涵盖更多领域,提供更全面解决方案。
Docker 的生态系统在不断扩展,涵盖了更多的领域,为用户提供更全面的解决方案。随着项目的成熟,Docker 及其生态系统的开发越来越侧重于社区合作和开源项目的共同发展。这种合作不仅促进了技术的创新,还帮助标准化了许多容器管理和编排的实践。例如,Libnetwork 的出现使得 Docker 具备了跨主机多子网的能力,同一个子网内的不同容器可以运行在不同的主机上。同时,各种第三方的 SDN 解决方案如 Pipework、Weave、Flannel、SocketPlane 等也为 Docker 网络提供了更多的选择和优化方案。