【Docker】网络

目录

[一.Docker 为什么需要网络管理](#一.Docker 为什么需要网络管理)

[二.Docker 网络架构简介](#二.Docker 网络架构简介)

三.常见网络类型

四.docker网络管理命令

[4.1.docker network create](#4.1.docker network create)

[4.2.docker network inspect](#4.2.docker network inspect)

[4.3.docker network connect](#4.3.docker network connect)

[4.4.docker network disconnect](#4.4.docker network disconnect)

[4.5.docker network prune](#4.5.docker network prune)

[4.6.docker network rm](#4.6.docker network rm)

[4.7.docker network ls](#4.7.docker network ls)

五.网络命令基本操作

六.brideg桥接网络

6.1.brideg桥接网络介绍

6.2.操作案例一------容器间进行通信

6.3.操作案例二------创建自定义网桥网络

6.4.操作案例三------DNS域名解析

6.5.操作案例四------端口的暴露和转发

七.host网络

7.1.host网络介绍

7.2.操作案例

[八.Container 网络](#八.Container 网络)

[8.1.Container 网络介绍](#8.1.Container 网络介绍)

8.2.案例

九.none网络


一.Docker 为什么需要网络管理

Docker 中的容器在默认情况下,其网络环境是与宿主机以及其他容器相互隔离的。

这种设计保障了容器运行时的独立性和安全性,但同时也带来了一系列网络通信方面的实际需求。

因此,合理管理 Docker 网络对于构建稳定、可访问的容器化应用至关重要。

具体来说,我们需要关注以下几个典型场景:

  • 容器之间的通信:在微服务架构中,多个容器往往需要协同工作,例如前端容器需要连接后端 API 容器,后端容器又需要访问数据库容器。如何配置网络,使它们能够稳定、安全地相互访问,是网络管理的基础问题。

  • 容器与宿主机的通信:有时容器需要访问宿主机上运行的服务,或是由宿主机主动访问容器内部,例如日志收集、健康检查等。理解并配置宿主机与容器间的通信机制,是实际部署中不可或缺的一环。

  • 容器与外部网络的通信:容器中的应用有时需要访问互联网或其他外部网络资源,比如下载依赖包、调用外部 API。同时,外部客户端也可能需要访问容器中运行的服务。这涉及到 Docker 的 NAT 机制、端口映射等网络设置。

  • 对外暴露容器服务:如果容器中运行了 Web 服务器、数据库等需要对外提供访问的服务,则必须通过端口映射或路由机制,将容器内的服务端口暴露给外部网络,使其能够被用户或其他系统访问。

  • 网络隔离的调整:虽然默认网络隔离有利于安全,但在某些场景下,我们可能需要容器共享宿主机的网络命名空间,直接使用宿主机的网络配置,例如高性能网络应用或特定网络调试场景。

  • 禁用容器网络:某些特定任务,如离线批处理或安全敏感型作业,可能根本不需要网络功能。此时应如何彻底关闭容器的网络栈,也是网络管理的一个方面。

  • 高度定制化网络:在复杂应用场景中,如跨主机容器组网、虚拟局域网(VLAN)划分、软件定义网络(SDN)集成等,往往需要根据业务需求构建高度定制化的容器网络方案。

综上所述,正是由于容器在实际使用中面临着多样化的网络需求,从简单的互联互通到复杂的拓扑构建,都离不开对 Docker 网络的深入理解与灵活管理。因此,掌握 Docker 网络管理是每个容器技术学习者的必备技能,也是实现高效、可靠容器化部署的关键所在。

二.Docker 网络架构简介

Docker 容器网络是容器化应用中一个重要的虚拟环境组成部分,它让应用程序从宿主机的网络环境中独立出来,形成容器内部自有的网络设备、IP 协议栈、端口套接字、IP 路由表以及防火墙等网络模块。通过这种方式,Docker 为每个容器提供了隔离、可配置的网络环境,为多容器应用的部署与通信奠定了基础。

Docker 为实现容器网络,主要采用三部分组成的架构:CNM(Container Network Model)Libnetwork驱动(Driver)

一、CNM(Container Network Model)

CNM 是 Docker 网络架构的设计规范,定义了容器网络的基本模型,主要由以下三个核心组件构成:

  • Sandbox

    沙盒提供了容器的虚拟网络栈,包括端口、套接字、IP 路由表、防火墙和 DNS 配置等。它实现了容器网络与宿主机网络的隔离,为每个容器创建了一个独立的网络环境。

  • Network

    网络是 Docker 内部的虚拟子网,用于连接多个容器。同一网络内的容器可以直接通信,而不同网络之间默认是隔离的。

  • Endpoint

    端点是容器连接到具体网络的虚拟网络接口,类似于物理机上的网络适配器。一个容器可以通过多个 Endpoint 接入多个网络,每个 Endpoint 仅能属于一个网络。

例如,假设容器 B 有两个 Endpoint,分别接入 Network A 和 Network B。那么容器 A(接入 Network A)可以与容器 B 通过 Network A 通信;而容器 A 与容器 C(仅接入 Network B)之间则无法直接通信,除非通过网关或路由策略进行配置。

二、Libnetwork

Libnetwork 是 Docker 对 CNM 模型的官方实现,使用 Go 语言编写,具有跨平台特性。它不仅是 Docker 网络功能的核心库,还扩展了以下功能:

  • 本地服务发现

  • 基于 Ingress 的容器负载均衡

  • 网络控制层与管理层功能

通过 Libnetwork,Docker 能够支持多主机网络、跨节点服务通信等高级网络特性,极大提升了容器编排和微服务架构中的网络管理能力。

三、驱动(Driver)

驱动负责具体网络功能的实现,包括容器之间的连通性、隔离性以及网络资源的分配。Docker 通过不同类型的驱动扩展其网络能力,常用的内置驱动包括:

  • Bridge Driver:默认驱动,创建桥接网络,适用于单机环境。

  • Host Driver:使容器直接使用宿主机的网络栈,无隔离。

  • Overlay Driver:支持多主机容器网络,常用于 Docker Swarm 或 Kubernetes 集群。

  • Macvlan / IPvlan Driver:为容器分配物理网络的 MAC 或 IP 地址,使其在局域网中像独立设备一样通信。

  • None Driver:禁用容器网络,适用于高度定制化场景。

每种驱动负责管理其对应类型网络的所有资源,用户也可通过插件方式引入第三方驱动,实现更灵活的网络方案。

三.常见网络类型

  1. Bridge 网络(桥接网络)

工作原理:

Bridge 是 Docker 的默认网络驱动。

当 Docker 服务启动时,它会在宿主机上创建一个名为 docker0 的虚拟网桥,并为其分配一个子网段(如 172.17.0.0/16)。

每次创建一个新的容器并使用默认的 bridge 网络时,Docker 会创建一对虚拟网络设备(veth pair),一端放在容器的网络命名空间中(命名为 eth0),另一端连接到 docker0 网桥上。

这样,所有连接到 docker0 的容器就处于同一个二层网络中,可以通过 IP 地址相互通信。

关键特性:

  • 默认隔离 :使用默认 bridge 网络的容器可以通过 IP 地址通信,但不能通过容器名称进行服务发现

  • 端口映射 :为了使外部网络能够访问 bridge 网络中的容器,必须在运行容器时使用 -p-P 参数,将容器的端口映射到宿主机的端口上。例如 -p 8080:80 会将容器的 80 端口映射到宿主机的 8080 端口。

  • 自定义 Bridge 网络:用户可以创建自定义的 bridge 网络。与默认 bridge 相比,自定义 bridge 网络提供了自动的 DNS 解析,容器之间可以通过容器名称进行通信,并且提供了更好的隔离性。

适用场景:

  • 在同一台 Docker 主机上运行多个需要相互通信的应用程序容器,例如一个 Web 应用容器和一个数据库容器。
  1. Host 网络(主机网络)

工作原理:

使用 --network=host 启动容器时,容器不会获得独立的网络命名空间,而是直接使用宿主机的网络堆栈。

这意味着容器将直接监听宿主机的网络接口和端口,容器内的服务看起来就像是宿主机本身的服务一样。

关键特性:

  • 性能最佳:由于绕过了 Docker 的网络栈和端口映射,网络性能最高,几乎没有开销。

  • 端口冲突:容器内使用的端口会直接占用宿主机的端口,如果多个容器都使用 host 模式并监听同一个端口,将会发生冲突。

  • 无网络隔离:容器在网络层面与宿主机没有隔离,无法进行复杂的网络配置(如端口映射)。

适用场景:

  • 对网络性能要求极高的应用,例如负载均衡器、高频交易系统。

  • 需要直接监控或管理宿主机网络流量的容器。

  1. Container 网络(容器网络)

工作原理:

使用 --network=container:<容器名或ID> 启动一个新容器时,新容器不会创建自己的网络设备,而是**与指定的已存在容器共享同一个网络命名空间。**它们将拥有相同的 IP 地址、端口范围等所有网络资源。

关键特性:

  • 网络共享:两个容器除了网络,其他资源(如文件系统、进程树)仍然是隔离的。

  • 本地通信 :共享网络的容器可以通过本地回环地址 127.0.0.1 进行高效通信,就像同一台机器上的两个进程一样。

  • 生命周期绑定:被共享网络的容器如果停止,依赖它的容器也会失去网络连接。

适用场景:

  • Sidecar 模式:为主容器提供辅助功能的容器(如日志收集器、代理服务),它们需要紧密的网络协作。

  • 需要对现有容器的网络栈进行调试或扩展,而不想修改原容器。

  1. None 网络(无网络)

工作原理:

使用 --network=none 启动的容器拥有自己独立的网络命名空间,但 Docker 不为它配置任何网络接口(除了本地的 lo 回环接口)。容器处于完全的网络断开状态。

关键特性:

  • 极致安全与隔离:容器无法与外部进行任何网络通信。

  • 手动配置 :如果需要网络,用户可以手动进入容器内部,使用 ip 等命令自行配置网络设备。

适用场景:

  • 需要处理高度敏感数据,且安全策略要求完全断网的容器。

  • 需要用户完全自定义网络栈的特定边缘场景。

  1. Overlay 网络(覆盖网络)

工作原理:

Overlay 网络是为 Docker Swarm 集群服务设计的。**它通过在多个 Docker 主机(节点)的底层物理网络之上创建一个虚拟网络,使得不同节点上的容器可以像在同一个网络中一样通信。**这通常通过 VXLAN 等隧道技术实现。

关键特性:

  • 跨主机通信:核心功能,使 Swarm 服务能够跨节点互联。

  • 加密:可以配置 Overlay 网络流量自动加密。

  • 服务发现:内置 DNS 服务,Swarm 服务可以通过服务名被发现。

  • 依赖集群:必须初始化或加入一个 Docker Swarm 集群才能使用。

适用场景:

  • 在 Docker Swarm 集群中部署的分布式微服务应用,这些服务需要跨多台主机进行通信。

关于 docker0 网桥的补充说明

docker0 是 Docker 安装时自动创建的默认 bridge 网桥。

它是一个软件交换机,负责:

  1. 连接容器:为默认 bridge 网络上的容器提供数据转发的平台。

  2. 地址分配:通过内置的 DHCP 机制为容器分配 IP 地址。

  3. NAT(网络地址转换) :当容器访问外部网络(互联网)或通过端口映射被访问时,docker0 网桥会负责进行源/目标地址的转换,使得容器内部 IP 能够与外界通信。

当用户创建自定义的 bridge 网络时,Docker 会为每个自定义网络创建一个新的网桥设备(通常名为 br-<网络ID>),其功能与 docker0 类似,但提供了更高级的功能(如内部 DNS)。

四.docker网络管理命令

4.1.docker network create

复制代码
docker network create [OPTIONS] NETWORK_NAME
  • OPTIONS\]:就是下面要讲的关键参数。

关键参数

-d, --driver:网络驱动

这是指定这个网络是什么"类型"的。

最常用的有:

  • bridge:默认驱动。适用于单个 Docker 主机上运行的容器。你可以把它理解成在你电脑内部创建的一个虚拟交换机。绝大多数情况都用这个。
  • overlay:用于多个 Docker 主机(即 Docker 集群,称为 Swarm)之间的容器通信,更复杂,初学者暂时用不到。
  • host:直接使用主机的网络命名空间,容器没有独立的网络。
  • none:禁用所有网络。

示例:创建一个使用 bridge 驱动的网络。

复制代码
docker network create -d bridge my-bridge-network

(因为 bridge 是默认驱动,所以 -d bridge 其实可以省略。)

--subnet:子网网段

这相当于为你这个"专属局域网"规划一个地址范围。所有连接到这个网络的容器,都会从这个范围里获取一个 IP 地址。

它必须使用 CIDR 格式(别怕,格式很简单:IP地址/掩码)。

常见规划:

  • 172.18.0.0/16:IP 范围从 172.18.0.1 到 172.18.255.254,非常大。
  • 192.168.100.0/24:IP 范围从 192.168.100.1 到 192.168.100.254,足够用了。

示例:指定一个子网。

复制代码
docker network create --subnet 192.168.100.0/24 my-network

想必大家在看到上面那一堆东西就头晕眼花了,这里需要带大家复习一下IP地址相关的知识了

一个IP地址(如 192.168.100.1)本质上是一个32位的二进制数。

为了便于人类阅读,我们把它分成4段(每段8位),并转换成十进制。

例如:
192.168.100.1 在二进制中是:
11000000.10101000.01100100.00000001


核心概念二:子网掩码与 / 后缀

子网掩码用来区分一个IP地址中,哪部分是网络号哪部分是主机号

  • 网络号:就像你家的街道名和门牌号,它标识了整个网络。

  • 主机号:就像你家里具体的房间号,它标识了网络中的某一个具体设备。

/16/24 是子网掩码的简写形式。它表示子网掩码中,从左到右连续有多少个 1

  • /16:表示子网掩码有16个1

    • 二进制:11111111.11111111.00000000.00000000

    • 十进制:255.255.0.0

  • /24:表示子网掩码有24个1

    • 二进制:11111111.11111111.11111111.00000000

    • 十进制:255.255.255.0

规则是:子网掩码中 1 对应的部分就是网络号,0 对应的部分就是主机号。


让我们来详细计算两个例子

例1:192.168.100.0/24

  1. 分解IP和掩码

    • IP地址: 192.168.100.0 -> 11000000.10101000.01100100.00000000

    • 子网掩码 (/24): 255.255.255.0 -> 11111111.11111111.11111111.00000000

  2. 划分网络号和主机号

    • 前24位(3个字节)是网络号:11000000.10101000.01100100 (这就是 192.168.100)

    • 后8位(1个字节)是主机号:.00000000

  3. 确定网络地址和广播地址

    • 网络地址 :主机位全部为 0这就是 192.168.100.0。它代表这个网络本身,不能分配给任何设备。

    • 广播地址 :主机位全部为 1

      • 主机位全1.11111111 -> .255

      • 所以广播地址是:192.168.100.255这个地址用于向网络中所有设备广播,也不能分配给具体设备。

  4. 计算可用IP范围

    • 第一个可用IP :网络地址的下一个地址。192.168.100.0 -> 192.168.100.1

    • 最后一个可用IP :广播地址的前一个地址。192.168.100.255 -> 192.168.100.254

    • 可用IP范围192.168.100.1192.168.100.254

  5. 计算可用IP总数

    • 主机号有8位,所以有 2^8 = 256 个组合。

    • 减去一个网络地址和一个广播地址,可用设备数量是 256 - 2 = 254个


例2:172.18.0.0/16

  1. 分解IP和掩码

    • IP地址: 172.18.0.0 -> 10101100.00010010.00000000.00000000

    • 子网掩码 (/16): 255.255.0.0 -> 11111111.11111111.00000000.00000000

  2. 划分网络号和主机号

    • 前16位(2个字节)是网络号:10101100.00010010 (这就是 172.18)

    • 后16位(2个字节)是主机号:.00000000.00000000

  3. 确定网络地址和广播地址

    • 网络地址 :主机位全 0 -> 172.18.0.0

    • 广播地址 :主机位全 1

      • 主机位全1.11111111.11111111 -> .255.255

      • 所以广播地址是:172.18.255.255

  4. 计算可用IP范围

    • 第一个可用IP172.18.0.0 -> 172.18.0.1

    • 最后一个可用IP172.18.255.255 -> 172.18.255.254

    • 可用IP范围172.18.0.1172.18.255.254

  5. 计算可用IP总数

    • 主机号有16位,所以有 2^16 = 65,536 个组合。

    • 减去一个网络地址和一个广播地址,可用设备数量是 65,536 - 2 = 65,534个

--gateway:网关地址

这个"专属局域网"要有一个"大门",用于和外部(比如互联网,或者其他网络)通信,这个"大门"就是网关。

它必须是你上面 --subnet 范围内的一个 IP 地址。

通常,我们会把子网里的第一个可用 IP 设为网关,比如 xxx.xxx.xxx.1。

示例:指定子网和网关。

复制代码
docker network create --subnet 192.168.100.0/24 --gateway 192.168.100.1 my-network

--ipv6:启用 IPv6

顾名思义,就是在这个网络中是否启用 IPv6 支持。true 表示启用,false 表示不启用。


话不多说,我们直接看例子

复制代码
docker network create mynet1 --subnet=192.168.0.0/16

我们看到,默认就是bridge模式

我们可以详细查看这个网络的详情

复制代码
docker network inspect mynet1

这些信息都是非常详细的

4.2.docker network inspect

语法

docker network inspect 命令用来查看 Docker 网络的详细信息,就像是用"显微镜"来观察一个网络的内部结构。

基本用法

bash 复制代码
# 查看单个网络
docker network inspect 网络名

# 查看多个网络
docker network inspect 网络名1 网络名2

默认输出

如果不加任何参数,命令会返回一个很详细的 JSON 格式信息,包含:

  • 网络名称、ID、创建时间

  • 使用的驱动

  • IPAM 配置(子网、网关)

  • 连接的容器列表

  • 其他配置选项


我们直接看例子

首先我们先创建一个子网啊

bash 复制代码
docker network create mynet2 --subnet=10.1.0.0/16
bash 复制代码
docker network inspect mynet2
bash 复制代码
docker network inspect mynet1 mynet2

4.3.docker network connect

你可以把 Docker 网络 想象成一个专属的电话网络或者一个公司的内部局域网。

  • 在这个"电话网络"里的所有"电话"(也就是容器),都可以互相直接通话(通信),而且通常叫名字就能找到对方。
  • 默认情况下,一个容器只加入一个这样的网络(就像你刚买的一部手机,只插了一张SIM卡,只能在一个运营商网络里使用)。

那么 docker network connect 命令的作用就是:给一部已经开机在用的手机(容器),再插上第二张SIM卡(连接到另一个网络),让它能同时接入另一个电话网络。

命令的语法和参数

bash 复制代码
docker network connect [OPTIONS] NETWORK CONTAINER

我们把它拆解一下:

docker network connect

  • 这是命令的主体,告诉 Docker:"我现在要进行网络连接操作"。

OPTIONS

  • 这是"选项",是可选的。你可以用它来指定一些额外的要求,比如你提到的 --ip。
  • --ip:比如,给你这部手机在第二个网络里指定一个固定的号码(IP地址),而不是让它自动获取。
  • --ip6:指定一个固定的IPv6地址。

NETWORK

  • 这是网络的名字或者ID。你要把容器连接到哪个网络?就写这个网络的名字。
  • 你可以用 docker network ls 命令查看所有现有的网络。

CONTAINER

  • 这是容器的名字或者ID。你要操作哪个容器?就写它的名字。
  • 你可以用 docker ps 命令查看正在运行的容器。

举个例子,一看就懂

假设我们有以下两个正在运行的容器:

  • 一个叫 my_web(想象成一个网站服务器)
  • 一个叫 my_database(想象成一个数据库)

还有一个自定义网络叫 my_backend_network。

目标:现在 my_web 容器需要访问 my_database 容器里的数据,但它们不在同一个网络里。我们就把 my_web 也加入到 my_database 所在的 my_backend_network 网络中。

步骤:

查看当前状态

首先,我们可以看一下 my_backend_network 里现在有哪些容器:

bash 复制代码
docker network inspect my_backend_network

你可能会发现,只有 my_database 在这个网络里。

执行连接命令

现在,我们把 my_web 容器连接进去:

bash 复制代码
docker network connect my_backend_network my_web

这个命令很简单,没有用任何 [OPTIONS],就是告诉Docker:把容器 my_web 连接到网络 my_backend_network。

验证结果

再次检查网络:

bash 复制代码
docker network inspect my_backend_network

你会发现,现在网络里有两个容器了:my_database 和 my_web。

效果

现在,在 my_web 容器内部,它可以直接使用 my_database 这个名字来访问数据库容器了!因为它们在同一個"内部局域网"里了。

另一个例子:使用 --ip 参数

如果我们想在上面的例子上加一个要 求:给 my_web 容器在 my_backend_network 网络里一个固定的IP地址,比如 172.20.0.100。

命令就会变成这样:

bash 复制代码
docker network connect --ip 172.20.0.100 my_backend_network my_web

这样,在这个网络里,my_web 容器就有了一个固定的"门牌号",其他容器可以通过这个IP地址准确地找到它。


话不多说,我们直接看例子

bash 复制代码
docker network create mynet4 --subnet=10.2.0.0/16

现在我们启动一个容器

bash 复制代码
docker run -dit --name busybox1 busybox:1.37

现在我们进去这个容器看看

bash 复制代码
docker exec -it busybox1 sh

我们看到它已经有一个172.17.0.3的IP地址,这个其实是docker0 给他分配的IP地址(docker0是 Docker 安装时自动创建的默认 bridge 网桥)

现在我们退出容器,然后在宿主机上执行下面这个

bash 复制代码
docker network connect mynet4 busybox1

执行完之后我们再进去容器内部看看

可以看到它多了一个IP啊,这个就是我们自定义网络mynet4赋予它的IP地址,我们可以退出来,在宿主机上查看网络的详细信息

bash 复制代码
docker network inspect mynet4

我们很容易就能看到下面这个字段

这个是不是就和上面那个对上了?

4.4.docker network disconnect

那么 docker network disconnect 就是:从一部手机(容器)里,拔掉指定的那张SIM卡(断开与指定网络的连接)。

命令的语法和参数

bash 复制代码
docker network disconnect [OPTIONS] NETWORK CONTAINER

我们来拆解一下:

docker network disconnect

  • 这是命令的主体,告诉 Docker:"我现在要进行网络断开操作"。

OPTIONS

  • 可选参数。最重要的就是 -f(强制)。

NETWORK

  • 这是网络的名字或者ID。你要把容器从哪个网络断开?就写这个网络的名字。

CONTAINER

  • 这是容器的名字或者ID。你要操作哪个容器?就写它的名字。

关键参数 -f(强制)

这个参数非常重要,我们来重点讲讲:

-f 或 --force:强制从容器的网络中断开。

  • 什么时候需要强制?
  • 当容器正在运行,并且断开网络可能会影响容器时,Docker 可能会拒绝断开。
  • 使用 -f 参数就是告诉 Docker:"别管那么多了,我确定要断开,直接执行吧!"
  • 注意:强制断开网络可能会立即终止容器在该网络上的所有连接,所以请谨慎使用。

举个例子,一看就懂

继续使用我们之前的例子:

  • 容器:my_web(网站服务器)
  • 网络:my_backend_network

场景:之前我们把 my_web 连接到了 my_backend_network 网络,现在这个网站服务器不再需要访问那个网络的资源了,我们想把它从这个网络中移除。

步骤:

查看当前状态

首先,确认 my_web 确实在 my_backend_network 网络中:

bash 复制代码
docker network inspect my_backend_network

执行断开命令

现在,我们把 my_web 从网络中断开:

bash 复制代码
docker network disconnect my_backend_network my_web

这个命令告诉Docker:把容器 my_web 从网络 my_backend_network 中断开连接。

验证结果

再次检查网络:

bash 复制代码
docker network inspect my_backend_network

你会发现,my_web 容器已经不在这个网络里了。

效果

现在,my_web 容器再也无法直接访问 my_backend_network 网络中的其他容器(比如 my_database)了。

使用 -f 强制断开的例子

场景:假设 my_web 容器正在通过 my_backend_network 网络与数据库进行重要的数据交换,Docker 可能会认为此时断开网络不安全。如果你确定要立即断开,就可以使用 -f 参数:

bash 复制代码
docker network disconnect -f my_backend_network my_web

或者:

bash 复制代码
docker network disconnect --force my_backend_network my_web

这样,无论容器在做什么,都会立即从该网络中断开。


话不多说,我们直接看例子,我们在4.3让busybox1容器连接上了mynet4网络

bash 复制代码
docker network inspect mynet4

我们很容易就能看到下面这个字段

现在我们就把它断开

bash 复制代码
docker network disconnect mynet4 busybox1

怎么样,mynet4的信息里面是不是就没有busybox1这个容器的信息了!!

现在我们也可以进去busybox1容器内部看看

bash 复制代码
docker exec -it busybox1 sh

也确实是恢复到了原来那个模样。

4.5.docker network prune

在Docker中,当我们创建网络、启动容器等操作时,可能会留下一些不再使用的网络(比如没有被任何容器使用的网络)。这些网络占用了资源,并且可能引起管理上的混乱。docker network prune 命令就是用来清理这些不再使用的网络。

命令的语法和参数

bash 复制代码
docker network prune [OPTIONS]

关键参数 -f--force

  • -f, --force:使用这个参数,Docker将不会在删除之前提示你确认,而是直接进行删除。

举个例子

  1. 不加 -f 参数

    如果你直接运行:

    bash 复制代码
    docker network prune

    Docker会显示一个警告,告诉你将删除所有未被使用的网络,并要求你确认。只有你输入 'y' 或 'yes'(取决于提示)后,它才会执行删除。

    示例输出:

  2. -f 参数

    如果你确定要删除所有未使用的网络,并且不想被提示打扰,可以使用 -f 参数:

    bash 复制代码
    docker network prune -f

    或者

    bash 复制代码
    docker network prune --force

    这样,Docker会直接删除所有未使用的网络,而不需要你确认。

注意点

  • 默认网络不会被删除 :Docker自带的默认网络(如 bridgehostnone)不会被删除,即使它们没有被使用。

  • 谨慎使用 :这个命令会删除所有未被使用的自定义网络。如果你有一些网络虽然当前没有容器使用,但将来可能会用到,那么请谨慎使用这个命令。建议在删除前,可以使用 docker network ls 来查看所有网络,并使用 docker network inspect <网络名> 来查看网络详情。


话不多说,我们直接看例子

4.6.docker network rm

这个命令用于删除一个或多个指定的网络。与 docker network prune(批量删除未使用的网络)不同,network rm 是删除你明确指定的网络。

语法:

bash 复制代码
docker network rm NETWORK [NETWORK...]

其中,NETWORK 可以是网络名或网络ID。

关键参数:

-f, --force:强制删除网络。这个参数用于强制删除一个网络,即使有容器正在使用它。

注意:默认情况下,如果网络上有容器(即使已停止的容器)正在使用,则不能删除网络。使用 -f 参数可以强制删除,但请谨慎使用,因为这可能会影响使用该网络的容器。

举个例子:

删除一个名为 my_network 的网络:

bash 复制代码
docker network rm my_network

删除多个网络:

bash 复制代码
docker network rm network1 network2

强制删除一个网络(即使有容器连接在上面):

bash 复制代码
docker network rm -f my_network

注意:使用 -f 强制删除网络时,Docker 会断开所有连接到该网络的容器,然后删除网络。这可能会导致容器失去网络连接,影响容器之间的通信。

重要提示:在删除网络之前,最好先确保没有容器在使用它。

你可以使用以下命令查看网络上的容器:

bash 复制代码
docker network inspect [网络名]

另外,不能删除 Docker 默认网络(如 bridge、host、none)。

让我们通过一个例子来演示:

假设我们有一个网络叫 my_backend,我们想删除它。

步骤1:检查网络是否存在以及是否有容器连接。

bash 复制代码
docker network ls
docker network inspect my_backend

步骤2:如果发现没有容器连接,那么可以安全删除:

bash 复制代码
docker network rm my_backend

步骤3:如果发现有容器连接,而你还是想删除,那么可以先断开容器,或者使用强制删除。

断开容器连接:

bash 复制代码
docker network disconnect my_backend container_name

然后删除网络:

bash 复制代码
docker network rm my_backend

或者直接强制删除:

bash 复制代码
docker network rm -f my_backend

注意:强制删除会直接断开所有连接在该网络上的容器,然后删除网络。


话不多说,我们直接看例子

bash 复制代码
docker network create mynet1
docker network create mynet2
docker network create mynet3

现在我们启动一个容器

bash 复制代码
docker run -itd --name busybox2 busybox:1.37
docker network connect mynet3 busybox2

现在我们去检查一下

bash 复制代码
docker network inspect mynet3

这就代表加入成功了啊。

现在我们进行删除

我们发现这个mynet3没有被删除!!这个是因为mynet3被这个busybox2容器使用着!!!

4.7.docker network ls

我们来看一下docker network ls命令,它用于列出Docker网络。这个命令有很多有用的参数,下面我们逐一讲解。

语法

bash 复制代码
docker network ls [OPTIONS]

别名

docker network listdocker network ls 的别名,功能完全相同。

关键参数

  1. -f, --filter:指定过滤条件,可以过滤显示的网络。

    • 例如,只显示驱动为bridge的网络:-f driver=bridge

    • 常用的过滤器:

      • driver=<driver-name>:按网络驱动过滤。

      • id=<network-id>:按网络ID过滤。

      • label=<key>label=<key>=<value>:按标签过滤。

      • name=<network-name>:按网络名称过滤。

      • type=<network-type>:按网络类型过滤(builtincustom)。

  2. --no-trunc:不截断输出,显示完整的网络ID和其他信息。

    • 默认情况下,Docker会截断ID以保持输出整洁,使用该参数将显示完整的ID。
  3. -q, --quiet:仅显示网络ID,不显示其他信息。

    • 这在脚本中非常有用,因为你可以直接获取网络ID列表。

示例

基本列出网络

bash 复制代码
docker network ls

输出类似:

使用过滤器

只显示bridge驱动网络:

bash 复制代码
docker network ls -f driver=bridge

只显示名称为bridge的网络:

bash 复制代码
docker network ls -f name=mynet3

显示自定义网络(类型为custom):

bash 复制代码
docker network ls -f type=custom

不截断:

bash 复制代码
docker network ls --no-trunc

仅显示网络ID

bash 复制代码
docker network ls -q

五.网络命令基本操作

一个是在创建容器时使用 --network 参数,另一个是对已运行的容器使用 docker network connect 命令。它们都可以将容器连接到网络,但时机和效果不同。

--network 参数:

  • 用于在创建容器时指定容器要加入的网络。
  • 例如:docker run --network=my_network my_image
  • 这样,容器在启动时就连接到 my_network 网络。
  • 一个容器在创建时只能使用一个 --network 参数,即只能加入一个网络。如果不指定,默认连接到 bridge 网络。

docker network connect 命令:

  • 用于将已经运行的容器连接到另一个网络。
  • 例如:docker network connect my_network my_container
  • 这样,一个已经运行的容器可以额外再连接到一个网络,从而一个容器可以同时连接到多个网络。

区别总结:

  • 时机不同:--network 是在容器创建时指定,而 docker network connect 是在容器运行后。
  • 数量不同:创建时只能指定一个网络,但运行后可以使用 docker network connect 连接多个网络。

我们需要注意一些点:

  • 使用 --network 指定网络时,容器不会连接到默认的 bridge 网络(即docker0网桥),而是连接到指定的网络。
  • 使用 docker network connect 时,如果容器原本在默认的 bridge 网络中,那么它除了新连接的网络外,仍然保留在默认的 bridge 网络中。

但是,这里有一个常见的误解:

  • 实际上,容器在创建时如果没有使用 --network 指定网络,则会默认连接到 bridge 网络(即docker0网桥)。
  • 而如果使用 --network 指定了其他网络,那么容器就不会连接到默认的 bridge 网络。

而 docker network connect 命令用于将已运行的容器连接到另一个网络,这个网络可以是用户自定义网络,也可以是默认的 bridge 网络(虽然通常不这么做)。

但是,如果容器原本不在默认的 bridge 网络中,那么使用 docker network connect 连接默认的 bridge 网络时,才会加入docker0网。


首先我们先创建一个网络

现在我们去看看这个mynet6什么情况

bash 复制代码
docker network inspect mynet6

现在我们创建两个容器来连接这个网络

bash 复制代码
docker run -itd \
--network mynet6 \
--name busybox3 \
busybox:1.37

现在我们重新去看看mynet6网络的信息

bash 复制代码
docker network inspect mynet6

亦或者,我们可以去看看容器的信息

bash 复制代码
docker inspect busybox3

没有问题吧

现在我们重新启动一个新的容器

bash 复制代码
docker run -itd --name busybox4 busybox:1.37

现在我们去看看它的信息

bash 复制代码
docker inspect busybox4

我们发现,虽然我们没有指定网络,但是它默认加入了docker 0的网络

不信的话,我们可以在宿主机上执行下面这个

bash 复制代码
ifconfig

这个是不是和上面那个对上了!!

现在我们把我们现在busybox4容器加入到mynet6看看

bash 复制代码
docker network connect mynet6 busybox4

现在我们去看看mynet6的信息

bash 复制代码
docker network inspect mynet6

这个就很明显了吧

现在我们回去看看那个busybox4容器的信息

bash 复制代码
docker inspect busybox4

现在就加入了2个网络里了!!

现在我们就让这两个容器退出mynet6

bash 复制代码
docker network disconnect mynet6 busybox3
docker network disconnect mynet6 busybox4

现在我们再去看看网络的信息

没有任何一个容器了

接下来我们就删除这个mynet6即可

bash 复制代码
docker network rm mynet6

六.brideg桥接网络

6.1.brideg桥接网络介绍

桥接网络工作过程

首先我们先在宿主机上进行查询

bash 复制代码
ifconfig

我们其实就能发现下面这个东西

接下来我们创建一个容器

bash 复制代码
docker run -dit --name test1 busybox:1.37

注意:当我们运行一个容器时,如果没有使用 --network 指定网络,那么它就会自动连接到默认的 bridge 网络。

接下来我们进去这个容器内部看看

我们可以看到容器内部也有一个eth0。

那么容器内部的eth0、宿主机的docker0、宿主机的eth0是不是有什么关系呢?

其实它们三者的关系就是下面这个图这样子

我们有三者:容器内部的eth0、宿主机的docker0、宿主机的eth0。

当我们启动一个容器(比如使用默认的bridge网络)时,Docker 会执行以下操作:

  1. 创建一对虚拟以太网设备(veth pair),一端放在容器内部(通常命名为 eth0@ifXX),另一端连接到 docker0 网桥上。

  2. 为容器分配一个在 docker0 网桥所在子网内的 IP 地址(比如 172.17.0.2)。

  3. 在容器内部设置路由,将默认路由指向 docker0 的 IP 地址(172.17.0.1)。

它们的工作流程如下:

  1. 当创建一个容器时,Docker会为容器创建一个网络命名空间(network namespace),这是一个隔离的网络环境。

  2. 在容器内部,你会看到一个eth0网络接口,这是容器内部的网络接口,它被分配了一个IP地址(通常在172.17.0.0/16网段)。

  3. 在宿主机上,Docker会创建一个veth pair(一对虚拟网络设备),其中一个veth放在容器的网络命名空间内,并命名为eth0 ,另一个veth则留在宿主的默认网络命名空间中,并命名为类似vethxxxx的名称。

  4. 留在宿主机的那个veth接口会被自动连接到docker0网桥

  5. 宿主机上的docker0网桥是一个虚拟交换机,它有自己的IP(如172.17.0.1),并且连接了所有容器的veth接口。

  6. 宿主机上的eth0是宿主机的物理网卡(或主网络接口),它连接外部网络。

它们三者配合工作的过程:

1. 容器内部通信(容器A → 容器B)

bash 复制代码
容器A的eth0 → veth pair → docker0网桥 → veth pair → 容器B的eth0
  • 容器A通过自己的eth0发送数据
  • 数据通过veth pair(虚拟以太网设备对)传到宿主机的docker0网桥
  • docker0查看目标IP地址,发现是同一网段的其他容器
  • docker0直接将数据转发给对应容器的veth pair
  • 数据到达容器B的eth0

关键:这种通信完全在docker0网桥内部完成,不经过宿主机的eth0

2. 容器访问外部网络(容器 → 互联网)

bash 复制代码
容器eth0 → veth pair → docker0 → 宿主机的路由表 → 宿主机的eth0 → 互联网
  • 容器通过容器的eth0发送数据,目标是非172.17.0.0/16网段的地址
  • 数据通过veth pair传到宿主机的docker0
  • docker0将数据交给宿主机的网络栈处理
  • 宿主机查看自己的路由表,发现目标需要从宿主机的eth0出去
  • 宿主机执行SNAT(源地址转换),把源IP从172.17.0.x改成宿主机的10.0.16.14
  • 数据通过宿主机的eth0发送到互联网

3. 外部访问容器(互联网 → 容器)

bash 复制代码
互联网 → 宿主机eth0 → DNAT → docker0 → veth pair → 容器eth0
  • 外部请求到达宿主机的eth0,目标可能是10.0.16.14:8080
  • 宿主机检查DNAT(目标地址转换)规则
  • 如果配置了端口映射,宿主机把目标IP和端口改为容器的172.17.0.x:80
  • 修改后的数据包发送到docker0网桥
  • docker0通过veth pair把数据传给对应容器的eth0

整个过程,

  • 宿主机上的eth0只负责与外部网络通信.
  • docker0负责内部容器之间的通信以及容器与宿主机网络栈之间的桥梁。
  • 容器内部的eth0则是容器与docker0网桥之间的通道。

Bridge 网络解析

当我们安装 Docker 后,默认会创建三个网络:bridge、host 和 none。

其中,bridge 网络是默认网络,除非我们使用 --network 指定其他网络,否则新创建的容器都会连接到这个网络。

  • Bridge 网络使用 Linux 内核中的 Linux bridge 技术。Linux bridge 是一个虚拟的网桥,它能够在网络段之间转发流量。
  • 在 Docker 中,这个虚拟网桥默认叫做 docker0。我们可以把 docker0 看作一个虚拟交换机,所有连接到默认 bridge 网络的容器都会通过一根虚拟网线连接到这个交换机上。

默认的 Bridge 网络

  1. 当我们启动 Docker 时,它会自动创建一个默认的 bridge 网络,在 Docker 中命名为 bridge,在 Linux 内核中对应一个名为 docker0 的网桥。
  2. 我们可以使用 docker network ls 看到这个网络,它的 DRIVER 是 bridge,SCOPE 是 local(本地范围)。

容器如何连接到默认 Bridge 网络

  • 当我们运行一个容器时,如果没有使用 --network 指定网络,那么它就会自动连接到默认的 bridge 网络。
  • 例如:docker run -d --name my_container nginx,这个容器就会连接到默认的 bridge 网络。

默认 Bridge 网络的特性

  • 容器间通信:**连接到同一个 bridge 网络的容器可以通过 IP 地址相互通信。**但是,默认情况下,容器之间通过容器名称来通信是不行的(除非使用自定义的 bridge 网络,默认的 bridge 网络不支持自动服务发现)。
  • 隔离性:没有连接到同一个 bridge 网络的容器之间是隔离的,不能直接通信。
  • 与外部通信:容器可以通过宿主机的网络栈与外部通信(通过 NAT),外部网络也可以通过端口映射访问容器(使用 -p 参数)。

自定义 Bridge 网络

除了默认的 bridge 网络,我们还可以创建自定义的 bridge 网络。

创建自定义 bridge 网络的好处:

  • 自动 DNS 解析:在自定义 bridge 网络中,容器之间可以通过容器名称进行通信,Docker 内置了 DNS 服务器,为容器提供名称解析。
  • 更好的隔离:可以将一组相关的容器连接到同一个自定义网络,与其他容器隔离。
  • 可以动态地连接和断开网络。

默认 Bridge 网络与自定义 Bridge 网络的区别

  • 默认 bridge 网络不支持通过容器名通信,而自定义 bridge 网络支持。
  • 默认 bridge 网络通常用于兼容旧版本,建议使用自定义 bridge 网络。

6.2.操作案例一------容器间进行通信

现在我们先启动一下容器

bash 复制代码
docker run -itd --name b1 busybox:1.37
docker run -itd --name b2 busybox:1.37

注意:当我们运行一个容器时,如果没有使用 --network 指定网络,那么它就会自动连接到默认的 bridge 网络。

现在我们进入第一个容器看看

现在我们去看看默认的桥接网络的信息

bash 复制代码
docker network inspect bridge

可以看到,我们两个容器被默认加入了bridge网络。

现在我们打开一个容器

bash 复制代码
docker exec -it b1 sh

可以看到,在eth0中显示它的IP地址是172.17.0.2。是不是和上面对上了啊??

现在我们打开另外一个容器

bash 复制代码
docker exec -it b2 sh

可以看到,在eth0中显示它的IP地址是172.17.0.3。

现在我们在b1这个容器里面执行下面这个命令

bash 复制代码
ping 172.17.0.3

没有问题

现在我们去b2容器内部执行下面这个命令

bash 复制代码
ping 172.17.0.2

也是没有任何问题的。

现在两个容器都能进行通信的!!!

现在我们回去宿主机看看

我们发现这个docker0的IP地址就是172.17.0.1

我们仔细观察一下

这个docker0就是bridge的GateWay!!

  • 在Docker的默认桥接网络(bridge)中,每个容器会分配一个IP地址,并且这些容器可以通过这个桥接网络相互通信。
  • 而docker0是宿主机上的一个虚拟网桥,它有一个IP地址,通常为172.17.0.1(也可能是其他,但默认是172.17.0.0/16网段)。
  • 在这个网络中,docker0的IP地址(例如172.17.0.1)被用作连接在这个桥接网络上的容器的默认网关(Gateway)。

这意味着:

  • 当容器试图访问与其不在同一网络的地址时,数据包会被发送到网关,也就是docker0的IP地址。
  • 然后由宿主机负责将发送到宿主机docker0的数据包再通过宿主机的网络接口(如eth0)转发到外部网络。

所以,是的,docker0就是默认桥接网络(bridge)的网关(Gateway)。

然后我们仔细看看

  • docker0的IP地址:172.17.0.1
  • b1容器的IP地址:172.17.0.2
  • b2容器的IP地址:172.17.0.3

它们确实是都在同一个网络里面!!

现在我们停止一个容器

bash 复制代码
docker stop b1

现在我们再去检查一下bridge网络

bash 复制代码
docker network inspect bridge

现在容器就只剩下b2了!还是很简单的吧!!

6.3.操作案例二------创建自定义网桥网络

在默认情况下, 我们创建的容器都会连接在docker0这个bridge上。

那其实我们也 可以创建一些自定义的bridge,让运行的容器通过自定义bridge进行通信。

还记得我们的docker network create有一个选项是-d吗?

**-d, --driver:**指定这个网络是什么"类型"的。

最常用的有:

  • bridge:**默认驱动。**适用于单个 Docker 主机上运行的容器。你可以把它理解成在你电脑内部创建的一个虚拟交换机。绝大多数情况都用这个。
  • overlay:用于多个 Docker 主机(即 Docker 集群,称为 Swarm)之间的容器通信,更复杂,初学者暂时用不到。
  • host:直接使用主机的网络命名空间,容器没有独立的网络。
  • none:禁用所有网络。

示例:创建一个使用 bridge 驱动的网络。

复制代码
docker network create -d bridge my-bridge-network
等价于
docker network create my-bridge-network

(因为 bridge 是默认驱动,所以 -d bridge 其实可以省略。)


话不多说,我们之间看例子

首先我们先创建一个桥接网络

复制代码
docker network create mynet1

注意,创建的网络默认就是bridge的

复制代码
docker network inspect mynet1

可以看到ip地址是172.18.0.0/16,网关是172.18.0.1

我们现在在宿主机上查看一下

复制代码
ifconfig

可以看到,宿主机上就有一个网段的IP也是172.18.0.1,这就说明这个宿主机上的br-ae2460400cde就是docker自定义桥接网mynet1的网关。

注意:宿主机的docker0是容器的默认bridge网的网关

现在我们创建两个容器

复制代码
docker run -itd --name b3 --network mynet1 busybox:1.37
docker run -itd --name b4 --network mynet1 busybox:1.37

现在我们去查看一下网络的信息

复制代码
docker network inspect mynet1

可以看到

  • b3的IP地址:172.18.0.2
  • b4的IP地址:172.18.0.3

很好连接成功了,现在我们分别进去容器内部去ping对方

复制代码
docker exec -it b3 sh

现在我们ping对方成功了!!

复制代码
docker exec -it b4 sh

现在我们发现,它们确实是都可以进行网络通信的

6.4.操作案例三------DNS域名解析

  • Docker 自定义桥接网络是支持通过Docker DNS服务进行域名解析的, 也就是说我们 可以直接使用容器名进行通信,因为DNS服务可以解析容器名到IP地址的映射
  • 但是默认的 bridge网络是不支持DNS的。

话不多说,我们直接看例子

复制代码
docker run -itd --name b5 busybox:1.37
docker run -itd --name b6 busybox:1.37

现在我们去看看默认的桥接网络的信息

复制代码
docker network inspect bridge

我们看到

  • b5的IP地址:172.17.0.2
  • b6的IP地址:172.17.0.4

现在我们分别进去容器,ping对方的容器名

复制代码
docker exec -it b5 sh

我们发现不能解析容器名,但是能解析IP地址。

我们换一个容器看看

复制代码
docker exec -it b6 sh

我们发现不能解析容器名,但是能解析IP地址。

这个就是默认bridge网络的缺陷!!

自定义桥接网络

现在我们创建自定义桥接网络

复制代码
docker network create mynet2

现在我们创建两个容器

复制代码
docker run -itd --name b7 --network mynet2 busybox:1.37
docker run -itd --name b8 --network mynet2 busybox:1.37

现在我们去看看mynet2网络的信息

复制代码
docker network inspect mynet2

可以看到两个容器都在这个网络里面

现在我们分别进入这个两个容器,然后ping对方容器名

复制代码
docker exec -it b7 sh

我们发现完全没有问题。

我们换一个容器看看

复制代码
docker exec -it b8 sh

完全没有问题!!自定义桥接网络就是能通过容器名解析成IP地址的。

6.5.操作案例四------端口的暴露和转发

为什么需要端口暴露和转发?

连接在默认 bridge 网络上的容器,默认只能与同一网络上的其他容器通信,无法被外部网络(包括宿主机所在的局域网或互联网)直接访问。

为了让外部能够访问容器内运行的服务(比如一个网站或一个API),我们必须进行"端口暴露和转发"。这就像是在宿主机上开了一个"窗口",外部的流量通过这个"窗口"被定向到对应的容器内部。

第一部分:端口暴露的两种方式

你提供的文档提到了两种方式:-P-p。它们都是在运行容器(docker run)时使用的参数。

  1. -P(大写P):自动暴露
  • 作用 :使用 -P 参数,Docker 会自动将容器中所有已经用 EXPOSE 指令声明过 的端口,映射到宿主机的一个随机高端口上(通常是32768以上)。

  • 特点

    • 自动性:你不需要指定具体的端口号,Docker 为你自动分配。

    • 随机性:宿主机上对应的端口是随机的。

    • 依赖 EXPOSE :它只对在 Dockerfile 中通过 EXPOSE 指令声明的端口生效。

  • 如何查看映射结果?

    使用 docker port <容器名或ID> 命令。这个命令会告诉你容器内部的端口被映射到了宿主机的哪个端口上。

示例情景

假设一个镜像的 Dockerfile 中有 EXPOSE 80。当你运行 docker run -P my-image 后,Docker 可能会将容器的 80 端口映射到宿主机的 49153 端口。此时,访问 http://宿主机IP:49153 就能访问到容器内 80 端口的服务。

  1. -p(小写p):手动指定暴露
  • 作用 :使用 -p 参数,你可以精确地指定将容器的某个端口映射到宿主机的某个端口。

  • 语法-p <hostPort>:<containerPort>

    • <hostPort>:宿主机上的端口。

    • <containerPort>:容器内部的端口。

  • 特点

    • 精确控制:你可以完全控制使用哪个宿主机端口,方便管理和记忆。

    • 灵活性高 :不依赖 Dockerfile 中的 EXPOSE 指令。即使 Dockerfile 没有 EXPOSE 80,你依然可以通过 -p 8080:80 成功映射。

示例情景

如果你想将容器的 80 端口映射到宿主机的 8080 端口,命令就是 docker run -p 8080:80 my-image。之后,访问 http://宿主机IP:8080 的流量都会被转发到容器的 80 端口。

第二部分:端口转发的工作原理

我们用文字来描述它:

  1. 初始状态:有两个容器(Container 1 和 Container 2),它们内部都运行着一个服务,开放了 80 端口。但此时,外部网络无法直接访问它们的 80 端口。

  2. 实施端口转发

    • 启动 Container 1 时,使用了 -p 8088:80。这创建了一条规则:"将所有发送到宿主机 8088 端口的网络流量,转发到 Container 1 的 80 端口"。

    • 启动 Container 2 时,使用了 -p 8089:80。这创建了另一条规则:"将所有发送到宿主机 8089 端口的网络流量,转发到 Container 2 的 80 端口"。

  3. 流量路径

    • 当用户访问 http://宿主机IP:8088 时:

      • 流量到达宿主机的 8088 端口。

      • Docker 的端口转发机制监听到这个请求。

      • 根据 -p 8088:80 的规则,Docker 将流量准确地转发给 Container 1。

      • Container 1 内部的 80 端口服务接收到请求并处理。

    • 当用户访问 http://宿主机IP:8089 时:

      • 同理,流量被 Docker 根据 -p 8089:80 的规则,转发给 Container 2 的 80 端口。

首先我们

复制代码
docker run --name test-nginx --rm -d -p 8088:80 nginx:1.22.0

现在我们去浏览器看看

七.host网络

7.1.host网络介绍

想象一下,你住在一个大公寓楼(宿主机)里。

  • 默认情况(Bridge网络模式): 公寓楼为每个租户(容器 )分配了一个带独立门牌号(IP地址 )的独立单间(Network Namespace )。如果你想从自己的房间访问楼外的互联网,或者访客想来找你,都需要经过大楼的总前台(Docker守护进程 )和统一的楼门(宿主机IP ),并由前台帮你转发(端口映射)。

    • 优点: 安全,租户之间互不干扰。

    • 缺点: 多了一道转发的工序,效率稍低。

  • Host 网络模式: 在这种模式下,你不再拥有自己的独立小单间。你就直接住在了大楼的客厅(宿主机的Network Namespace )里。你直接使用大楼的地址和门牌号(宿主机的IP和端口)。访客可以直接敲大楼的门来找你,不需要前台转接。

    • 优点: 直接、快速,没有转发开销。

    • 缺点: 缺乏隐私和隔离,如果大家都用同一个门,容易冲突。

  1. 什么是 Network Namespace?

这是理解所有 Docker 网络的基础。Namespace 是 Linux 内核提供的一种资源隔离机制

  • Network Namespace 专门用来隔离网络设备、IP 地址、端口号、路由表、防火墙规则等。

  • 默认情况下,每一个 Docker 容器在启动时,都会被分配一个独立的 Network Namespace 。这就好比给了每个容器一个独立的"网络世界",它们各自有自己的网卡、自己的 localhost(127.0.0.1),互相之间默认不直接连通。

  1. Host 网络模式打破了这种隔离

当你使用**--network=host** 参数启动一个容器时,你就是在告诉 Docker:"不要为这个容器创建新的、独立的 Network Namespace 了,就让它直接用宿主机的那个吧!"

这意味着:

  • 没有虚拟化网卡: 在默认的 Bridge 模式下,容器内会有一张虚拟的 eth0 网卡,并分配一个像 172.17.0.x 这样的私有 IP。在 Host 模式下,容器内根本看不到这张虚拟网卡 ,它看到的就是宿主机所有的物理网卡(如 ens33, eth0) 和虚拟网卡。

  • 直接使用宿主机 IP: 容器内任何网络程序绑定的 IP,实际上就是绑定了宿主机的 IP。如果你在容器里运行一个 Web 服务器并监听 80 端口,那么外界就可以通过访问 http://<宿主机IP>:80 来直接访问这个服务。

  • 端口不再隔离: 这是最关键的一点。在默认模式下,容器内的 80 端口和宿主机的 80 端口是两回事,你需要通过 -p 80:80 来做一个映射。在 Host 模式下,容器直接使用宿主机的端口空间。如果容器占用了 80 端口,那么宿主机本身就不能再使用 80 端口了,否则会造成冲突。

  1. 如何使用 Host 网络?

在运行 docker run 命令时指定**--network=host**参数即可:

bash 复制代码
# 使用 host 网络模式运行一个 Nginx 容器
docker run -d --name my-nginx --network=host nginx

运行这个命令后,Nginx 容器就会在宿主机网络环境中直接启动。你无需使用 -p 80:80 来映射端口,因为容器已经在直接使用宿主机的 80 端口了。

  1. 优缺点分析

优点:

  1. 高性能: 由于绕过了 Docker 的虚拟网桥和 NAT(网络地址转换),网络性能最高,几乎与宿主机上直接运行的进程无异。这对于对网络延迟和吞吐量要求极高的应用(如高性能计算、负载均衡器、DNS 服务器等)非常有益。

  2. 简单直接: 配置简单,不需要管理复杂的端口映射。服务在容器里监听什么端口,在外界就用什么端口访问。

缺点:

  1. 缺乏隔离性,安全性较低: 这是最大的缺点。**容器内的程序可以与宿主机上的其他程序一样,任意操作宿主机的网络栈。**例如,容器内的程序可以抓取宿主机上所有网卡的流量,或者修改宿主机的防火墙规则,这带来了潜在的安全风险。

  2. 端口冲突: 所有使用 Host 模式的容器都共享宿主机的端口池。**如果两个容器都想监听 80 端口,那么后启动的那个就会失败,因为端口已经被占用了。**在 Bridge 模式下,你可以将多个容器的 80 端口分别映射到宿主机的不同端口上(如 -p 8080:80, -p 8081:80),从而避免冲突。

  3. 灵活性差: 失去了 Docker 网络模型带来的灵活性和便利性,比如无法轻松地使用 Docker 的 DNS 服务发现功能(容器间通过名称通信)。

7.2.操作案例

首先我们创建两个容器,分别使用两个

bash 复制代码
docker run -itd --name test1 busybox:1.37

我们看一下默认的bridge网络

bash 复制代码
docker network inspect bridge

现在我们启动另外一个容器

bash 复制代码
docker run -itd --network host --name test2 busybox:1.37

我们去看看host网络的信息

bash 复制代码
docker network inspect host

现在我们分别进入容器内部看看

bash 复制代码
docker exec -it test1 sh

现在我们去看看

bash 复制代码
docker exec -it test2 sh

嗯?怎么这么多网络

现在我们到宿主机上面看看宿主机的网络信息

bash 复制代码
ifconfig

可以看到,这个test2查询到的网络信息和宿主机上的是一模一样的,也就是说test2容器完全使用的是宿主机上的网络信息。

八.Container 网络

8.1.Container 网络介绍

想象一下,公寓楼(宿主机 )里有两个租户:租户A(容器A )和租户B(容器B)。

  • 默认情况(Bridge网络模式): 每个租户都有自己的单间(Network Namespace ),有独立的门牌号(IP地址 )和内部电话(端口 )。他们通过大楼的总机(Docker网桥)与外界联系。

  • Host 网络模式: 租户直接住在大楼的客厅(宿主机的Network Namespace),使用大楼的地址和门牌。

  • Container 网络模式(other container模式): 现在,租户B(容器B )决定不自己单独住,而是去和租户A(容器A )合租,也就是说,租户B使用租户A的单间 。他们共享同一个门牌号(IP地址 )和内部电话(端口 )。但是,他们各自还有自己独立的卧室(其他Namespace,如进程、文件系统等),只是网络空间共享。

  1. 什么是 Container 网络模式?

Container 网络模式是 Docker 中一种特殊的网络模式,它允许一个容器(我们称之为"客户容器")共享另一个容器(我们称之为"目标容器")的网络命名空间(Network Namespace)。

这意味着:

  • 客户容器不会创建自己独立的网络空间,而是加入到目标容器的网络空间中。

  • 两个容器将共享同一个 IP 地址、端口空间、路由表、防火墙规则等所有网络资源。

  • 但是,两个容器的其他命名空间(如进程、文件系统、用户等)仍然是隔离的。

  1. 如何使用 Container 网络模式?

在运行 docker run 命令时,使用 **--network container:<目标容器名称或ID>**参数。

bash 复制代码
# 首先,启动一个目标容器,比如一个Nginx容器,我们命名为web-server
docker run -d --name web-server nginx

# 然后,启动一个客户容器,并共享web-server的网络命名空间
docker run -it --network container:web-server busybox sh

在这个例子中,busybox 容器将共享 web-server 容器的网络环境。在 busybox 容器内部,你可以看到与 web-server 容器相同的网络接口、IP地址等。而且,如果你在 busybox 容器中监听80端口,那么它实际上会与 web-server 容器的80端口冲突,因为它们共享端口空间。

  1. 工作原理

当两个容器共享同一个网络命名空间时,它们就像同一台机器上的两个进程一样,共享所有网络资源。

因此,它们可以通过 localhost 直接通信,因为它们共享同一个回环地址(127.0.0.1)。

同时,它们对外使用同一个IP地址,所以外界通过这个IP地址访问时,需要根据端口号来区分是访问哪个容器的服务。

  1. 优缺点分析

优点:

  1. 容器间高效通信: 共享网络命名空间的容器之间可以通过 localhost 直接通信,效率高,延迟低。

  2. 共享网络配置: 如果多个容器需要共享复杂的网络配置(例如多个进程需要监听多个端口,或者需要共享一个网络栈),这种模式可以简化配置。

  3. 资源节约: 相对于为每个容器分配独立的网络命名空间,这种模式可以减少一些网络资源(如IP地址)的消耗。

缺点:

  1. 端口冲突: 共享网络命名空间的容器共享同一个端口空间,因此不能有多个容器同时监听同一个端口,否则会造成冲突。

  2. 网络隔离性降低: 两个容器之间没有网络隔离,一个容器可以监视另一个容器的网络流量,甚至可能干扰对方的网络通信。

  3. 依赖性强: 客户容器的网络依赖于目标容器。如果目标容器停止,那么客户容器的网络也会失效。

  4. 使用场景有限: 这种模式通常用于一些特定的场景,例如:

    • Sidecar 模式:在微服务架构中,一个主容器和一个辅助容器(Sidecar)共享网络,Sidecar 容器负责为主容器提供额外的网络功能(如代理、日志收集、监控等)。

    • 需要同时运行多个进程,但又希望它们共享同一个网络环境,并且不想将它们放在同一个容器中(保持进程隔离和镜像的单一职责)。

8.2.案例

现在我们先启动一个容器

bash 复制代码
docker run -itd --name test1 busybox:1.37

现在我们去看看bridge网段的信息

bash 复制代码
docker network inspect bridge

很好,现在这个test1容器已经连上网了。

现在我们创建一个新的容器,这个新的容器是会和test1共享网络信息

bash 复制代码
docker run -itd --name test2 --network container:test1 busybox:1.37

现在我们再次去查看一下bridge网桥的信息

bash 复制代码
docker network inspect bridge

发现居然没有变化,我们现在去查看一下test2的网段的信息

bash 复制代码
docker inspect test2

可以看到test2的网络配置是空的。

现在我们来查看一下两个容器的IP信息

先看test1的

bash 复制代码
docker exec -it test1 sh

我们再去看看test2的

bash 复制代码
docker exec -it test2 sh

我们仔细对比一下,是不是一模一样!!!

也就是说test2就是使用了test1的网络信息。

现在我们停止test1容器

bash 复制代码
docker stop test1

现在我们再次进入test2容器看看IP信息

bash 复制代码
docker exec -it test2 sh

我们发现只剩本地回环了!!

现在我们回去重启test1容器

bash 复制代码
docker restart test1
docker restart test2

现在我们再去看看test2的网络信息

bash 复制代码
docker exec -it test2 sh

现在又恢复了网络!!!

九.none网络

什么是none网络?

在Docker中,none网络是一种特殊的网络模式,当容器使用none网络时,它不会配置任何网络栈。

也就是说,容器内除了lo(本地回环)网卡外,没有其他任何网卡(如eth0等)。

这意味着容器与外界是网络隔离的,它无法与外部网络(包括其他容器、宿主机以及互联网)进行通信。

如何使用none网络?

在运行容器时,通过指定**--network=none**参数来使用none网络。

示例:

bash 复制代码
docker run -it --network=none ubuntu:20.04 /bin/bash

进入容器后,可以使用ip addr命令查看网络设备,你会看到只有lo网卡。

none网络的特点

  1. 网络隔离:容器处于一个完全隔离的网络环境中,无法进行任何网络通信(除了本地回环)。

  2. 安全性:由于没有网络连接,这种模式提供了最高级别的网络隔离,适用于需要绝对安全隔离的场景。

  3. 自定义网络配置:用户可以在容器内部手动配置网络,以满足特定需求。但请注意,容器内配置网络通常需要特权模式(因为需要配置网卡、路由等)


话不多说,我们看例子

bash 复制代码
docker run -itd --network=none --name test3 busybox:1.37

这个时候我们可以去看看none网段的信息

bash 复制代码
docker network inspect none

怎么样?是不是就有我们的test3

现在我们进入test3看看

bash 复制代码
docker exec -it test3 sh

只有本地回环网络了。

我们试一下访问外部网络

访问不了外部网络,那么宿主机呢?

我们回到宿主机,执行下面这个命令

bash 复制代码
ifconfig

我们试着去访问宿主机的docker0和eth0

发现都是不行的。

相关推荐
爱宇阳2 小时前
Java Spring Boot 项目 Docker 容器化部署教程
java·spring boot·docker
爱宇阳3 小时前
从容器化到自动化:Vue3 项目 Docker 部署与 GitLab CI/CD 集成 Harbor 全流程
docker·自动化·gitlab
Grass Router 小草聚合路由3 小时前
GrassRouter融合通信设备-多链路聚合路由在各行业的应急网络中的重要作用和解决方案
网络·多链路聚合·应急保障设备·多链路聚合通信设备·聚合路由·多卡聚合通信设备·5g聚合路由设备
高旭博3 小时前
10. kubernetes资源——statefulset有状态负载
云原生·容器·kubernetes
我就是一粒沙4 小时前
网络安全培训
网络·安全·web安全
_Walli_4 小时前
k8s集群搭建(七)-------- 微服务间的调用
微服务·容器·kubernetes
马达加斯加D4 小时前
k8s --- resource: Pod, ReplicaSet and Deployment
云原生·容器·kubernetes
tang777895 小时前
对抗高级反爬:基于动态代理 IP 的浏览器指纹模拟与轮换策略
网络·网络协议·tcp/ip
oil欧哟5 小时前
Agent 设计与上下文工程- 02 Workflow 设计模式(上)
前端·网络·人工智能