Docker容器网络互联

avatar 2022年12月16日18:12:43 评论 511 次浏览

我的试验环境说明:centos8.4 + Docker version 20.10.7, build f0df350

如何让容器之间能互相通信呢?答案就是《容器互联》。

参考:

https://www.cnblogs.com/kevingrace/p/6590319.html

https://www.cnblogs.com/bakari/p/9036984.html

Docker单主机容器通信

基于对net namespace的控制,docker可以为在容器创建隔离的网络环境,在隔离的网络环境下,容器具有完全独立的网络栈,与宿主机隔离,也可以使容器共享主机或者其他容器的网络命名空间,基本可以满足开发者在各种场景下的需要。

按docker官方的说法,docker容器的网络有五种模式:

bridge模式,–net=bridge(默认) 这是dokcer网络的默认设置,为容器创建独立的网络命名空间,容器具有独立的网卡等所有单独的网络栈,是最常用的使用方式。在docker run启动容器的时候,如果不加–net参数,就默认采用这种网络模式。安装完docker,系统会自动添加一个供docker使用的网桥docker0,我们创建一个新的容器时,容器通过DHCP获取一个与docker0同网段的IP地址,并默认连接到docker0网桥,以此实现容器与宿主机的网络互通。

host模式,–net=host 这个模式下创建出来的容器,直接使用容器宿主机的网络命名空间。将不拥有自己独立的Network Namespace,即没有独立的网络环境。它使用宿主机的ip和端口。这种模式主要适用于管理员希望以docker方式管理服务器。(实际使用不多)

none模式,–net=none 为容器创建独立网络命名空间,但不为它做任何网络配置,容器中只有lo,用户可以在此基础上,对容器网络做任意定制。这个模式下,dokcer不为容器进行任何网络配置。需要我们自己为容器添加网卡,配置IP。因此,若想使用pipework配置docker容器的ip地址,必须要在none模式下才可以。

其他容器模式(即container模式,join模式),–net=container:NAME_or_ID 与host模式类似,只是容器将与指定的容器共享网络命名空间。这个模式就是指定一个已有的容器,共享该容器的IP和端口。除了网络方面两个容器共享,其他的如文件系统,进程等还是隔离开的。

用户自定义:docker 1.9版本以后新增的特性,允许容器使用第三方的网络实现或者创建单独的bridge网络,提供网络隔离能力。

参考:https://www.coonote.com/docker-note/docker-network-mode.html

最后发现默认的docker0这种bridge和用户自己创建的bridge的网络方案最实用。那么这两种方式有啥区别呢?

Link方式实现本机容器间互联通信

容器互联大体有以下三种方式:

  • 基于volume的互联

  • 基于link的互联

  • 基于网络的互联

一些常用命令:

docker network ls
docker network create -d bridge demo-net # 新建虚拟网络

# 用下面的命令创建docker网桥
docker network create br0 -d bridge -o com.docker.network.bridge.name='br0' \
--subnet=172.10.200.0/24 --ip-range=172.10.200.0/24 --gateway=172.10.200.1
# 运行容器
docker run -itd --name centostst --network br0 bmc/opensuse15.2:dev /bin/bash

# 第二个例子
docker run -itd --name suse11 --network demo-net opensuse /bin/bash
docker run -itd --name suse22 --network demo-net opensuse /bin/bash

# 分别进入容器,户型能够ping通
docker exec -it suse11 /bin/bash
docker exec -it suse22 /bin/bash

# vi /etc/docker/daemon.json 设置所有容器的DNS
# 这样容器就可以共享这里的DNS配置,解析域名了。
"dns": [
  "223.5.5.5",
  "8.8.8.8"
]
# 单独指定容器DNS
docker run -it --rm --dns=223.5.5.5 --dns-search=test.com bmc/opensuse15.2:dev

添加路由实现容器跨主机互联通信

Docker默认的网桥是docker0。此网桥只会在本机连接所有容器。下面我们借助两台服务器上的docker0网桥来互相通信。

