文章目录
docker 网络管理
docker 网络基础
docker 容器网络模型
- 1.7.0版本开始,Docker 将网络功能以插件化的形式剥离出来,成为独立的容器网络项目,被称为
libnetwork
,为不同容器定义统一规范的网络层标准 libnetwork
网络架构基于一套称为容器网络模型(CNM)的接口- CNM 的理念是为应用提供跨不同网络基础架构的可移植性
- 平衡了应用的可移植性
- 使用者更关心高层的实现,不用关心底层的具体实现
CNM 架构
CNM 高层架构
- 沙箱(虚线部分):也叫沙盒(SandBox),包含了容器的网络栈配置,涉及容器的接口、路由表、DNS管理等,是通过 Linux 网络名称空间、FreeBSD Jail(操作系统层虚拟化技术)、其他类似的机制实现,一个沙箱可以包含多个来自不同网络的端点
- 端点(Endpoint):也叫接入点,用来将沙箱连接到网络,端点架构将与网络的实际连接从应用中抽象出来,有助于移植,让服务无需关心如何连接网络就可以使用不同类型的网络驱动
- 网络(Network):CNM 没有定义 OSI 七层模型中的网络层,这里的网络可以使用由 Linux 网桥、虚拟局域网等来实现
CNM 驱动接口
提供了2个可插拔且开放的接口
- 网络驱动(Network Drivers):提供网络运行的具体实现
- 本地网络驱动:docker 引擎本身实现(overlay 网络、本地网络)
- 远程网络驱动:社区或者其他供应商提供的网络驱动
- 也可以自己创建网络驱动
- IPAM 驱动:IP 地址管理,内置的 IP地址管理驱动,如果没有明确指定,它会为网络和端点提供默认的子网或IP地址,远程 IPAM 驱动可提供工具整合
docker 本地网络驱动
常用本地网络驱动类型 | 说明 |
---|---|
bridge | 桥接网络 |
host | 主机网络 |
overlay | 覆盖网络 |
none | 关闭容器的所有网络连接 |
bridge:默认网络驱动程序
host:使用主机的网络栈
overlay:本地 Linux 桥接网络和 VxLAN技术的结合
网络的作用域
docker network ls
远程网络驱动
意思就是第三方网络插件,与 CNM 兼容的
- contive
- calico
- kuryr
- …
网络驱动选择推荐
场景 | 网络驱动 |
---|---|
同一个主机多个容器需要通信 | 自定义的桥接网络 |
容器网络不与主机隔离,其他方面需要被隔离 | 主机网络 |
不同主机上的容器需要通信 | overlay |
docker 与专用网络栈集成 | 第三方网络插件 |
Linux 网络基础
Linux 网桥
网桥是一种在网段之间转发流量的链路层设备,可以是硬件设备,也可以是运行在主机内核的软件设备,Linux 网桥是 Linux内核中用于物理交换机的虚拟化实现的二层网络设备,Docker 的 bridge 是 Linux 网桥的高层实现
网络名称空间
在内核中一个被隔离的网络栈,拥有自己的网络接口、路由、防火墙规则,网络名称空间可以确保同一个主机上的2个容器不能互相通信,设置与主机本身也不能通信,除非通过 docker 网络进行连接,主机的网络的名称空间也被称为全局的网络名称空间
veth 对
- Linux 通过在内核中进行数据复制赖实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中,所以转发效率高,虚拟接口就像一块普通的以太网卡,只是它没有连接到外部接口时候,不需要真正同外部网络设备通信
- Docker 利用这项技术,它在主机和容器的内部分别创建一个虚拟接口,并让他们彼此连通,这样的一对接口就叫 veth 对(veth pair),也可以用大写的 VETH 表示
- veth 也叫虚拟以太网设备,用于连接2个网络名称空间的 Linux 网络接口,是一个全双工的连接
iptables
Linux 内置的包过滤系统,它为 Docker 本地网络提供主机端口映射、负载均衡决策标记流量等
容器运行网络配置
设置容器的网络连接
--network
选项 | 说明 |
---|---|
none | 不适用任何网络连接 |
bridge | 默认设置 |
host | 容器内部使用主机的网络栈 |
container | 使用其他容器的网络栈,需要指定这个容器 |
network-name/network-id | 自定义的docker网络 |
none
bridge
host
container
设置容器的 IP 地址
默认情况下,docker会为每一个容器连接到docker网络的容器分配IP地址,IP地址是从地址池中取的,docker守护进程就是每个容器的DHCP服务器,所以每一个网络也都有一个默认的子网掩码和网关地址
- 使用默认设置是不能指定IP地址的
- 需要用户自己创建的桥接网络才行
示例
设置容器的 MAC 地址
手动指定的话,docker 不会检查其唯一性
设置容器的发布端口
管理 docker 网络
docker network 子命令
:网络管理命令用法
子命令 | 说明 |
---|---|
connect | 将容器连接到指定网络 |
create | 创建容器网络 |
disconnect | 断开容器与指定网络的连接 |
inspect | 显示一个或者多个网络的详细信息 |
ls | 显示网络列表 |
prune | 删除未被使用的网络 |
rm | 删除一个或者多个网络 |
配置容器网络连接
默认桥接网络
启动docker时候,自动创建一个默认的桥接网络:bridge
- 新创建的容器默认会连接到这个网络,在不指定的情况下
- 也可以创建用户自己的桥接网络,用户自定义的桥接网络优先级要高得多
- 在docker中,桥接网络通过软件网桥让连接到同一桥接网络的容器之间可以互相通信,同时隔离那些没有连接到该桥接网络的容器,bridge驱动会自动在主机生成对应规则,让不同的桥接网络上的容器之间不能直接通信
默认桥接网络的工作原理
- docker 守护进程启动,自动在主机上创建一个docker0的 Linux 虚拟网桥,此时如果没有明确指定网络类型,创建的容器自动连接这个虚拟网桥上,虚拟网桥的工作方式和物理交换机类似,主机上的所有容器通过它连接在同一个二层网络中
- docker 守护进程为每个启动的容器创建一个 veth pair,它是一对直接相连的虚拟网络接口,其他一端在容器的网络名称空间中(eth0@xxxx),另外一端链接到虚拟网桥docker0,位于docker的网络名称空间中,以 vethxxx 形式命名
须知
默认的桥接网络有很多局限性
- 容器之间只能使用 ip 访问,不能通过容器名称
- 要使用容器名称。只能使用传统的 --link 进行互联
自定义默认网桥
- docker 引擎默认生成的网桥信息:172.17.0.1/16
- 在 /etc/docker/daemon.json 配置文件中指定
{
"big": "192.169.0.0/16"
}
主机网络
主机网络用于启动直接连接到docker 主机网络栈容器,其实就是关闭了 docker 网络,直接使用主机网络
- 网络是没有隔离的,和主机公用一个
优势在我
- 更好的网络性能
- 被认为是不安全的,暴露公共网络中
- –mac-address 配置无效
none 网络
这个没啥子好说的
container 网络模式
加入另一个容器的网络名称空间,需要自定义网络栈的时候,是很有用的
- 一个特殊的网络模式
- 容器会共享其他容器的网络环境
- 彼此就不存在网络隔离
自定义桥接网络
可以使用 docker 网络驱动或外部网络驱动插件创建一个自定义的网络,多个容器连接到这个自定义的网络中,这样连接的容器可以使用IP通信,也可以使用名称通信
- docker 内置了bridge网络驱动的
- 可以直接创建桥接网络
- 生产环境不建议使用默认的桥接网络
区别
- 自定义提供了容器化应用之间更好的隔离和互操作性,自动互相暴露所有端口,但是不会暴漏在外部
- 自定义提供了容器间自动DNS解析,不用使用–link进行互联就可以使用名称进行通信
- 可以随时断开自定义桥接网络,在运行的时候
- 可为每个用户自定义桥接网络创建一个可配置的网桥(没懂)
- 默认桥接网络中连接的容器可以共享环境变量(啥意思)
容器与外部的通信
默认情况
- 容器内可以主动访问外部网络
- 外部网络无法访问容器内
容器访问外部网络
前提
- 容器访问外部网络–》要运行内核的IP转发–》
net.ipv4.conf.all.forwarding
- iptables 默认的
FORWARD
策略是ACCEPT
(这个好像不对,我环境不是这个也可以)
NAT 实现容器到外部的访问
我们先看默认网桥
我们再看自定义网桥
上述的一个 NAT 转发是三层网络上的实现
外部网络访问容器
默认情况
- 创建的容器不会将任何端口对外发布,容器外部是无法访问到的
- 外部访问容器内的应用必须要明确的授权
- 首先要通过 docker run 命令创建容器时,使用 -p 或 -P 进行设置,会创建一个 iptables 规则,将容器的一个端口映射到 Docker 主机上的一个端口,允许外部网络通过这个端口访问容器
- 上述实现也是通过 NAT 实现的
端口映射的 NAT 过程
- 创建一个对外映射的 tomcat 服务
- 查看主机的 iptables 的 nat 表中添加对应的规则
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER # 外部流量改写其目的地址,所有流量转到DOCKER链
# DOCKER链将所有不是从自定义网桥进来的包,目标端口是8080的包将被修改为目标地址为172.25.0.2和目标端口8080的包
-A DOCKER ! -i br-cf85df2e6fc1 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.25.0.2:8080
# 还有一个出去的链规则,用于将容器对外部访问的结果传回外部网络
-A POSTROUTING -s 172.25.0.2/32 -d 172.25.0.2/32 -p tcp -m tcp --dport 8080 -j MASQUERADE
#对于每一个映射端口,主机都会启动一个 docker-proxy 进程来处理容器的流量
限制外部网络访问
- 默认情况下,所有外部源IP都被允许连接到 Docker 守护进程,若要配置允许特定的 IP 或网络访问容器,需要在 DOCKER 过滤器链的顶部插入否定规则
- 记住不要手动去改关于 Docker 有关的 iptables 规则,如果需要添加 Docker 规则,则应将他们添加到 DOCKER-USER 链中,这些规则会在 Docker 自动创建任何规则之前加载
### 只允许192.168.1.236访问
iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.236 -j DROP
容器与容器的通信
容器间通信的解决方案
- 默认的同一个
docker
网络上的所有容器在所有端口上都可以相互连接 - host 模式让所有容器都在主机网络空间,共用主机的协议栈,主机所有的容器都可以互相通过主机的接口互相通信
- 自定义网桥,容器之间可以通过名称或者别名互相访问
- 默认桥接网络不支持基于名称的服务发现和用户指定的IP地址,所连接的容器只能通过IP地址互相访问,除非使用了容器互联 --link
- 容器之间可以通过挂载主机目录实现通信
- 容器通过端口映射提供连接
- container 网络模式让容器公用一个IP网络,2个容器之间通过 localhost 通信
默认桥接网络的传统容器间连接
–link
- 重启源容器,并不会引起这些变量的变化