容器网络概述

Docker 容器在运行时,需要与宿主机、其他容器以及外部网络进行通信。Docker 通过 网络驱动(Network Driver) 机制为容器提供灵活的网络配置能力。每个容器在创建时都会被分配一个网络命名空间(Network Namespace),从而实现网络层面的隔离。

Docker 的网络架构核心组件包括:

  • Network Namespace:为每个容器提供独立的网络栈(网卡、路由表、iptables 规则等)。
  • Veth Pair:虚拟以太网设备对,用于连接容器与宿主机网桥(如 docker0)。
  • Linux Bridge:虚拟交换机(如 docker0),负责同一宿主机内容器间的二层转发。
  • NAT / iptables:实现容器访问外网及端口映射(-p 参数)。

容器网络种类

Docker 支持多种网络模式,适用于不同的使用场景:

网络模式驱动(Driver)说明典型场景
Bridge(桥接)bridgeDocker 默认网络模式。容器通过虚拟网桥 docker0 互联,经 NAT 访问外网。每个容器拥有独立 IP(默认 172.17.0.0/16)。单机多容器通信、开发测试环境
Host(主机)host容器与宿主机共享网络命名空间,无独立网卡和 IP,直接使用宿主机网络栈。性能最高,但存在端口冲突风险。对网络性能要求极高、无需网络隔离的服务(如监控 Agent)
Container(容器复用)container新容器与指定容器共享网络栈(IP、端口),但文件系统和进程仍然隔离。类似 Pod 中多容器共享网络的概念。Sidecar 模式、网络调试
None(无网络)null容器仅拥有 lo 回环网卡,无任何外部网络连接。完全隔离。安全沙箱、纯计算任务、离线处理
Overlay(覆盖网络)overlay基于 VXLAN 等隧道技术,实现跨 Docker Host 的容器通信。Docker Swarm 默认使用此模式。多节点集群、Swarm 编排
Macvlanmacvlan为容器分配独立的 MAC 地址,使其表现为物理网络中的独立主机,可直接被外部网络访问。需要容器直接接入物理网络、传统应用迁移
自定义网络(User-defined)bridge / overlay用户通过 docker network create 创建,支持自定义网段、DNS 服务发现、网络隔离等高级特性。生产环境多项目隔离、微服务架构

补充说明:

  • 单机环境下,Bridge 是最常用的模式;跨主机通信通常需要借助 Overlay、Flannel、Calico 等方案。
  • Flannel 并非 Docker 原生驱动,而是通过为每台宿主机分配不冲突的子网,配合 Docker Bridge 实现跨主机容器通信,属于第三方 Overlay 方案。
  • 自定义 Bridge 网络相比默认 docker0,额外提供了容器名 DNS 解析和自动网络隔离能力,推荐在生产环境中使用。

一、Docker 本地网络模式实验

Docker 默认提供了几种网络模式,用于处理容器与宿主机、容器与外网的连接。

1. Bridge 模式(桥接模式)

这是 Docker 的默认网络模式。所有容器连接到 docker0 网桥,通过 NAT 访问外网。

  • 特点:
  • 默认网段:172.17.0.0/16。
  • 不同 Docker Host 上的容器默认无法直接通信(因为网段冲突)。

实验步骤:

  1. 查看默认网桥信息
# 查看宿主机网卡信息,确认 docker0 存在
[root@wen ~]# ip a
# 输出中应包含 docker0,状态通常为 DOWN,IP 为 172.17.0.1/16
  1. 查看 Docker 网络列表
[root@wen ~]# docker network ls
# 输出示例:
# NETWORK ID  NAME    DRIVER  SCOPE
# f2f19a5e2ebc  bridge  bridge  local
# 5aeb2630e0f9  host    host    local
# 44b9cab07f8c  none    null    local
  1. 启动 Bridge 模式容器
# 默认即为 --network bridge,可省略
[root@wen ~]# docker run -it --network bridge centos:7.7.1908 /bin/bash