vi /etc/docker/daemon.json 
{
  "bip":"172.16.200.1/24"
}
{
  "bip":"172.16.201.1/24"
}

上面的配置分别配置两台服务器,然后重启docker。

之后你会发现现在两台机器上的两个容器IP是不会互通的。但是他们能够Ping通主机的内网IP,下面在宿主机上面添加到达对方的路由:

# docker1
route add -net 172.16.201.0/24 gw 10.10.200.172
route del -net 172.16.201.0/24 gw 10.10.200.172

# docker2
route add -net 172.16.200.0/24 gw 10.10.200.142

# 添加权限
--privileged

杯具,最后发现还是不通,看看是哪里出问题了? (这种方式并不是太好,还是用下面的方式吧 O(∩_∩)O哈哈~)

桥接到Docker宿主机实现跨主机Docker容器通信

如果希望Docker跨主机访问,最简单的方式就是将不同主机的docker0 设置为同一网段。

整体网络拓扑结构就是这样(网上借用的示意图,参考即可):

在两台宿主机,安装网桥查询工具

zypper in bridge-utils
brctl show

PC-A: eth1:10.10.200.142
PC-B: eth1:10.10.200.172

PC-A执行:

# 第一步
vi /etc/docker/daemon.json 

"bip": "10.10.200.142/24",
"fixed-cidr": "10.10.200.16/28"

"default-gateway": "192.168.61.1" # 不需要这行 

# 第二步
ifconfig eth1 0.0.0.0 # 将物理网卡IP值空
brctl addif docker0 eth1 # 将docker0 桥接到 eth1 上
brctl show
systemctl restart docker.service 

ifconfig # 查看网卡
docker0   Link encap:Ethernet  HWaddr 02:42:6A:9E:15:CA  
          inet addr:10.10.200.142  Bcast:10.10.200.255  Mask:255.255.255.0

# 第三步
docker start susexx # 启动容器,查看IP,ping主机试一试

PC-B执行:

# 第一步
vi /etc/docker/daemon.json 

"bip": "10.10.200.172/24",
"fixed-cidr": "10.10.200.32/28" 

# 第二步
ifconfig eth1 0.0.0.0 # 将物理网卡IP置空
brctl addif docker0 eth1 # 将docker0 桥接到 eth1 上
brctl show
systemctl restart docker.service 

ifconfig # 查看网卡
docker0   Link encap:Ethernet  HWaddr 02:42:6A:9E:15:CA  
          inet addr:10.10.200.172  Bcast:10.10.200.255  Mask:255.255.255.0
          
# 第三步
docker start susexx # 启动容器,查看IP,ping主机试一试

大家可以看到实现了,PC-A 和 PC-B 两台宿主机上的容器互通。

参考:

https://developer.51cto.com/art/202002/609994.htm

https://www.pianshen.com/article/5546389320/

主机重启自动启动br0的绑定

在上面的配置中,如果主机重启,有可能网桥br0上配置的IP地址无法正常访问,这是因为网桥没有和实体网卡绑定。怎么办?

CentOS系统

这个时候在/etc/rc.local中配置brctl addif br0 eno1可能报错,重启不生效。给网卡做如下配置:

# brctl addif br0 eno1

# /etc/sysconfig/network-scripts/ifcfg-br0
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
UUID=f2e0b49a-d9fe-4472-85e4-30ccdfbb254e
TYPE=Bridge
NAME=br0
DEVICE=br0
ONBOOT=yes
IPADDR=192.168.xx.xx
PREFIX=16

# /etc/sysconfig/network-scripts/ifcfg-eno1
TYPE=Ethernet
BOOTPROTO=none
ONBOOT=yes
DEVICE=eno1
BRIDGE=br0

SuSE系统

suse用上面的方法可能不行了,这个时候把绑定命令写入after.local文件中有效。

# cat /etc/init.d/after.local
#!/bin/bash
brctl addif br0 em1
brctl addif br1 em2

# systemctl status after-local.service
# 启动服务的配置可以参考其它文章。
avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: