【网络运维】Docker网络:基础与实战

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通信

要求容器有属于同一网络的网卡,可通过--networkdocker 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

数据流路径

  1. 容器发送:172.17.0.2 → www.baidu.com
  2. docker0接收并交给NAT处理
  3. NAT转换:192.168.108.30 → www.baidu.com
  4. 通过宿主机网卡发送到外网

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网络的核心概念:

  1. 网络类型:none、host、bridge三种原生网络各有适用场景
  2. 网络创建:支持自定义bridge网络,可指定子网、网关和静态IP
  3. 容器通信:IP、DNS、joined容器三种方式满足不同需求
  4. 内外互通:通过NAT实现容器访问外网,通过端口映射实现外部访问容器
  5. 实战应用:Tomcat部署展示了网络配置的实际应用

理解Docker网络机制对于构建稳定、高效的容器化应用至关重要。在实际应用中,应根据具体需求选择合适的网络模型,平衡性能、安全性和灵活性。

相关推荐
A小辣椒1 天前
TShark:Wireshark CLI 功能
linux
A小辣椒2 天前
TShark:基础知识
linux
AlfredZhao2 天前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao2 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334663 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪3 天前
linux 拷贝文件或目录到指定的位置
linux
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush43 天前
嵌入式linux学习记录十四、术语
linux·嵌入式