7.1 理解 Docker0

每一个安装了 Docker 的linux主机都有一个docker0的虚拟网卡。这是个桥接网卡,使用了veth-pair 技术!

7.1.1 查看本地ip ip addr

  1. # 我们查看主机的 ip addr
  2. [root@kuangshen ~]# ip addr
  3. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN groupdefault qlen 1000
  4. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  5. inet 127.0.0.1/8 scope host lo
  6. valid_lft forever preferred_lft forever
  7. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast stateUP group default qlen 1000
  8. link/ether 00:16:3e:30:27:f4 brd ff:ff:ff:ff:ff:ff
  9. inet 172.17.90.138/20 brd 172.17.95.255 scope global dynamic eth0
  10. valid_lft 310954997sec preferred_lft 310954997sec
  11. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue stateUP group default
  12. link/ether 02:42:bb:71:07:06 brd ff:ff:ff:ff:ff:ff
  13. inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
  14. valid_lft forever preferred_lft forever

7.1.2 每启动一个容器,linux主机就会多了一个虚拟网卡

  1. # 我们启动了一个tomcat01,主机的ip地址多了一个 123: vethc8584ea@if122
  2. # 然后我们在tomcat01容器中查看容器的ip是 122: eth0@if123
  3. # 我们再启动一个tomcat02观察
  4. [root@kuangshen ~]# docker run -d -P --name tomcat02 tomcat
  5. # 然后发现linux主机上又多了一个网卡 125: veth021eeea@if124:
  6. # 我们看下tomcat02的容器内ip地址是 124: eth0@if125:
  7. [root@kuangshen ~]# docker exec -it tomcat02 ip addr
  8. # 观察现象:
  9. # tomcat --- linux主机 vethc8584ea@if122 ---- 容器内 eth0@if123
  10. # tomcat --- linux主机 veth021eeea@if124 ---- 容器内 eth0@if125
  11. # 相信到了这里,大家应该能看出点小猫腻了吧!只要启动一个容器,就有一对网卡

结论:

  • veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈一端彼此相连着
  • 正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备!
  • Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等,以此构建出非常复杂的虚拟网络结构,比如 OpenStack Neutron。

7.1.3 网络模型图

image.png
结论:
tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动 默认都是docker0网络。
docker默认会给容器分配一个可用ip。

7.1.4 小结

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据 Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网 关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接 通信。
image.png
Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机容器内分别创建一个虚拟接口,并 让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中 进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容 器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。

7.2 —Link

作用:通过服务名直接访问容器,而不直接使用ip