# 进入容器后查看 IP
[root@b76b36b8c644 /]# ifconfig
# 输出示例:inet 172.17.0.2 (属于 172.17.0.0/16 网段)
  1. 查看网络详情
[root@wen ~]# docker network inspect bridge

2. Host 模式(主机模式)

容器与宿主机共享网络命名空间,没有独立的网卡和 IP。

  • 特点:
  • 容器与宿主机 IP、主机名完全一致。
  • 缺点:多个容器若绑定相同端口(如 80),会产生端口冲突。

实验步骤:

  1. 启动两个 Host 模式容器
# 启动容器 C1
[root@wen ~]# docker run -it --network host --name C1 centos:7.7.1908 /bin/bash
[root@wen /]# yum -y install iproute
[root@wen /]# ip a  # 看到的即为宿主机网络

# 启动容器 C2 (在另一个终端)
[root@wen ~]# docker run -it --network host --name C2 centos:7.7.1908 /bin/bash
  1. 验证端口冲突
# 在 C1 中安装并启动 httpd
[root@wen /]# yum -y install httpd
[root@wen /]# echo "test httpd" > /var/www/html/index.html
[root@wen /]# httpd -k start # 启动成功

# 在 C2 中执行相同操作
[root@wen /]# yum -y install httpd
[root@wen /]# httpd -k start 
# 报错信息:(98)Address already in use: AH00072: make_sock: could not bind to address [::]:80
# 说明端口被 C1 占用

3. Container 模式(容器复用模式)

新容器不创建独立网卡,而是与指定容器共享网络栈。

实验步骤:

# 1. 启动第一个容器 d1
[root@wen ~]# docker run -it --name d1 centos:7.7.1908 /bin/bash

# 2. 启动 d2,指定共享 d1 的网络
[root@wen ~]# docker run -it --name d2 --network container:d1 centos:7.7.1908 /bin/bash

# 结果:d1 和 d2 拥有相同的 IP 地址和端口范围,但文件系统和进程隔离。

4. None 模式(无网络模式)

容器仅有 lo 回环网卡,无外部网络连接。

实验步骤:

# 启动容器
[root@wen ~]# docker run -it --network none centos:7.7.1908 /bin/bash

# 容器内尝试安装软件或查看 IP 会失败/无 IP
[root@0fd5a2fbc44c /]# yum -y install iproute # 可能因无网报错
[root@wen ~]# docker inspect 0fd5a2fbc44c # 查看详细信息确认无 IP

二、跨 Docker Host 容器间通信实验 (Flannel)

为了解决不同宿主机上容器网段冲突及通信问题,使用 Flannel + Etcd 构建 Overlay 网络。

  • 环境规划:
  • Node1: 192.168.2.124 (安装 etcd, flannel, docker)
  • Node2: 192.168.2.125 (安装 flannel, docker)
  • 容器网段: 172.200.0.0/16

1. 环境准备 (Node1 & Node2)

1.1 关闭防火墙和 SELinux

# 两台机器都执行
[root@localhost ~]# systemctl stop firewalld.service
[root@localhost ~]# systemctl disable firewalld.service
[root@localhost ~]# setenforce 0 # 临时关闭
# 永久关闭需修改 /etc/selinux/config

1.2 修改主机名

# Node1 (192.168.2.124) 执行
[root@node1 ~]# hostnamectl set-hostname node1

# Node2 (192.168.2.125) 执行
[root@node2 ~]# hostnamectl set-hostname node2

1.3 配置 Hosts 解析

# 两台机器都执行
[root@node1 ~]# cat >> /etc/hosts <<EOF
192.168.2.124 node1
192.168.2.124 etcd
192.168.2.125 node2
EOF

1.4 安装软件

# Node1 安装 etcd, flannel, docker
[root@node1 ~]# yum -y install etcd flannel docker

# Node2 安装 flannel, docker
[root@node2 ~]# yum -y install flannel docker

2. 配置 Etcd (仅 Node1)

2.1 修改 Etcd 配置

