除了自动创建的网络,还可以根据业务需要创建自定义网络。Docker提供三种自定义网络驱动: bridgeoverlaymacvlanoverlaymacvlan 用于创建跨主机的网络。

注:建议使用自定义的网络来控制哪些容器可以相互通信,可以自动DNS解析容器名称到IP地址

自定义创建bridge网络

测试通过 bridge 驱动创建类似于默认的 bridge 网络(自定义网桥中会自己分配ip地址和网关地址)

  • 创建自定义网桥 ```shell [root@centos-01 ~]# docker network create —driver bridge my-net c62a2e3d6ad5dece71a470cde488ad9c41c24fac9380689f43905ffbd70d4389

[root@centos-01 ~]# brctl show bridge name bridge id STP enabled interfaces br-c62a2e3d6ad5 8000.0242ae4b8680 no
docker0 8000.0242cbf135ea no

[root@centos-01 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE f6524186651f bridge bridge local ed7ffc7437dd host host local c62a2e3d6ad5 my-net bridge local fa66bc1a17f4 none null local

  1. 看到新增网桥`br-c62a2e3d6ad5` `c62a2e3d6ad5` 是新建网桥 `my-net` 的短id`docker network inspect` 看下 `my-net` 的配置信息
  2. ```bash
  3. [root@centos-01 ~]# docker network inspect my-net
  4. [
  5. {
  6. "Name": "my-net",
  7. "Id": "c62a2e3d6ad5dece71a470cde488ad9c41c24fac9380689f43905ffbd70d4389",
  8. "Created": "2021-06-18T11:16:55.17530733+08:00",
  9. "Scope": "local",
  10. "Driver": "bridge",
  11. "EnableIPv6": false,
  12. "IPAM": {
  13. "Driver": "default",
  14. "Options": {},
  15. "Config": [
  16. {
  17. "Subnet": "172.19.0.0/16",
  18. "Gateway": "172.19.0.1"
  19. }
  20. ]
  21. },
  22. "Internal": false,
  23. "Attachable": false,
  24. "Ingress": false,
  25. "ConfigFrom": {
  26. "Network": ""
  27. },
  28. "ConfigOnly": false,
  29. "Containers": {},
  30. "Options": {},
  31. "Labels": {}
  32. }
  33. ]

这里 172.19.0.0/16Docker 自动分配的IP网段,网关为 172.19.0.1 ,在 my-net 对应的网桥br-c62a2e3d6ad5

注:如果想要指定IP网段。只需在创建网段时指定 --subnet-gateway 参数即可,命令如下:

  1. docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my-net

容器要使用新的网络,需要在启动时通过 --network 指定

  1. [root@centos-01 ~]# docker run -d --network=my-net --name nginx nginx
  2. 2104ba150f62d9ea552d09b05ccb0b376db10ce054b50908d16361a639826b84

查看容器配置
image.png
容器分配到的IP为 172.19.0.2 到目前为止,这里的IP是docker自动从 subnet 中分配的,如果想要指定一个静态IP可以通过 --ip 指定
这里有个问题需要注意

  1. [root@centos-01 ~]# docker run -d --network=my-net --ip 172.19.0.110 --name nginx nginx
  2. 5506e7ca82c8252727d8e7e4ae2c25ae1e3e5276fcf031112a17702ac4194e77
  3. docker: Error response from daemon: user specified IP address is supported only when connecting to networks with user configured subnets.

Docker中只有使用 --subnet 创建的网络才能指定静态IP。上面也有提到这点,因此在使用 docker-compose 或者 docker run 命令创建容器时,如果需要指定可以使用 :

  • –subnet 指定 IP
  • –gateway 指定网关
  • my-net 指定网桥名称

    同网桥下的容器通信

  • nginx1:

    1. [root@centos-01 ~]# docker run -d --name nginx1 --network=my-net nginx
    2. 96a448f4c29fef3038abdd91410d7f9264ef3620cb1a80974bcb63694e61953c

    image.png

    1. [root@centos-01 ~]# docker exec -it nginx1 /bin/bash
    2. root@96a448f4c29f:/# ping 172.19.0.3
    3. PING 172.19.0.3 (172.19.0.3) 56(84) bytes of data.
    4. 64 bytes from 172.19.0.3: icmp_seq=1 ttl=64 time=0.175 ms
    5. 64 bytes from 172.19.0.3: icmp_seq=2 ttl=64 time=0.052 ms
    6. 64 bytes from 172.19.0.3: icmp_seq=3 ttl=64 time=0.044 ms

    nginx2:

    1. [root@centos-01 ~]# docker run -d --name nginx2 --network=my-net nginx
    2. 8d47f51c8138e0ef935f3e8a7447c16a655ce21f18e87a0af0bc6e5ea2daaa21

    image.png

    1. [root@centos-01 ~]# docker exec -it nginx2 /bin/bash
    2. root@8d47f51c8138:/# ping 172.19.0.2
    3. PING 172.19.0.2 (172.19.0.2) 56(84) bytes of data.
    4. 64 bytes from 172.19.0.2: icmp_seq=1 ttl=64 time=0.043 ms
    5. 64 bytes from 172.19.0.2: icmp_seq=2 ttl=64 time=0.064 ms
    6. 64 bytes from 172.19.0.2: icmp_seq=3 ttl=64 time=0.049 ms

    结果可知:同一网络中的容器、网关之间都是可以通信的

    容器跨网桥通信

    这里有个问题是 my-net 与默认的 bridge 网络是否可以通信,正常来说两个网络属于不同的网桥应该不能通信,测试一下: ```bash [root@centos-01 ~]# docker ps -a 1CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8d47f51c8138 nginx “/docker-entrypoint.…” 32 minutes ago Up 32 minutes 80/tcp nginx2 96a448f4c29f nginx “/docker-entrypoint.…” 32 minutes ago Up 32 minutes 80/tcp nginx1

[root@centos-01 ~]# docker run -d —name nginx3 nginx 220cc3010771f7a3b0c778d4d5668baa860e969e8d5a6cde830290b31dad89fd

[root@centos-01 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 220cc3010771 nginx “/docker-entrypoint.…” 3 seconds ago Up 2 seconds 80/tcp nginx3 8d47f51c8138 nginx “/docker-entrypoint.…” 32 minutes ago Up 32 minutes 80/tcp nginx2 96a448f4c29f nginx “/docker-entrypoint.…” 32 minutes ago Up 32 minutes 80/tcp nginx1

[root@centos-01 ~]# brctl show bridge name bridge id STP enabled interfaces br-c62a2e3d6ad5 8000.0242ae4b8680 no veth0a1e1ba veth1069d0c docker0 8000.0242cbf135ea no veth3147348

[root@centos-01 ~]# docker inspect nginx3

  1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/21738459/1623995046046-c86a1d3d-6278-4e94-84c5-0aff61970c17.png#align=left&display=inline&height=402&id=mcBIW&margin=%5Bobject%20Object%5D&name=image.png&originHeight=402&originWidth=1155&size=42319&status=done&style=shadow&width=1155)<br />新建容器 `nginx3` 但不指定网桥所以会使用默认的 `bridge` 网络,结果显示 `br-c62a2e3d6ad5` 上绑定了两个虚拟网卡 `veth0a1e1ba` 和 `veth1069d0c` 对应 `nginx1` 和 `nginx2` , `docker0` 上绑定了 `veth3147348` ,对应 `ngnix3` ,分配的IP地址是 `172.17.0.2` 也可以看出来不在一个网段。
  2. ```bash
  3. [root@centos-01 ~]# docker exec -it nginx1 /bin/bash
  4. root@96a448f4c29f:/# ping 172.17.0.2
  5. PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.

结果可知:不同网段的确是 **ping** 不通的

思考:“不同的网络如果加上路由是否可以通信”,如果host上对每个网络都有一条路由,同时操作系统上打开了 ip forwarding ,host就成了一个路由器,挂接在不同网桥上的网络就能够相互通信。试试看

查看路由表

  1. [root@centos-01 ~]# ip r
  2. default via 192.168.126.67 dev ens33 proto static metric 100
  3. 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
  4. 172.19.0.0/16 dev br-c62a2e3d6ad5 proto kernel scope link src 172.19.0.1
  5. 192.168.126.0/24 dev ens33 proto kernel scope link src 192.168.126.143 metric 100

image.png
172.17.0.0/16 和172..16.0/24两个网络的路由都定义好了。再看看 ip forwarding

  1. [root@centos-01 ~]# sysctl net.ipv4.ip_forward
  2. net.ipv4.ip_forward = 1

这里看到路由转发也是开启的,条件都满足的情况下为什么还不行呢,再看看 iptables
image.png

这里看到原因是因为: **iptables** **DROP** 掉了网桥 **dockero****br-c62a2e3d6ad5** 之间双向的流量。从规则命名 **DOCKER-ISOLATION** 可知 **docker** 在设计上就是要隔离不同的 **netwrok** ,这里可以通过使用 **docker network connect** 命令添加一块网卡来实现不同网桥容器通信

  1. [root@centos-01 ~]# docker ps -a
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 220cc3010771 nginx "/docker-entrypoint.…" 34 hours ago Up 34 hours 80/tcp nginx3
  4. 8d47f51c8138 nginx "/docker-entrypoint.…" 34 hours ago Up 34 hours 80/tcp nginx2
  5. 96a448f4c29f nginx "/docker-entrypoint.…" 34 hours ago Up 34 hours 80/tcp nginx1
  6. [root@centos-01 ~]# docker network connect my-net 220cc3010771 #将nginx3连接到my-net中
  1. [root@centos-01 ~]# docker exec -it nginx1 /bin/bash
  2. root@96a448f4c29f:/# ping 172.19.0.4
  3. PING 172.19.0.4 (172.19.0.4) 56(84) bytes of data.
  4. 64 bytes from 172.19.0.4: icmp_seq=1 ttl=64 time=0.130 ms
  5. 64 bytes from 172.19.0.4: icmp_seq=2 ttl=64 time=0.046 ms
  6. 64 bytes from 172.19.0.4: icmp_seq=3 ttl=64 time=0.060 ms

此时发现 nginx1 已经可以访问到 nginx3 了。

外部访问容器

容器访问外网是通过 iptablesSNAT 实现的,docker容器在启动的时候,如果不指定端口映射参数,容器外部无法通过网络访问容器内的网络应用和服务。需要设置端口映射,也可以使用 Dockerfile 文件中的 EXPOSE 指令来配置。

端口映射使用 **-p****-P** 来实现

  • -p 容器内部端口绑定到指定的主机端口
  • -P 容器内部端口随机映射到主机的高端口

    IP:HOSTPORT:CONTAINERPORT

    指定ip:指定宿主机port:指定容器port : 适用于映射到指定地址的指定端口

  1. [root@wangpengliang ~]# docker run -it -d -p 127.0.0.1:5000:5000 --name redis redis #将容器的5000端口映射到指定地址127.0.0.1的5000端口上
  2. c2179a906b05e210c42eb6561cf76285f3391e703d5db249a154e06d4d025f28
  3. [root@wangpengliang ~]# docker ps -a
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. 4927cb5dfe67 redis "docker-entrypoint.s…" 49 seconds ago Up 48 seconds 127.0.0.1:5000->5000/tcp, 6379/tcp redis

IP::CONTAINERPORT

指定ip、未指定宿主机port(随机)、指定容器port :适用于映射到指定地址的任意端口

  1. [root@wangpengliang ~]# docker run -it -d -p 127.0.0.1::5000 --name redis redis #将容器的5000端口映射到指定地址127.0.0.1的任意端口上
  2. c19e6b8f249db67b2f50455d35159f718a1d68e6efd02c106f0148bae14ba496
  3. [root@wangpengliang ~]# docker ps -a
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. c19e6b8f249d redis "docker-entrypoint.s…" 2 seconds ago Up 2 seconds 6379/tcp, 127.0.0.1:49153->5000/tcp redis

HOSTPORT:CONTAINERPORT

未指定ip、指定宿主机port、指定容器port :适用于将容器指定端口指定映射到宿主机的一个端口上(映射所有接口地址)

  1. [root@wangpengliang ~]# docker run -it -d -p 80:8000 --name redis redis #将容器的8000端口映射到宿主机的80端口上
  2. 3ad63ffd90665413e644cd16f2eb7d404fcb14bb509eee05f67e0db8f1c067a4
  3. [root@wangpengliang ~]# docker ps -a
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. 3ad63ffd9066 redis "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 6379/tcp, 0.0.0.0:80->8000/tcp, :::80->8000/tcp redis

绑定 UDP 端口

默认情况下 -p-P 绑定的都是 tcp 协议端口,如果要绑定 udp 协议端口,只能使用 -p 参数,且在最后添加 /udp 字符串

  1. [root@wangpengliang ~]# docker run -d -p 127.0.0.1:5553:5000/udp jcdemo/flaskapp
  2. 6aa30aa070a6e77f0d3f8653df69c654edf6e8bb68cea475aefbc68f6f7f9572

绑定多个端口

多次使用 -p 参数可以映射多个端口

  1. [root@wangpengliang ~]# docker run -d -p 5552:5000 -p 5551:5001 jcdemo/flaskapp
  2. fa116ae4f5c19d82d9d4f40560c3219c85540a21d88f7fa999b60382ab57524a

查看映射端口配置

  1. docker port container_ID #容器ID
  2. #结果输出
  3. 80/tcp -> 0.0.0.0:800

跨主机网络解决方案

TODO