第5章 网络
摘要 :本章系统讲解 Docker 网络的核心原理与实战操作。首先介绍
none与host两种特殊网络的适用场景;随后深入bridge网络,剖析docker0网桥、veth-pair虚拟网卡对的工作机制;接着讲解如何自定义容器网络(含静态 IP 分配)、容器间连通性规则(同网络互通、跨网络隔离)以及三种容器通信方式(IP、Docker DNS、joined 容器);最后分别阐述容器访问外网(MASQUERADE 源地址伪装)与外部访问容器(端口映射 + docker-proxy)的底层原理,并以 Tomcat 镜像定制为例串联端口映射与镜像构建实战。
1、none和host网络的适用场景
Docker 安装时会自动在 host 上创建三个网络,我们可用 docker network ls 命令查看:

1.1 none
none 网络就是什么都没有的网络。
挂在这个网络下的容器**除了 lo,没有其他任何网卡**。
容器创建时,可以通过 --network=none 指定使用 none 网络。

none网络的driver类型是null,IPAM字段为空。挂在none网络上的容器只有lo,无法与外界通信。
示例:
bash
[root@docker ~]# docker run -it --network=none busybox
/ #
/ # ifconfig-----只有一个lo环回
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
/ # hostname
4027da12afaf
应用场景:
- (封闭意味着隔离)一些对安全性要求高 并且不需要联网的应用可以使用 。
比如某个容器的唯一用途是生成随机密码,就可以放到 none 网络中避免密码被窃取。
1.2 host
挂在host网络上的容器共享宿主机的network namespace 。即**容器的网络配置与host网络配置完全一样**。

连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样。
可以通过 --network=host 指定**使用 host 网络。
示例:
bash
docker run -it --network=host busybox #容器网络与宿主机相同
/ #
/ # ip l---看到有多个网卡
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000
link/ether 00:0c:29:33:15:f6 brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
link/ether 02:42:02:fd:82:b3 brd ff:ff:ff:ff:ff:ff
/ #
/ # hostname #容器主机与宿主机相同
docker
/ #
优点:性能好
缺点:牺牲一些灵活性。比如要考虑端口冲突问题,Docker host 上已经使用的端口不能再用。
应用场景:
-
容器对网络传输效率有较高要求。
-
让容器可以直接配置 host 网路。比如某些跨 host 的网络解决方案,其本身也是以容器方式运行的,这些方案需要对网络进行配置,比如管理 iptables。
2、bridge网络
知识补充:
选择vmnet1,虚拟机和虚拟机可以通,主机和虚拟机也能通,但不能上网。

选择vmnet8,虚拟机和虚拟机可以通,还能上网(通过路由器)

2.1 Bridge网桥概念
bridge就是虚拟二层交换机。
Docker 安装时会创建一个 命名为 docker0 的 linux bridge。
只要启动容器没有特别指定网络,所有容器都会连接到docker0网桥。
2.2 veth‑pair(虚拟网卡对)

Docker 就创建了在主机和所有容器之间一个虚拟共享网络
每启动一个容器,Docker就会生成一对veth‑pair虚拟网卡:
-
一端在容器内即 eth0;
-
另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)
veth‑pair相当于一根虚拟网线,把容器eth0 和 docker0网桥连接起来。
通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。
2.3 docker0 网桥工作过程
- 容器启动,创建veth‑pair,一端挂docker0,另一端作为容器eth0网卡。
- docker0会给容器分配属于docker0网段的IP地址,docker0的IP就是容器的网关。
- 同一个docker0上的多个容器: 容器之间通过docker0二层交换,使用IP地址可以互相通信。
- 同docker0上容器之间、宿主机和容器之间可以互通;docker0无内置DNS,只能用IP通信,不能直接用容器名ping。
- 流量转发原理
- 容器访问外网:宿主机iptables
SNAT/MASQUERADE源地址伪装,替换容器内网IP为宿主机IP。 - 外部物理机访问容器:必须
‑p端口映射,iptables DNAT做目标地址转换;宿主机本机可直接访问容器内网IP,无需‑p。
- 容器访问外网:宿主机iptables
- 外部物理机不能直接访问容器的172.x.x.x内网IP