[root@node1 ~]# vim /etc/etcd/etcd.conf
# 修改第6行:监听所有地址
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379,http://0.0.0.0:4001"
# 修改第21行:广播地址
ETCD_ADVERTISE_CLIENT_URLS="http://etcd:2379,http://etcd:4001"

2.2 启动 Etcd 并验证

[root@node1 ~]# systemctl start etcd
[root@node1 ~]# systemctl enable etcd

# 验证健康状态
[root@node1 ~]# etcdctl cluster-health
# 输出应显示 cluster is healthy

3. 配置 Flannel (Node1 & Node2)

3.1 配置 Flannel 连接 Etcd (两台机器)

[root@node1 ~]# vim /etc/sysconfig/flanneld
# 修改第4行,指向 etcd 地址
FLANNEL_ETCD_ENDPOINTS="http://etcd:2379"
# 前缀保持默认
FLANNEL_ETCD_PREFIX="/atomic.io/network"

3.2 在 Etcd 中配置容器网段 (仅 Node1)

# 写入网络配置
[root@node1 ~]# etcdctl mk /atomic.io/network/config '{ "Network": "172.200.0.0/16" }'

# 验证写入
[root@node1 ~]# etcdctl get /atomic.io/network/config
# 输出:{ "Network": "172.200.0.0/16" }

4. 启动 Flannel 并关联 Docker (Node1 & Node2)

4.1 启动 Flannel 服务

# 两台机器都执行
[root@node ~]# systemctl start flanneld
[root@node ~]# systemctl enable flanneld

# 查看是否生成 flannel0 网卡
[root@node ~]# ip a 
# 应看到 flannel0 接口

4.2 配置 Docker 使用 Flannel 网段

原理:Flannel 启动后会生成 /run/flannel/subnet.env,Docker 需要读取其中的 bip 和 mtu。

Node1 操作:

# 1. 查看分配的子网信息
[root@node1 ~]# cat /run/flannel/subnet.env
# 假设输出 FLANNEL_SUBNET=172.200.27.1/24, FLANNEL_MTU=1472

# 2. 修改 Docker 配置
[root@node1 ~]# vim /etc/docker/daemon.json
{
    "insecure-registries": ["http://192.168.2.124"],
    "bip": "172.200.27.1/24",  # 对应 subnet.env 中的 FLANNEL_SUBNET
    "mtu": 1472               # 对应 subnet.env 中的 FLANNEL_MTU
}

# 3. 重启 Docker
[root@node1 ~]# systemctl restart docker

# 4. 验证 docker0 IP 是否变化
[root@node1 ~]# ip a
# docker0 的 inet 应变为 172.200.27.1/24

Node2 操作:

# 1. 查看分配的子网信息 (Node2 会分配到不同子网)
[root@node2 ~]# cat /run/flannel/subnet.env
# 假设输出 FLANNEL_SUBNET=172.200.21.1/24

# 2. 修改 Docker 配置
[root@node2 ~]# vim /etc/docker/daemon.json
{
    "insecure-registries": ["http://192.168.2.125"],
    "bip": "172.200.21.1/24",  # 注意这里是 Node2 分配到的子网
    "mtu": 1472
}

# 3. 重启 Docker
[root@node2 ~]# systemctl restart docker

5. 最终验证

Node1 启动容器

[root@node1 ~]# docker run -it centos:7.7.1908 /bin/bash
[root@... /]# ip a
# 容器 IP 应为 172.200.27.x

Node2 启动容器

[root@node2 ~]# docker run -it centos:7.7.1908 /bin/bash
[root@... /]# ip a
# 容器 IP 应为 172.200.21.x

通信测试在 Node1 的容器中 ping Node2 容器的 IP(例如 ping 172.200.21.2),若能通,则跨主机通信配置成功。

注意

如果相互ping不通,可能是没有打开ipv4转发

# (Node1 & Node2 均需执行)
# 1. 使用 echo 命令将配置永久写入 /etc/sysctl.conf
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf

# 2. 执行命令,让配置立即生效
sysctl -p

更多推荐