虚拟化网络

通过纯软件的方式来实现,是网络虚拟化的简单实现。

OpenVSwitch

纯软件实现,但是功能十分强大,并不是集成在内核中的,需要单独下载。

SDN 将全部的网络的控制层面都集成到一台主机上。

容器间通信

单机通信

image-20201111174141323

交换机的实现,每个容器会生成一对网卡,一个网卡放在容器中,一个网卡放在交换机上。如果将一个局域网中或者说一个网段的所有主机的一个接入网卡放置在一个虚拟的交换机上,就形成了交换机。

路由器的实现,可以理解为是一个独立单独的名称空间来实现路由器的功能,用来转发不同网段的数据。

多机通信

桥接模式

image-20201111174551396

管理困难,并且很容易产生广播风暴。并且是 nat 桥网络,并不是真正的物理桥网络。

桥接模式的弊端

如果要向外网发布内网的 web 那么就必须做 DNAT 映射,映射完成后才可以访问。但是如果内网有多个主机,这时就不会映射到一个端口上了,这时就会出现问题。

联盟式网络

两个容器联接到一起,UTS NET IPC 是共享的,会使用同一个网卡,同一个 IO 同一个主机名的解析。

开放式容器

直接开放与物理机直接连接,物理机能看到或者是连接到哪些主机,那么容器就可以连接并看到这些主机,与物理机共享资源,是联盟式网络的扩展。

nat 模式

将主机内的网络通过桥接到外网网卡进行转换 DNAT,然后对外网进行通信。

这样的方式虽然可以实现通信,但是会导致 NAT 转换次数过多的问题。

Overlay Network

image-20201111191933768

通过隧道进行转发,转发通过 eth0 进行转发,转发过程中外网网卡会主动在包头上额外携带一个多加的包头,用来存储外网网卡上的 IP 地址,进行转发数据并通信。

只能在同一网段上通信。

范例:docker 网卡及网桥的显示

Docker 0 网卡的作用

作为一个容器之间进行交互的虚拟网卡和网桥来使用

当容器运行时出现的网卡

这个网卡就是留在虚拟机中的一半网卡

网卡体现

24: veth7534419@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue maste
28: vethb9e279c@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue maste

虚拟网桥的接口体现

[root@centos7_10 ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242830530e1       no              veth7534419
                                                        vethb9e279c
对应关系如下
veth7534419@if23            ---->            veth7534419
vethb9e279c@if27            ---->            vethb9e279c

Docker 网络类型

[root@centos7_10 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
b36043d8c409        bridge              bridge              local
e9b392141842        host                host                local
0a69c6674e88        none                null                local

bridge

软件方式的网桥

  • 会为每个主机安装生成一对网卡,并且一半在容器中,一半放在 docker 0 这个虚拟网桥或网卡上
  • Docker 0 桥其实是一个默认 nat 桥,新创建容器后生成一对网卡的同时也会添加到 iptables 一条 nat 转换规则

网络模式的指定

查看网络支持的模型

[root@centos7_12 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
22c04e853e32        bridge              bridge              local
75b3a2e60ce2        host                host                local
65a432fbe268        none                null                local

查看网络的详细信息

[root@centos7_12 ~]# docker network inspect bridge
[root@centos7_12 ~]# docker container inspect 5ee6a14a1289

使用 ip netns 设置网络名称空间

使用 ip net 命令来模拟容器间的网络名称通信

ipnet 命令用法

[root@centos7_10 ~]# ip netns help
Usage: ip netns list
       ip netns add NAME
       ip netns set NAME NETNSID
       ip [-all] netns delete [NAME]
       ip netns identify [PID]
       ip netns pids NAME
       ip [-all] netns exec [NAME] cmd ...
       ip netns monitor
       ip netns list-id

创建网络名称空间并查看新建名称空间中的网卡,默认该网络名称空间中只存在 lo 网卡

[root@centos7_10 ~]# ip netns exec net1 ifconfig -a
lo: flags=8<LOOPBACK>  mtu 65536
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

创建一对网卡

ip link 命令也支持创建 link 链路,并且支持的类型众多,类似于 veth vxlan 等

[root@centos7_11 ~]# ip link add name veth1.1 type veth peer name veth1.2

查看创建出的一对网卡

veth1.2@veth1.1:
veth1.1@veth1.2:

#对照相应不同的网卡,一对网卡 1.2 对应 1.1

将新建的网卡添加到 net1 网络名称空间中

[root@centos7_11 ~]# ip link set dev veth1.2 netns net1

再次查看网络名称空间中接口

[root@centos7_11 ~]# ip netns exec net1 ip add
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: veth1.2@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 66:d7:a7:4c:0c:52 brd ff:ff:ff:ff:ff:ff link-netnsid 0

设置 net1 网络名称空间中的网卡名称

[root@centos7_11 ~]# ip netns exec net1 ip link dev veth1.2 name eth0

为虚拟网卡配置 IP 地址

[root@centos7_11 yum.repos.d]# ifconfig veth1.1 10.1.0.1/24 up

为名称空间网卡配置 IP 地址

[root@centos7_11 yum.repos.d]# ip netns exec net1 ifconfig eth0 10.1.0.2/24 up

测试在网络名称空间中是否可以 ping 通主机 IP 地址

[root@centos7_11 yum.repos.d]# ip net exec net1 ping 10.1.0.1
PING 10.1.0.1 (10.1.0.1) 56(84) bytes of data.
64 bytes from 10.1.0.1: icmp_seq=1 ttl=64 time=0.021 ms

实现两个名称空间的互相通信

1. 新建网络名称空间
[root@centos7_11 ~]# ip netns add net2

2. 移动网卡到新建网络名称空间
[root@centos7_11 ~]# ip link set dev veth1.1 netns net2

3. 为新建网络名称空间的网卡改名
[root@centos7_11 ~]# ip netns exec net2 ip link set veth1.1 name eth0

4. 查看现有网卡
[root@centos7_11 ~]# ip netns exec net2 ip add
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: eth0@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether b2:2f:09:84:c6:ce brd ff:ff:ff:ff:ff:ff link-netnsid 0

5. 为网卡新增 IP 地址
[root@centos7_11 ~]# ip netns exec net2 ifconfig eth0 10.1.0.1/24 up

6. 测试两个网络名称空间是否可以通信
[root@centos7_11 ~]# ip netns exec net2 ping 10.1.0.2
PING 10.1.0.2 (10.1.0.2) 56(84) bytes of data.
64 bytes from 10.1.0.2: icmp_seq=1 ttl=64 time=0.046 ms

修改 service 文件为容器指定网络

-b 指定网桥
--bip 指定地址范围

指定容器的主机名进行运行

主机名就是容器的 ID 号,容器 ID 可以直接通过 docker ps 命令来查看

[root@centos7_10 ~]# docker container run -h busyhost -it busybox
/ # hostname
busyhost

容器网络的类型

image-20201112185126329Closed container

封闭式容器,在该容器中只允许自己与自己通信,并不可以与其他的容器或者是宿主机进行通信。

实现方式

容器 ID 就是主机名,并且主机使用的是外部主机的网络,并不是使用的本机并且局限在本机。

Bridge Container

image-20201112201804599简介

容器通过网桥与外网进行通信,就是通过 NAT 来对外进行通信。这种通信方式会产生 NAT 转换次数过多的现象,并且容器之间的通信也要依赖于网桥,容器之间并不是开始就可以进行交互通信的。

范例:实现注入 DNS 地址等配置,并配置为网桥模式

[root@centos7_10 ~]# docker container run -it --name httpd --network bridge -h t1.dingchen.club --dns 8.8.8.8 --dns-search ilinux.io --add-host www.dingchen.club:1.1.1.1 --rm busybox:latest

-it 指定进入容器并且以非交互式运行
--name 指定运行容器的名称
--network 指定网络的模式配置,bridge 代表是网桥模式
-h 注入容器的主机名
--dns 指定解析的 DNS 服务器地址
--dns-search 指定如果解析不到,自动填充的域名后缀
--add-host 指定单独域名解析出的主机 IP 地址
--rm 指定镜像,运行完成后自动删除

/ # cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
1.1.1.1 www.dingchen.club
172.17.0.2      t1.dingchen.club t1

Opening inbound communication

四种暴露方式

  • -p 选项的使用格式
    • -p
      • 将指定的容器端口映射至主机所有地址的一个动态端口
    • -p :
      • 将容器端口 映射至指定的主机端口
    • -p ::
      • 将指定的容器端口 映射至主机指定 的动态端口
    • -p ::
      • 将指定容器端口 映射至主机指定的 的端口
    • “动态端口” 指随机端口,具体的映射结果可使用 docker port 命令查看

image-20201112201822081映射为动态端口

1. 将容器中的 IP 映射为一个指定端口
[root@centos7_10 ~]# docker run --name web --rm -p 80 dingchen/httpd:v0.1

2. 查看生成的 iptables 规则
[root@centos7_10 ~]# iptables -vnL -t nat
Chain POSTROUTING (policy ACCEPT 24 packets, 2223 bytes)
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.2           172.17.0.2           tcp dpt:80
    
3. 查看 docker port web 命令显示结果
[root@centos7_10 ~]# docker port web
80/tcp -> 0.0.0.0:32768
  1. 访问测试

image-20201112203529140指定 IP 映射动态随机端口

1. 映射端口
[root@centos7_10 ~]# docker run --name web --rm -p 192.168.1.10::80 dingchen/httpd:v0.1
主机后的两个 :: 代表随机端口映射

2. docker port 查看
[root@centos7_10 ~]# docker port web
80/tcp -> 192.168.1.10:32768

映射为宿主机指定端口

1. 映射为指定端口
[root@centos7_10 ~]# docker run --name web --rm -p 80:80 dingchen/httpd:v0.1

2. 查看 docker port web 命令结果
[root@centos7_10 ~]# docker port web
80/tcp -> 0.0.0.0:80

3. 访问测试
[root@centos7_10 ~]# curl 192.168.1.10
busybox

映射为指定宿主机 IP 地址的指定端口

1. 设置指定 IP 的制定端口映射
[root@centos7_10 ~]# docker run --name web --rm -p 192.168.1.10:8080:80 dingchen/httpd:v0.1

2. docker port web 查看
[root@centos7_10 ~]# docker port web
80/tcp -> 192.168.1.10:8080

映射为指定宿主机的 IP 地址和端口以及指定容器的协议端口

docker run -p 8080:80/tcp -p 8443:443/tcp -p 53:53/udp --name nginx-test-port nginx

Joined containers

image-20201112205940229不同容器共享网络 name space

开启 b1 的容器

[root@centos7_10 ~]# docker run --name b1 -it --rm busybox
/ # hostname -i
172.17.0.2

开启 b2 容器并显示 network name space

--network container:b1 详解 : 定义共享空间是 b1 并且共享的是网络空间
[root@centos7_10 ~]# docker run --name b2 --network container:b1 -it --rm busybox
/ # hostname -i
172.17.0.2

开启 b2 容器

/ # mkdir -p /data/html/
/ # echo busybox > /data/html/index.html
/ # httpd -h /data/html/

使用 b1 访问 127.0.0.1 的 http,成功访问

/ # wget -O - -q 127.0.0.1
busybox

Open Container

容器共享宿主机网络空间

使用命令直接开启共享主机网络空间

[root@centos7_10 ~]# docker run --name b1 --network host -it --rm busybox

在容器中开启 httpd 并使用宿主机访问 127.0.0.1 的 httpd 服务

/ # mkdir -p /data/html
/ # echo busybox > /data/html/index.html
/ # httpd -h /data/html/


[root@centos7_10 ~]# curl 127.0.0.1
busybox

自定义 docker 0 桥

自定义 docker 0 桥的网络属性信息:/etc/docker/daemon.json 文件

{
    "bip": "192.168.1.5/24",        #docker 0 的网络地址,只要修改了 bip 地址,那么其他的选项都会自动计算,除了 dns
    "fixed-cidr": "10.20.0.0/16",    #ipv4    限制地址的分配范围
    "fixed-cidr-v6": "::::",        #ipv6
    "mtu": 1500,                    #指定 mtu 大小
    "default-gateway": "10.20.1.1",    #指定默认网关
       "default-gateway-v6": "2001:db8:abcd::89",    #ipv6 网关地址
    "dns": ["10.20.1.2","10.20.1.3"]    #dns 服务器地址
}

定制 docker 0 桥的 IP 地址

1. 设置 docker 0 网卡的默认 IP 地址
[root@centos7_10 ~]# vi /etc/docker/daemon.json
{
  "registry-mirrors": ["https://9ac42ay9.mirror.aliyuncs.com"],
  "bip": "136.0.0.5/24"
}

2. 重启服务
[root@centos7_10 ~]# systemctl restart docker

3. 查看 IP 地址
[root@centos7_10 ~]# ip add
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:4a:29:ee:71 brd ff:ff:ff:ff:ff:ff
    inet 136.0.0.5/24 brd 136.0.0.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:4aff:fe29:ee71/64 scope link
       valid_lft forever preferred_lft forever

更改 docker 服务器监听 IP 地址和端口

也可以通过修改 DOCKER_HOST 变量,实现 Docker 监听地址。

默认本地是使用的 socket 文件进行访问的,并不是通过 IP 地址和端口组成的套接字。socker 文件位置在 /var/run/docker.sock 并且在 docker 的启动文件中也会定义

范例:修改本地为监听 IP + 端口并且 socket 文件同时存在

  1. 更改 docker.service 启动文件
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375
  1. 查看端口和 socket 文件是否全部存在
[root@centos7_10 ~]# ss -ntl;ls /var/run/docker.sock
State      Recv-Q Send-Q Local Address:Port               Peer Address:Port     
LISTEN     0      128       [::]:2375                  [::]:*
/var/run/docker.sock
  1. 远程连接查看 docker 服务器已经存在的镜像
fang[root@centos7_12 ~]# docker -H 192.168.1.10:2375 image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
dingchen/httpd      v0.1                f9ba1712fe72        4 hours ago         1.23MB
nginx               1-alpine            e5dcd7aa4b5e        6 days ago          21.8MB
redis               latest              62f1d3402b78        2 weeks ago         104MB
busybox             latest              f0b02e9d092d        4 weeks ago         1.23MB

为 docker 服务的启动添加 label 标签

ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375 --label="name=docker1"

创建一个网桥并将一个容器加入其中

  1. 创建网桥
[root@centos7_12 ~]#  docker network create -d bridge --subnet "156.1.0.0/16" --gateway "156.1.0.1" mybr0
f90c3ea4d9b324c2c8c4bf967feb7063f07ac9eaf7f2b9c424fe7d57b4e86dde
  1. 查看网桥
[root@centos7_12 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f90c3ea4d9b3        mybr0               bridge              local
  1. 将容器加入到网桥中
[root@centos7_12 ~]# docker container run --network mybr0 -it busybox
  1. 查看容器的 IP 地址,可以看到分配的正是网桥所定义的地址范围中的地址
/ # ip add
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
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:99:0d:00:02 brd ff:ff:ff:ff:ff:ff
    inet 153.13.0.2/16 brd 153.13.255.255 scope global eth0
       valid_lft forever preferred_lft forever

实现不同网桥的通信

  1. 开启一个容器到 docker 0 网桥
[root@centos7_12 ~]# docker container run --network bridge -it busybox
/ # ip add
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
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
12: eth0@if13: <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
       valid_lft forever preferred_lft forever
  1. 开启另一个容器到 mybr0 网桥
[root@centos7_12 ~]# docker run --network mybr0 -it busybox
/ # ip add
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
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 02:42:99:0d:00:02 brd ff:ff:ff:ff:ff:ff
    inet 153.13.0.2/16 brd 153.13.255.255 scope global eth0
       valid_lft forever preferred_lft forever
  1. 开启宿主机的核心转发功能
[root@centos7_12 ~]# sysctl -p
net.ipv4.ip_forward = 1
  1. 测试是否可以通信

答案是不可以,因为 docker 为了不产生广播风暴,很聪明的将各个交换机隔开了,并且是使用的 iptables 规则隔开

只需要找出隔开两个交换机的 iptables 规则并删除即可使两台主机通信

当 ping 另一台主机时,发现了现象就是数据包被丢弃了,并且没有回应,也就是没有返回消息,这就证明数据包被 DROP 规则给丢弃了,并且没有返回消息

[root@centos7_12 ~]# iptables -D DOCKER-ISOLATION-STAGE-2 2
[root@centos7_12 ~]# iptables -D DOCKER-ISOLATION-STAGE-2 1
  1. 重新测试是否可以正常通信

image-20201112232627794

docker 的 link 网络

在 docker 中不同的容器进行通信的方式有以下几种

  1. docker 容器自带的 IP 地址进行通信
  2. docker 容器通过暴露端口进行通信

第一种方式会导致 IP 地址的硬绑定,并且不方便迁移,容器重启后有可能 IP 地址就会变化,除非可以使用固定的 IP 地址。

第二种方式进行通信是有限的,并且只可以通过固定的端口进行通信。

**还有另一种方式就是通过 docker 的 link 机制通过 hosts 文件解析主机名的方式来进行通信。**这种方式并不会因为服务的端口变化而终止并且可以通过自定义名称进行通信。

实验要求:运行一个 mariadb 服务器,让 alpine 通过 link 网络与 mariadb 进行通信。

  1. 后台运行 mariadb
[root@centos7 centos]# docker run --name db -e MYSQL_ROOT_PASSWORD=server -d mariadb
  1. 运行 alpine 并 link 到 mariadb 的网络中
[root@centos7 ~]# docker container run --name web -it --link db:aliasdb alpine
  1. 查看 web 的 env 环境变量
/ # env
ALIASDB_ENV_MARIADB_MAJOR=10.5
HOSTNAME=55bbd081c607
SHLVL=1
ALIASDB_PORT=tcp://172.17.0.2:3306
HOME=/root
ALIASDB_PORT_3306_TCP=tcp://172.17.0.2:3306
ALIASDB_NAME=/web/aliasdb
TERM=xterm
ALIASDB_ENV_GPG_KEYS=177F4010FE56CA3336300305F1656F24C74CD1D8
ALIASDB_ENV_MARIADB_VERSION=1:10.5.8+maria~focal
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
ALIASDB_PORT_3306_TCP_ADDR=172.17.0.2
ALIASDB_ENV_MYSQL_ROOT_PASSWORD=server
ALIASDB_ENV_GOSU_VERSION=1.12
ALIASDB_PORT_3306_TCP_PORT=3306
ALIASDB_PORT_3306_TCP_PROTO=tcp
  • 第一个部分是web容器自身提供的一些环境变量,如NGINX_VERSION,HOSTNAME,HOME,PATH等.
  • 第二个部分则是ALIASDB_ENV开头的变量,这些都是从source container中导入的,变量来源于Dockerfile中使用ENV命令定义的变量,或者是docker run的时候通过-e 添加的环境变量。
  • 第三个部分是ALIASDB_NAME 这个变量,这变量记录了link的两个容器的组合,这里就是/web/db
  • 第四个部分就是ALIASDB_PORT开头的一系列变量,这些变量会有很组,每组变量的命名格式如下
<alias>_PORT_<port>_<protocol>
<alias>_PORT_<port>_<protocol>_PORT
<alias>_PORT_<port>_<protocol>_PROTO
<alias>_PORT_<port>_<protocol>_ADDR

其中<port>是在Dockerfile中使用EXPOSE导出的端口,还有docker run 的时候使用-p导出的端口。<protocol>则是这些端口对应的协议。

  • 第五个部分就是ALIASDB_PORT这个变量,这个变量是EXPOSE导出端口中的第一个端口对应的连接url, 如果有EXPOSE导出的端口,还有docker run -p指定导出的端口,那么通过-p指定的端口是第一个被导出的端口
  1. 查看 web 的 hosts 文件

实质上能通信主要是依靠于 hosts 文件可以进行主动解析

/ # cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2      aliasdb ca87e14e3249 db
172.17.0.3      55bbd081c607

link机制和网络新特性

通过上文中对link机制的介绍,可以发现link机制提供了如下几个功能

  • 名称解析
  • 对link的容器可以使用别名
  • 安全的容器间连接通信
  • 环境变量的注入

安全的容器间连接通信,这个需要结合docker daemon的-icc=false 这个选项,默认同一个宿主机上的所有容器可以互相通信,当使用-icc=false 的时候所有容器之间是无法进行互相通信的(具体原因会单独出篇文章分析),但是使用link机制后,即使使用了-icc=false 两个容器之间也可以进行基于端口的通信。很不幸的是当docker引入网络新特性后,link机制变的有些多余,但是为了兼容早期版本,–link机制在默认网络上的功能依旧没有发生变化,docker引入网络新特性后,内置了一个DNS Server,但是只有用户创建了自定义网络后,这个DNS Server才会起作用。在网络新特性为未引入之前,有三种网络,第一种就是docker0这种桥接网络,用的也是最多的,第二个则是复用主机网络,称为HOST网络,第三种就是none网络,只创建了一个空的网络命名空间,没有网络接口,无法和外界通信,可以让使用者自己去构建网络。当网络新特性引入后,有了overlay网络,有了用户自定义网络。用户自定义网络下,用户可以通过docker的network子命令创建一个自定义的桥接网络,这个自定义桥接的网络和默认的docker0桥接网络基本功能都是一致的,只是在这个自定义桥接网络中拥有一些特性,可以替代link机制。这些特性包括如下几个方面:

  • 基于DNS的名称自动解析
  • 安全的隔离环境
  • 动态的附加或者脱离一个网络
  • 支持使用–link设置别名

在用户自定义网络下,不使用link机制就可以实现名称解析功能了,不再是通过link机制追加名称解析关系到/etc/hosts文件中了。并且在默认的docker0桥接网络和自定义网络下使用link机制的效果是不一样的,在自定义网络中link机制只是负责设置别名的,不再提供环境变量注入的功能了。自定义网络中同时也提供了--net-alias功能和link机制提供别名功能是一样的。保留link机制目的是为了兼容。

daemon.json 文件定义网络

vim /etc/docker/daemon.json
{
"hosts": ["tcp://0.0.0.0:2375", "fd://"],
"bip": "192.168.100.100/24",
"fixed-cidr": "192.168.100.128/26", #分配容器IP范围,此项的子网掩码只作用在分配 IP 时,定义从什么地方开始,但是分配后的 IP 掩码还是与网卡相同。
"fixed-cidr-v6": "2001:db8::/64",
"mtu": 1500,
"default-gateway": "192.168.100.200",  #网关必须和bip在同一个网段
"default-gateway-v6": "2001:db8:abcd::89", 
"dns": [ "1.1.1.1", "8.8.8.8"]
}

实现不同主机的不同容器通信

通信方式

  1. 通过 NAT 进行通信
  2. 通过桥接模式进行通信
  3. 通过 Open vSwitch 进行通信
  4. 通过 weave 进行通信

通过 NAT 进行通信

更改两个容器的 IP 网段不可以一致,因为如果两个宿主机的 IP 地址一致,那么就会出现主机认为本身的 IP 地址与本机在同一网段,所以就不会通过路由去转发数据包。

实验环境

宿主机 A :192.168.1.14

宿主机 B:192.168.1.13

第一个宿主机 A 更改网段

  1. 更改网段
[06:56:22root@centos7_14~]#cat /etc/docker/daemon.json
{
  "registry-mirrors": ["https://9ac42ay9.mirror.aliyuncs.com"],
  "bip": "192.168.100.1/24"
}
[06:57:29root@centos7_14~]#systemctl restart docker  
  1. 查看重启服务后的 IP 地址
[06:59:11root@centos7_14~]#ip add
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:ed:49:c0:45 brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.1/24 brd 192.168.100.255 scope global docker0
       valid_lft forever preferred_lft forever

第二个宿主机 B 更改网段

  1. 更改网段
[06:58:13root@centos7_13~]#cat /etc/docker/daemon.json    
{
  "registry-mirrors": ["https://9ac42ay9.mirror.aliyuncs.com"],
  "bip": "192.168.200.1/24"
}
[06:58:17root@centos7_13~]#systemctl restart docker
  1. 重启服务后的 IP 地址
[06:59:08root@centos7_13~]#ip add
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:a3:d0:9d:7f brd ff:ff:ff:ff:ff:ff
    inet 192.168.200.1/24 brd 192.168.200.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:a3ff:fed0:9d7f/64 scope link 
       valid_lft forever preferred_lft forever

启动容器并查看 IP 地址

宿主机 A 运行容器查看 IP

[07:04:20root@centos7_14~]#docker container run -it centos 
[root@cbb04b86ee08 /]# hostname -i
192.168.100.2

宿主机 B 运行容器查看 IP

[07:03:46root@centos7_13~]#docker container run -it centos
[root@eaec7aed3497 /]# hostname -i
192.168.200.2

添加路由及防火墙规则

添加防火墙的原因就是因为 iptables -vnL -t filter --line-number 命令查看中,看到防火墙调用了 docker 的原生规则,也就是默认 FROWARD链中会禁止所有的网段转发到指定虚拟网卡。

所以需要添加防火墙规则,以转发指定网段的数据包。

docker 已经默认开启了内核中的 forward 功能,所以并不需要手动开启,如果没有开启需要手动进行开启。

宿主机 B 指路由,添加防火墙规则

[root@centos7_13 ~]# ip route add 192.168.100.0/24 via 192.168.1.14 
[root@centos7_13 ~]# iptables -A FORWARD -s 192.168.1.0/24 -j ACCEPT

宿主机 A 指路由,添加防火墙规则

[root@centos7_14 ~]# ip route add 192.168.200.0/24 via 192.168.1.13 
[root@centos7_14 ~]# iptables -A FORWARD -s 192.168.1.0/24 -j ACCEPT

测试是否可以互通

  1. 宿主机 A ping 宿主机 B 的容器

image-20201119090947327通过桥接模式实现互通

桥接模式就是将内部的容器与外网网卡绑定到一起形成一个网桥,使用这个网桥与外网进行通信。

image-20201119091821689安装配置网桥

两台宿主机分别执行

[root@centos7_13 ~]# yum install bridge-utils -y

添加网卡

[root@centos7_13 ~]# brctl addif docker0 eth1

指路由

如果不指路由没有办法使两个不同网段的容器进行通信

ip route add default via 192.168.1.2

测试

image-20201119110955720

实现容器间不可以通信

命令格式,默认选项 --icc 为 yes 可以进行通信

dockerd   --icc   Enable inter-container communication (default true)
--icc=false   #此配置可以禁止同一个宿主机的容器之间通信

修改 service 文件

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -icc=false

小架构