Docker网络:基础与实战
Docker网络是容器化技术中至关重要的组成部分,它决定了容器之间以及容器与外部世界的通信方式。本章将系统性地介绍Docker原生网络类型、自定义网络的创建方法、容器间通信的三种方式,以及容器内外网络流量的处理机制。通过实际操作演示,帮助读者深入理解Docker网络的工作原理。
Docker原生网络类型
Docker安装时会自动创建三种默认网络,可通过docker network ls命令查看:
bash
[root@docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
a1b809382f0d bridge bridge local
6ad21ed9ea1f host host local
4e31521b27c6 none null local
1. none网络
- 驱动类型:null
- 特点:容器只有lo回环接口,完全隔离,无法与外界通信
- 适用场景:安全性要求高、无需联网的容器(如密码生成器)
- 创建方式 :
docker run -it --network=none busybox

bash
[root@docker ~]# docker run -it --network=none busybox
/ #
/ # ifconfig
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
2. host网络
- 特点:容器共享宿主机网络命名空间,网络配置与宿主机完全相同
- 优点:网络性能最佳,无需NAT转换
- 缺点:存在端口冲突风险
- 适用场景:对网络性能要求高的应用;需要直接配置宿主机网络的场景
bash
[root@docker ~]# 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
/ #
Bridge网络详解
1. 默认bridge网络
Docker安装时创建名为docker0的Linux网桥,未指定网络的容器默认连接到此网桥。
网络拓扑结构:
容器eth0 <--veth pair--> docker0网桥 <--> 宿主机网络

验证实验:
bash
# 安装桥接工具
[root@docker ~]# yum install -y bridge-utils
# 查看初始网桥状态
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02420be905a5 no
# 创建容器后再次查看
[root@docker ~]# docker run -itd --name busybox1 busybox
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02420be905a5 no vethddb2744
2. veth pair原理
veth pair是一对虚拟网卡,像被虚拟网线连接:
- 一端在容器内(如
eth0@if25) - 另一端在宿主机并连接到网桥(如
vethddb2744)
bash
# 容器内查看网卡
24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
# 宿主机查看对应网卡
25: vethddb2744@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
3. 网络配置信息
bash
[root@docker ~]# docker network inspect bridge
[
{
"Name": "bridge",
"IPAM": {
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
}
}
]
# 验证网关
[root@docker ~]# ip a | grep docker0
3: docker0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state UP
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
自定义容器网络
1. 创建自定义bridge网络
bash
# 创建默认配置的网络
[root@docker ~]# docker network create --driver bridge my_net
# 创建指定子网和网关的网络
[root@docker ~]# docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net2
2. 查看网络结构
bash
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-89f7bc11b602 8000.0242194d039e no # my_net
br-ec761bc51778 8000.02427fa54b88 no # my_net2
docker0 8000.02420be905a5 no vethddb2744
3. 指定静态IP
注意 :只有使用--subnet创建的网络才能指定静态IP
bash
[root@docker ~]# docker run -it --network=my_net2 --ip 172.22.16.8 --name busybox3 busybox
# 验证IP配置
30: eth0@if31: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:16:10:08 brd ff:ff:ff:ff:ff:ff
inet 172.22.16.8/24 brd 172.22.16.255 scope global eth0
容器间连通性分析
1. 同一网络内的通信
bash
# busybox2 ping busybox3(同属my_net2)
[root@docker ~]# docker exec -it busybox2 sh
/ # ping -c 3 172.22.16.8
PING 172.22.16.8 (172.22.16.8): 56 data bytes
64 bytes from 172.22.16.8: seq=0 ttl=64 time=0.197 ms
2. 不同网络间的隔离
默认情况下,不同bridge网络的容器无法通信:
bash
# busybox2(my_net2)ping busybox1(docker0)
[root@docker ~]# docker exec -it busybox2 sh
/ # ping -c 3 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
隔离原因:iptables规则DROP不同网桥间的流量
bash
-A DOCKER-ISOLATION-STAGE-2 -o br-ec761bc51778 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
3. 跨网络通信解决方案
为容器添加多块网卡实现跨网络通信:
bash
# 为busybox1添加my_net2网卡
[root@docker ~]# docker network connect my_net2 busybox1
# 验证新增网卡
32: eth1@if33: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:16:10:03 brd ff:ff:ff:ff:ff:ff
inet 172.22.16.3/24 brd 172.22.16.255 scope global eth1
# 现在可以跨网络通信
/ # ping -c 3 172.22.16.3
64 bytes from 172.22.16.3: seq=0 ttl=64 time=0.199 ms
容器通信的三种方式
1. IP通信
要求容器有属于同一网络的网卡,可通过--network或docker network connect实现。
2. Docker DNS Server
- Docker 1.10+版本内置DNS服务器
- 通过容器名直接通信
- 限制:仅限user-defined网络
bash
# 使用容器名通信
[root@docker ~]# docker exec -it bbox2 sh
/ # ping -c 3 bbox1
PING bbox1 (172.22.16.2): 56 data bytes
64 bytes from 172.22.16.2: seq=0 ttl=64 time=0.177 ms
# 默认bridge网络不支持DNS
/ # ping -c 3 bbox3
ping: bad address 'bbox3'
3. Joined容器
共享网络栈,通过127.0.0.1通信
bash
# 创建joined容器
[root@docker ~]# docker run -it --network container:web1 busybox
# 验证网络配置(与web1完全相同)
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
# 通过localhost访问服务
/ # wget 127.0.0.1
Connecting to 127.0.0.1 (127.0.0.1:80)
适用场景:
- Web服务器与应用服务器间的本地通信
- 网络监控容器监控其他容器的流量
容器与外部世界通信
1. 容器访问外部世界
默认通过NAT实现:
bash
# docker host测试外网访问
[root@docker ~]# ping -c 3 www.baidu.com
PING www.baidu.com (223.109.82.6) 56(84) bytes of data.
64 bytes from 223.109.82.6 (223.109.82.6): icmp_seq=1 ttl=128 time=67.8 ms
64 bytes from 223.109.82.6 (223.109.82.6): icmp_seq=2 ttl=128 time=13.0 ms
64 bytes from 223.109.82.6 (223.109.82.6): icmp_seq=3 ttl=128 time=12.5 ms
--- www.baidu.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 12.454/31.074/67.754/25.937 ms
# 容器内测试外网访问
[root@docker ~]# docker run -it --name test1 busybox
/ # ping -c 3 www.baidu.com
PING www.baidu.com (223.109.82.6): 56 data bytes
64 bytes from 223.109.82.6: seq=0 ttl=127 time=21.240 ms
NAT转换过程:
bash
# 查看NAT规则
[root@docker ~]# iptables -t nat -S
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
# tcpdump验证地址转换
# docker0接口:源地址为容器IP
15:23:42.854951 IP 172.17.0.2 > 223.109.82.41: ICMP echo request
# ens160接口:源地址变为宿主机IP
15:25:41.886472 IP 192.168.108.30 > 223.109.82.41: ICMP echo request
数据流路径:
- 容器发送:172.17.0.2 → www.baidu.com
- docker0接收并交给NAT处理
- NAT转换:192.168.108.30 → www.baidu.com
- 通过宿主机网卡发送到外网
2. 外部世界访问容器
通过端口映射实现:
bash
# 动态端口映射
[root@docker ~]# docker run -d -p 80 httpd
[root@docker ~]# docker ps
PORTS
0.0.0.0:32768->80/tcp
# 指定端口映射
[root@docker ~]# docker run -d -p 8080:80 httpd
[root@docker ~]# curl 192.168.108.30:8080
<html><body><h1>It works!</h1></body></html>
实现机制:docker-proxy进程监听宿主端口并转发到容器
bash
# 查看docker-proxy进程
[root@docker ~]# ps aux | grep docker-proxy
root 12345 0.0 0.1 123456 7890 ? Sl 10:00 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8080 -container-ip 172.17.0.3 -container-port 80
实战:Tomcat容器部署
1. 拉取并运行Tomcat
bash
# 搜索Tomcat镜像
[root@docker ~]# docker search tomcat
# 拉取镜像
[root@docker ~]# docker pull tomcat
# 运行容器
[root@docker ~]# docker run -itd -p 8080:8080 tomcat
92d78922526ba2a54ef63c48d2fec80b10997027de93457a4e2d56d7ea7448e2
访问tomcat首页

首页报错,应用目录出现问题。
2. 解决Web应用目录问题
bash
# 进入容器
[root@docker ~]# docker exec -it 92d bash
# 查看目录结构(webapps为空)
root@92d78922526b:/usr/local/tomcat# ls webapps
# 修复:用webapps.dist替换webapps
root@92d78922526b:/usr/local/tomcat# rm -r webapps
root@92d78922526b:/usr/local/tomcat# mv webapps.dist webapps
3. 访问验证
通过http://宿主机IP:8080访问Tomcat管理界面
总结
本文系统探讨了Docker网络的核心概念:
- 网络类型:none、host、bridge三种原生网络各有适用场景
- 网络创建:支持自定义bridge网络,可指定子网、网关和静态IP
- 容器通信:IP、DNS、joined容器三种方式满足不同需求
- 内外互通:通过NAT实现容器访问外网,通过端口映射实现外部访问容器
- 实战应用:Tomcat部署展示了网络配置的实际应用
理解Docker网络机制对于构建稳定、高效的容器化应用至关重要。在实际应用中,应根据具体需求选择合适的网络模型,平衡性能、安全性和灵活性。