思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们 能不能使用服务名访问呢?
jdbc:mysql://mysql:3306,这样的话哪怕mysql重启,我们也不需要修改配置了!docker提供了 —link 的操作!

  1. # 我们再启动一个tomcat03,但是启动的时候连接tomcat02
  2. [root@kuangshen ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
  3. a3a4a17a2b707766ad4f2bb967ce1d94f658cd4cccef3bb8707395cdc71fa1e7
  4. # 这个时候,我们就可以使用tomcat03 ping通tomcat02 了
  5. [root@kuangshen ~]# docker exec -it tomcat03 ping tomcat02
  6. PING tomcat02 (172.18.0.3) 56(84) bytes of data.
  7. 64 bytes from tomcat02 (172.18.0.3): icmp_seq=1 ttl=64 time=0.093 ms
  8. 64 bytes from tomcat02 (172.18.0.3): icmp_seq=2 ttl=64 time=0.066 ms
  9. # 再来测试,tomcat03 是否可以ping tomcat01 失败
  10. [root@kuangshen ~]# docker exec -it tomcat03 ping tomcat01
  11. ping: tomcat01: Name or service not known
  12. # 再来测试,tomcat02 是否可以ping tomcat03 反向也ping不通
  13. [root@kuangshen ~]# docker exec -it tomcat02 ping tomcat03
  14. ping: tomcat03: Name or service not known

思考,这个原理是什么呢?我们进入tomcat03中查看下host配置文件

  1. [root@kuangshen ~]# docker exec -it tomcat03 cat /etc/hosts
  2. 127.0.0.1 localhost
  3. ::1 localhost ip6-localhost ip6-loopback
  4. fe00::0 ip6-localnet
  5. ff00::0 ip6-mcastprefix
  6. ff02::1 ip6-allnodes
  7. ff02::2 ip6-allrouters
  8. 172.18.0.3 tomcat02 b80da266a3ad # 发现tomcat2直接被写在这里
  9. 172.18.0.4 a3a4a17a2b70
  10. # 所以这里其实就是配置了一个 hosts 地址而已!
  11. # 原因:--link的时候,直接把需要link的主机的域名和ip直接配置到了hosts文件中了。

Tip:—link早都过时了,我们不推荐使用!我们可以使用自定义网络的方式

7.3 自定义网络

7.3.1 基本命令查看

命令如下:

  1. C:\Users\Edward>docker network --help
  2. Usage: docker network COMMAND
  3. Manage networks
  4. Commands:
  5. connect Connect a container to a network
  6. create Create a network
  7. disconnect Disconnect a container from a network
  8. inspect Display detailed information on one or more networks
  9. ls List networks
  10. prune Remove all unused networks
  11. rm Remove one or more networks
  12. Run 'docker network COMMAND --help' for more information on a command.

7.3.2 查看所有网络

  1. C:\Users\Edward>docker network ls
  2. NETWORK ID NAME DRIVER SCOPE
  3. b9e59ff509b8 bridge bridge local
  4. 44a163eade93 host host local
  5. 036b5323cc88 none null local

所有网路模式:

网络模式 配置 说明
bridge 模式 —net=bridge 默认值,在Docker网桥docker0上为容器创建新的网络栈
none 模式 —net=none 不配置网络,用户可以稍后进入容器,自行配置
container 模式 — net=container:name/id 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。
host 模式 —net=host 容器和宿主机共享Network namespace
用户自定义 —net=自定义网络 用户自己使用network相关命令定义网络,创建容器的 时候可以指定为自己定义的网络

7.3.3 查看网络具体信息

  1. # 命令
  2. [root@kuangshen ~]# docker network inspect b9e59ff509b8
  3. [
  4. {
  5. "Name": "bridge",
  6. "Id": "b9e59ff509b82a5782b005af64e7143468c8a829681a2bd6f807ffa3c3f5d4ae",
  7. "Created": "2021-08-16T01:42:34.606664025Z",
  8. "Scope": "local",
  9. "Driver": "bridge",
  10. "EnableIPv6": false,
  11. "IPAM": {
  12. "Driver": "default",
  13. "Options": null,
  14. "Config": [
  15. {
  16. "Subnet": "172.17.0.0/16",
  17. "Gateway": "172.17.0.1"
  18. }
  19. ]
  20. },
  21. "Internal": false,
  22. "Attachable": false,
  23. "Ingress": false,
  24. "ConfigFrom": {
  25. "Network": ""
  26. },
  27. "ConfigOnly": false,
  28. "Containers": {
  29. "8e70d2b7f72aed016f6659d6ba5ee4cbc4e695e5100f7d3fa308e9c2788048c1": {
  30. "Name": "mysql5",
  31. "EndpointID": "19c9e8bf3f748b6477a0fb833109e81acad6ed5056cc9df9586904c978218cfb",
  32. "MacAddress": "02:42:ac:11:00:02",
  33. "IPv4Address": "172.17.0.2/16",
  34. "IPv6Address": ""
  35. }
  36. },
  37. "Options": {
  38. "com.docker.network.bridge.default_bridge": "true",
  39. "com.docker.network.bridge.enable_icc": "true",
  40. "com.docker.network.bridge.enable_ip_masquerade": "true",
  41. "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
  42. "com.docker.network.bridge.name": "docker0",
  43. "com.docker.network.driver.mtu": "1500"
  44. },
  45. "Labels": {}
  46. }
  47. ]

7.3.4 自定义网卡

默认我们不配置网络,也就相当于默认值 —net bridge 使用的docker0

docker run -d -P --name tomcat01 --net bridge tomcat

默认 docker0 网卡的特点:

  1. 它是默认的
  2. 域名访问不通
  3. —link 域名通了,但是删了又不行

7.3.4.1 创建网卡

  1. # 自定义创建的默认default "bridge"
  2. # 自定义创建一个网络网络
  3. [root@kuangshen ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
  4. 09bd09d8d3a6b33e6d19f49643dab551e5a45818baf4d5328aa7320c6dcfc236
  5. # 确认下
  6. [root@kuangshen ~]# docker network ls
  7. NETWORK ID NAME DRIVER SCOPE
  8. 4eb2182ac4b2 bridge bridge local
  9. ae2b6209c2ab host host local
  10. 09bd09d8d3a6 mynet bridge local # 自己创建的网卡
  11. c037f7ec7e57 none null local

7.3.4.2 创建容器使用自定义网卡

  1. [root@kuangshen ~]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
  2. 065f82e947c760c63539ab4c0de0d683787ec7ac6d0dcaa71f64e191319f9fe7
  3. [root@kuangshen ~]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
  4. 2e85d71afe87c87166786b0bbae2d90eefb969d716fcd78a21173add5956cb12
  5. [root@kuangshen ~]# docker ps
  6. CONTAINER ID IMAGE PORTS NAMES
  7. 2e85d71afe87 tomcat 0.0.0.0:32772->8080/tcp tomcat-net-02
  8. 065f82e947c7 tomcat 0.0.0.0:32771->8080/tcp tomcat-net-01
  9. # 再来查看下
  10. [root@kuangshen ~]# docker network inspect mynet
  11. [
  12. {
  13. "Name": "mynet",
  14. "Id":
  15. "09bd09d8d3a6b33e6d19f49643dab551e5a45818baf4d5328aa7320c6dcfc236",
  16. ............
  17. "Containers": {
  18. "065f82e947c760c63539ab4c0de0d683787ec7ac6d0dcaa71f64e191319f9fe7": {
  19. "Name": "tomcat-net-01",
  20. "EndpointID":
  21. "d61cef1bc294d7f10fb6d9b728735fc87bed79e4e02f5298374f0fab3e9b2da6",
  22. "MacAddress": "02:42:c0:a8:00:02",
  23. "IPv4Address": "192.168.0.2/16",
  24. "IPv6Address": ""
  25. },
  26. "2e85d71afe87c87166786b0bbae2d90eefb969d716fcd78a21173add5956cb12": {
  27. "Name": "tomcat-net-02",
  28. "EndpointID":
  29. "adbc37a20526c2985c3589382998a3d106ef722662c7b296a57d8a7c8f449f38",
  30. "MacAddress": "02:42:c0:a8:00:03",
  31. "IPv4Address": "192.168.0.3/16",
  32. "IPv6Address": ""
  33. }
  34. },
  35. "Options": {},
  36. "Labels": {}
  37. }
  38. ]
  39. # 我们来测试ping容器名和ip试试,都可以ping通
  40. [root@kuangshen ~]# docker exec -it tomcat-net-01 ping 192.168.0.3
  41. PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
  42. 64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.093 ms
  43. [root@kuangshen ~]# docker exec -it tomcat-net-01 ping tomcat-net-02
  44. PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
  45. 64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.063 ms
  46. 64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.066 ms

发现
我们自定义的网络docker都已经帮我们维护好了对应的关系
所以我们平时都可以这样使用网络,不使用 --link 效果一样,所有东西实时维护好,直接域名 ping 通。

7.4 网络连通

image.png
docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离:
大家公司项目部署的业务都非常多,假设我们有一个商城,我们会有订单业务(操作不同数据),会有 订单业务购物车业务(操作不同缓存)。如果在一个网络下,有的程序猿的恶意代码就不能防止了,所 以我们就在部署的时候网络隔离,创建两个桥接网卡,比如订单业务(里面的数据库,redis,mq,全 部业务 都在order-net网络下)其他业务在其他网络。

  • 跨网络操作别人(如tomcat1访问tomcat-net-01),可使用如下命令:

    1. docker network connect [OPTIONS] NETWORK CONTAINER
  • tomcat1访问tomcat-net-01 案例如下: ```shell [root@kuangshen ~]# docker network connect mynet tomcat01 # tomcat01就是左侧的tomcat1 [root@kuangshen ~]# docker network inspect mynet [ { …… “Containers”: {

    1. "065f82e947c760c63539ab4c0de0d683787ec7ac6d0dcaa71f64e191319f9fe7": {
    2. "Name": "tomcat-net-01",
    3. "EndpointID":
    4. "d61cef1bc294d7f10fb6d9b728735fc87bed79e4e02f5298374f0fab3e9b2da6",
    5. "MacAddress": "02:42:c0:a8:00:02",
    6. "IPv4Address": "192.168.0.2/16",
    7. "IPv6Address": ""
    8. },
    9. "2e85d71afe87c87166786b0bbae2d90eefb969d716fcd78a21173add5956cb12": {
    10. "Name": "tomcat-net-02",
    11. "EndpointID":
    12. "adbc37a20526c2985c3589382998a3d106ef722662c7b296a57d8a7c8f449f38",
    13. "MacAddress": "02:42:c0:a8:00:03",
    14. "IPv4Address": "192.168.0.3/16",
    15. "IPv6Address": ""
    16. },
    17. // 发现我们的tomcat01就进来这里了,tomcat01拥有了双ip
    18. // (一个是docker0默认分配的,一个是mynet分配的)
    19. "bcd122e0dcf6bf8c861eaa934911f98a5497a4954f3fde9575e496160bd23287": {
    20. "Name": "tomcat01",
    21. "EndpointID":
    22. "b2bf2342948e17048d872a4d5603c77e90d0e032439d510e86c10a1acc3928d9",
    23. "MacAddress": "02:42:c0:a8:00:04",
    24. "IPv4Address": "192.168.0.4/16",
    25. "IPv6Address": ""
    26. }

    }, …… } ]

tomcat01 可以ping通了

[root@kuangshen ~]# docker exec -it tomcat01 ping tomcat-net-01 PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data. 64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.071 ms 64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.067 ms

tomcat02 依旧ping不通,大家应该就理解了

[root@kuangshen ~]# docker exec -it tomcat02 ping tomcat-net-01 ping: tomcat-net-01: Name or service not known= ```