2.4 实验步骤
- 配置yum源,安装
bridge‑utils网桥查看工具。 - 执行
brctl show,初始状态docker0网桥interfaces为空,无挂载网卡。 - 后台运行busybox容器:
docker run ‑itd ‑‑name busybox1 busybox。 - 再次执行
brctl show,观察宿主机出现veth开头网卡,已经挂载到docker0网桥。 docker exec ‑it busybox1 sh进入容器,容器内执行ip a,查看eth0网卡以及@if对端编号,确认veth‑pair配对关系。- 测试同网桥容器IP互通;测试ping容器名字,验证docker0没有DNS解析。
2.5 重要命令
bash
#安装网桥工具
cd /etc/yum.repos.d/
vim cloud.repo
yum install -y bridge-utils
#查看宿主机网桥及挂载网卡
brctl show
#查看docker0网桥详细信息(网段、网关)
docker network inspect docker0
#后台创建测试容器
docker run -itd --name busybox1 busybox
#进入容器
docker exec -it busybox1 sh
#容器内查看网卡
ip a
#宿主机查看本机网卡
ip addr
关键考点总结
- docker0只是虚拟交换机,不是物理硬件。
- veth‑pair一定成对出现,容器删除,宿主机对应的veth网卡自动销毁。
- docker0不支持容器名DNS解析,仅IP通信。
- 外部物理机访问容器必须
‑p端口映射;宿主机本机访问容器内网IP不需要端口映射。 - 容器访问外网依赖宿主机iptables SNAT/MASQUERADE地址伪装。
brctl show需要提前安装bridge‑utils工具包才可以使用。
3、如何自定义容器网络
Docker除内置的none、host、bridge三种默认网络,支持用户创建自定义user-defined网络;自定义网络驱动有bridge、overlay、macvlan,其中overlay、macvlan用于跨主机容器网络,本节主要讲解单机自定义bridge网络。
3.1 创建自定义bridge网络(自动分配网段)
- 命令:
docker network create --driver bridge my_net - 执行后宿主机新增独立网桥(名称为网络ID缩写,如
br-89f7bc11b602)。 - 查看网络信息:
docker network inspect my_net,Docker自动分配子网与网关。 - 查看宿主机网桥列表:
brctl show,可看到新建网桥。
3.2 创建自定义bridge网络(手动指定子网与网关)
-
可通过--subnet、--gateway参数,手动定义网段和网关。
docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net2 -
执行后宿主机生成对应网桥
br-ec761bc51778,网关配置在该网桥网卡上。 -
容器使用该网络:启动容器增加参数--network=my_net2,容器自动从指定网段获取IP。
docker run -it --network=my_net2 --name busybox2 busybox
3.3 容器指定静态IP
-
使用--ip参数给容器分配静态IP。
docker run -it --network=my_net2 --ip 172.22.16.8 --name busybox3 busybox -
⚠️重要限制:只有创建网络时使用
--subnet手动指定网段的自定义网络,才支持静态IP;自动分配网段的自定义网络不能使用--ip,会直接报错。
3.4 核心命令汇总
- 创建自定义网络:
docker network create --driver bridge [--subnet 网段 --gateway 网关] 网络名 - 查看所有网络:
docker network ls - 查看网络详细配置:
docker network inspect 网络名 - 查看宿主机网桥:
brctl show - 指定网络启动容器:
docker run --network=网络名 镜像 - 指定静态IP启动容器:
docker run --network=网络名 --ip 静态IP 镜像
3.5 核心考点提炼
- 自定义网络三种驱动:bridge(单机桥接)、overlay、macvlan(后两者用于跨主机)。
- 创建自定义bridge网络,宿主机生成独立网桥,每个自定义bridge是独立二层网络。
- 静态IP前提:创建网络时必须用--subnet声明网段,否则无法使用--ip指定静态IP。
- 容器接入自定义网络,启动时加
--network参数。
4、理解容器之间的连通性
本节讲解Docker桥接网络的通信规则:同网络容器互通,不同网络默认隔离,以及跨网络通信的实现方案。
4.1 同一自定义网络内容器互通
- 拓扑:
my_net2自定义网桥下挂载busybox2、busybox3两个容器。 - 实验验证:
- 在busybox2内ping busybox3的IP,可正常连通;
- 同时可以ping通
my_net2网关地址。
- 结论:挂载在同一个bridge网络中的容器之间、容器与网关之间可以直接通信。
4.2 不同Docker网络默认相互隔离
- 测试场景:my_net2(自定义网桥) 和 默认docker0(默认bridge)属于两个独立网桥。
- busybox2(my_net2)ping busybox1(docker0),100%丢包,无法通信。
- 疑问:宿主机路由表已经存在两条网段路由,并且
net.ipv4.ip_forward=1(开启IP转发),为什么不通? - 根本原因:Docker自动在iptables中添加DOCKER-ISOLATION隔离规则,直接DROP掉不同网桥之间双向流量。Docker设计上默认隔离不同网络。
4.3 跨网络通信解决方案
-
方案原理:给容器新增一块网卡,将容器同时接入多个网络。
-
核心命令:
docker network connect <网络名> <容器名>- 示例:
docker network connect my_net2 busybox1 - 执行后,busybox1容器新增一块网卡eth1,分配my_net2网段IP。
- 示例:
-
验证结果:busybox1同时存在两个网卡,分别属于docker0和my_net2;此时busybox2可以成功ping通busybox1。
4.4 关键命令汇总
- 查看宿主机路由表:
ip r - 查看内核IP转发状态:
sysctl net.ipv4.ip_forward - 查看iptables完整规则:
iptables-save - 查看网桥信息:
brctl show - 将已有容器接入指定网络:
docker network connect 网络名 容器名 - 查看容器内网卡与IP:
docker exec -it 容器名 ip a - 容器内连通性测试:
ping -c 3 目标IP
4.5 核心考点提炼
- 同网络:同一bridge网络内的容器默认互通。
- 跨网络:不同Docker网络默认隔离,不是路由问题,是iptables DOCKER-ISOLATION隔离策略,即使宿主机开启ip转发也不通。
- 跨网络通信方法:用
docker network connect把容器同时加入多个网络,容器多网卡实现跨网络访问。 - 每个自定义bridge是独立二层网络,互相隔离。
5、容器通信的三种方式
容器之间通信一共有3种方案:IP通信、Docker DNS Server、joined容器(共享网络栈)。
5.1 IP通信
- 前提条件 :两个容器必须接入同一个网络,拥有同网络的网卡,才可以直接使用IP互相访问。
- 使用方法:
- 创建容器时,用
--network参数直接指定自定义网络; - 已有容器,使用
docker network connect命令把容器加入目标网络。
- 创建容器时,用
- 原理:同网段二层互通,直接依靠容器IP完成网络交互。
5.2 Docker DNS Server(容器名通信)
-
作用:解决IP不固定的问题,可以直接使用容器名称通信,不需要硬编码IP。Docker 1.10版本后内置内嵌DNS服务。
-
使用方法:启动容器时,用--name给容器命名,多个容器接入
同一个用户自定义网络,即可直接ping容器名。
- 示例:
docker run -it --network my_net2 --name bbox1 busybox - 在同网络另一个容器里:
ping bbox1,DNS自动解析为容器IP。
- 示例:
-
⚠️重要限制:
Docker DNS只支持用户自定义网络,默认bridge(docker0)网络不支持容器名解析。
- 验证:在默认bridge网络创建bbox3、bbox4,执行
ping bbox3会提示bad address,无法解析。
- 验证:在默认bridge网络创建bbox3、bbox4,执行
5.3 joined容器(共享网络栈)
- 核心特点:多个容器共享同一个网络栈,共用网卡、IP、路由等全部网络配置。
- 多个容器使用同一个IP;容器之间可以直接通过
127.0.0.1互相访问。
- 多个容器使用同一个IP;容器之间可以直接通过
- 使用参数:
--network=container:容器名/容器ID - 实验流程:
- 先启动基础容器
web1(httpd); - 新建busybox容器,添加参数
--network=container:web1,让busybox共享web1的网络栈; - 两个容器IP完全相同,busybox可以用
127.0.0.1访问web1里面的服务。
- 先启动基础容器
- 适用场景:多个容器需要共用同一个端口,互相本地访问,不需要额外端口映射。
5.4 三种通信方式对比总结
| 通信方式 | 要点 | 限制 |
|---|---|---|
| IP通信 | 同网络,通过IP互通 | IP不固定,不方便动态部署 |
| Docker DNS Server | 用容器名字通信,内置DNS | 仅自定义网络可用,默认bridge不行 |
| joined容器 | 共享网络栈,共用IP,127.0.0.1互访 | 多个容器不能占用相同端口 |
5.5 核心命令汇总
- 指定网络创建容器:
docker run --network 网络名 --name 容器名 镜像 - 将已有容器加入网络:
docker network connect 网络名 容器名 - joined容器共享网络栈:
docker run --network=container:web1 busybox - 进入容器执行命令:
docker exec -it 容器名 sh
5.6 核心考点提炼
- 容器互通的基础前提:在同一个网络。
- DNS容器名解析的关键:必须是用户自定义网络,默认docker0桥接网络不支持DNS解析。
- joined容器本质:共享网络命名空间,共用IP,容器之间用127.0.0.1通信。
6、容器如何访问外部世界(容器访问互联网)
Docker容器网络通信分为两大方向:容器访问外部世界 、外部世界访问容器。本节讲解容器主动访问外部网络的原理。
6.1 现象:容器默认可以访问外网
- 实验验证:宿主机能连通外网;启动busybox容器,在容器内部执行
ping www.baidu.com,可正常收到响应,证明容器默认就能访问外部网络。 - 概念说明:这里的"外网"指容器网络之外的网络环境,不单单指互联网,也包含宿主机其他网段、局域网。
6.2 底层核心:iptables NAT(MASQUERADE源地址转换)
-
容器默认接入
docker0网桥,网段172.17.0.0/16,容器IP属于私有内网地址,公网无法直接路由。 -
Docker自动在宿主机iptables的nat表添加POSTROUTING规则:
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-
规则含义:源IP属于172.17.0.0/16网段,且数据包不是从docker0网卡出去时,执行MASQUERADE(源地址伪装NAT),把数据包的源IP替换成宿主机出口网卡IP。
6.3 数据包转发完整流程(ping案例)
- 容器(IP:172.17.0.2)发出ping请求包,源地址为容器内网IP,数据包到达docker0网桥。
- 宿主机匹配iptables NAT规则,执行MASQUERADE,把报文源IP修改为宿主机网卡ens160的公网IP(192.168.108.30)。
- 修改后的数据包通过宿主机默认路由,从ens160网卡发送到外网目标服务器。
- 外网服务器返回响应包,目标IP是宿主机ens160地址。
- 宿主机根据NAT会话记录,把返回包目的IP改回容器内网IP,经docker0网桥转发回容器。
6.4 抓包验证实验(tcpdump)
- 安装工具:
yum install -y tcpdump - 同时在两个网卡抓ICMP(ping)报文:
- 抓docker0网卡:
tcpdump -i docker0 -n icmp,能看到原始源IP:172.17.0.2 - 抓宿主机物理网卡ens160:
tcpdump -i ens160 -n icmp,看到源IP已经替换成宿主机IP 192.168.108.30
- 抓docker0网卡:
- 抓包结果直观证明:NAT在宿主机上完成源地址替换。
6.5 关键命令汇总
- 查看nat表iptables规则:
iptables -t nat -S - 查看宿主机路由表:
ip r - 抓包命令:
tcpdump -i 网卡名 -n icmp - 测试连通性:
ping -c 3 目标地址,-c 3代表发送3个包后停止
6.6 核心考点提炼
- 容器访问外网的核心技术:MASQUERADE源NAT地址伪装,由宿主机iptables实现。
- 容器内网网段:
172.17.0.0/16,docker0网桥。 - 数据包变化:容器发出报文源IP为容器内网IP;经过宿主机NAT之后,出外网时源IP变成宿主机网卡IP。
- 前提:宿主机本身能访问外网,NAT规则由Docker服务自动创建。
- 容器访问外网:源NAT(MASQUERADE),容器主动向外发包
- 外部访问容器:端口映射+docker-proxy,外部主动访问宿主机端口,转发到容器
容器能ping通网关,但是无法访问外网:优先检查ip_forward内核参数、nat POSTROUTING伪装规则、filter FORWARD链。
7、外部世界如何访问容器
核心:端口映射(-p参数),把容器内服务端口绑定到宿主机端口,外部网络访问宿主机IP+宿主机端口,流量转发到容器内部端口。
7.1 端口映射基础原理
Docker通过端口映射,将容器对外提供服务的端口映射到宿主机(host)的端口,外部网络通过访问宿主机IP:映射端口 访问容器里的服务;端口映射在容器启动时通过-p参数配置。
- 动态端口映射:docker run -d -p 80 httpd
- 只指定容器端口80,宿主机自动随机分配一个空闲端口(示例中32768)。
- 查看端口映射:
docker ps或者docker port 容器ID。 - 访问方式:
宿主机IP:随机端口,示例192.168.108.30:32768。
- 指定固定端口映射:docker run -d -p 8080:80 httpd
- 格式:
宿主机端口:容器端口,宿主机8080端口映射容器80端口。 - 访问方式:
宿主机IP:8080。
- 格式:
7.2 流量转发机制
宿主机每配置一个映射端口,会启动docker-proxy进程处理流量转发,配合NAT、docker0网桥完成通信。 以0.0.0.0:8080->80/tcp为例:
docker-proxy监听宿主机的8080端口;- 外部客户端访问
192.168.108.30:8080,请求到达宿主机; docker-proxy接收请求,把流量转发给对应容器172.17.0.3:80;- 容器内httpd服务处理请求,响应数据原路返回给客户端。
7.3 网络拓扑简述
- 外网请求 → 宿主机网卡ens160(192.168.108.30) → docker-proxy → docker0网桥(172.17.0.1) → NAT转发 → 容器(172.17.0.3);
- 容器回复报文,经过NAT转换,原路返回外网客户端。
7.4 验证命令
- 查看运行容器与端口映射:
docker ps - 单独查看容器端口映射关系:
docker port 容器ID - 测试访问容器服务:
curl 宿主机IP:映射端口。
关键考点提炼
- 外部访问容器核心技术:端口映射 -p
-p两种写法:-p 容器端口(宿主机随机端口);-p 宿主机端口:容器端口(固定端口映射)- 流量转发核心进程:docker-proxy,负责监听宿主机端口并转发流量到容器
- 查看端口映射命令:
docker ps、docker port
8、tomcat
Tomcat 是 Apache 基金会的**开源轻量级 Servlet 容器(Web 应用服务器)**,用来运行 Java Web 项目(Servlet、JSP),自带简易 HTTP 服务。


--rm(红框,考点!)
含义:容器停止 / 退出之后,自动删除这个容器 ----只删容器,不删镜像。
✅作用:测试用,用完自动清理,不会残留无用容器;生产环境不要用
思考:我想要基于tomcat镜像做出一个能够直接访问的tomcat镜像该如何做?
原理
官方tomcat镜像默认webapps文件夹是空的 ,所以浏览器访问会404。 我们要把网页项目放入webapps,再打包成新镜像,以后run这个新镜像就能直接打开页面。 两种方式:Dockerfile方式(推荐,答辩必考)、docker commit提交容器方式。
方式1:Dockerfile(首选,必背)
1. 新建目录,准备素材
bash
mkdir mytomcat
cd mytomcat
把你的网页(index.html或者war包)放到这个文件夹。
2. 创建Dockerfile(文件名就叫Dockerfile,无后缀)
bash
# 基础镜像:用官方tomcat9
FROM tomcat:9.0
# 把当前目录的网页,复制到容器内tomcat的webapps目录
COPY index.html /usr/local/tomcat/webapps/
如果是war包:
COPY test.war /usr/local/tomcat/webapps/
💡 路径考点:容器里tomcat的webapps真实路径是/usr/local/tomcat/webapps
3. 构建镜像
bash
docker build -t mytomcat:v1 .
-t mytomcat:v1:给新镜像起名mytomcat,版本v1- 最后的
.:代表Dockerfile在当前目录
4. 启动容器,端口映射
bash
docker run -itd -p 8080:8080 mytomcat:v1
访问:宿主机IP:8080,直接看到你的网页,不再404!
方式2:docker commit(实验临时用,不推荐生产)
适合课堂实操:先启动tomcat容器,进入容器手动放入网页,再把这个容器打包成镜像。
bash
# 1.启动tomcat容器
docker run -itd -p 8080:8080 --name tomcat01 tomcat:9.0
# 2.进入容器
docker exec -it tomcat01 bash
# 3.进入webapps目录,新建index.html网页
cd /usr/local/tomcat/webapps
echo "hello tomcat" > index.html
exit
#4.把这个正在运行的容器,提交生成新镜像
docker commit tomcat01 mytomcat:v2
之后docker run这个mytomcat:v2镜像,访问就能看到页面。
注意:
- 官方tomcat镜像webapps为空,访问404,所以需要放入网页资源再打包。
- Dockerfile的
FROM指定基础镜像,COPY用来拷贝本地文件到镜像内。 docker build构建镜像;docker commit基于容器提交生成镜像。- 区分:Dockerfile是标准方式,可复用;commit是临时打包,不适合项目
- 不要写错容器内路径
/usr/local/tomcat/webapps - build命令末尾的
.不能漏掉! - 启动容器记得加
-p端口映射,否则外部浏览器访问不到
01 tomcat:9.0
2.进入容器
docker exec -it tomcat01 bash
3.进入webapps目录,新建index.html网页
cd /usr/local/tomcat/webapps
echo "hello tomcat" > index.html
exit
#4.把这个正在运行的容器,提交生成新镜像
docker commit tomcat01 mytomcat:v2
之后`docker run`这个mytomcat:v2镜像,访问就能看到页面。
注意:
1. 官方tomcat镜像webapps为空,访问404,所以需要放入网页资源再打包。
2. Dockerfile的`FROM`指定基础镜像,`COPY`用来拷贝本地文件到镜像内。
3. `docker build`构建镜像;`docker commit`基于容器提交生成镜像。
4. 区分:**Dockerfile是标准方式,可复用;commit是临时打包,不适合项目**
- 不要写错容器内路径 `/usr/local/tomcat/webapps`
- build命令末尾的`.`不能漏掉!
- 启动容器记得加 `-p`端口映射,否则外部浏览器访问不到