原理

核心:

  • 使用了 Linux 的虚拟化网络技术 veth-pair,在容器内和 docker0 分别创建虚拟网卡,互相连接
  • 容器删除,对应 veth-pair 也会被删除

安装 docker 后,查看本机 ip 信息
lo: 本机回环地址
eth0:内网地址
docker0:docker 地址

只要安装了 docker,就会有 docker0 网卡,通过 veth-pair 桥接
veth-pair:一对虚拟设备接口,一端连着协议,一端彼此相连,用来链接虚拟网络设备

  1. ip addr
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. inet6 ::1/128 scope host
  7. valid_lft forever preferred_lft forever
  8. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  9. link/ether 00:16:3e:04:66:39 brd ff:ff:ff:ff:ff:ff
  10. inet 172.19.177.207/20 brd 172.19.191.255 scope global dynamic eth0
  11. valid_lft 314899514sec preferred_lft 314899514sec
  12. inet6 fe80::216:3eff:fe04:6639/64 scope link
  13. valid_lft forever preferred_lft forever
  14. 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
  15. link/ether 02:42:fe:63:be:d4 brd ff:ff:ff:ff:ff:ff
  16. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  17. valid_lft forever preferred_lft forever
  18. inet6 fe80::42:feff:fe63:bed4/64 scope link
  19. valid_lft forever preferred_lft forever

启动一个容器
容器内部 docker 会分配 eth0,
这里可以看到宿主机 是 172.17.0.1,容器内是 172.17.0.2,属于同一个网段

  1. ip addr
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. 60: eth0@if61: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  7. link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  8. inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
  9. valid_lft forever preferred_lft forever

回到宿主机 查看 ip addr,会多出一个 veth 开头的网卡
并且
容器是 60: eth0@if61
宿主机 61: vethf7c3e9f@if60
也就是 60 连 61,61 连 60

  • 所以宿主机可以 ping 通容器,容器也可以 ping 宿主机
  • docker0相当于路由器,容器间也可以通过 veth-pair 转发, 互相访问
    • 不指定网络的情况下,都是 docker0路由,docker 会给容器分配一个默认可用的 ip
    • 最多65535个
      1. ip addr
      2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
      3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
      4. inet 127.0.0.1/8 scope host lo
      5. valid_lft forever preferred_lft forever
      6. inet6 ::1/128 scope host
      7. valid_lft forever preferred_lft forever
      8. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
      9. link/ether 00:16:3e:04:66:39 brd ff:ff:ff:ff:ff:ff
      10. inet 172.19.177.207/20 brd 172.19.191.255 scope global dynamic eth0
      11. valid_lft 314857120sec preferred_lft 314857120sec
      12. inet6 fe80::216:3eff:fe04:6639/64 scope link
      13. valid_lft forever preferred_lft forever
      14. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
      15. link/ether 02:42:fe:63:be:d4 brd ff:ff:ff:ff:ff:ff
      16. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
      17. valid_lft forever preferred_lft forever
      18. inet6 fe80::42:feff:fe63:bed4/64 scope link
      19. valid_lft forever preferred_lft forever
      20. 61: vethf7c3e9f@if60: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
      21. link/ether 62:9b:d9:39:17:cb brd ff:ff:ff:ff:ff:ff link-netnsid 0
      22. inet6 fe80::609b:d9ff:fe39:17cb/64 scope link
      23. valid_lft forever preferred_lft forever
      通过 veth-pair 容器和容器之间都能 ping 通

docker0相当于路由器,容器默认连接到 docker0

—link 根据容器名ping 通(一般不用)

使用—link,容器可以实现通过容器名访问对应容器

  1. # 第一个容器
  2. docker run -d -P -it --name tomcat01 tomcat
  3. # 第二个容器 --link 连接第一个容器
  4. docker run -d -P -it --name tomcat02 --link tomcat01 tomcat
  5. # 通过容器名 ping,2 ping 1,可以 ping 通
  6. docker exec -it tomcat02 ping tomcat01
  7. # 但是 1 ping 2,就不行了
  8. docker exec -it tomcat01 ping tomcat02

查看 容器02 的 /etc/hosts 会发现
172.17.0.2 tomcat01 c977b7b29a2c
所以 —link 其实就是修改了 hosts

所以这个配置方法并不灵活,如果 ip 改了,这里不能随之改变。

自定义网络-容器互连(常用)

docker0 不支持容器名访问,通过 —link 实现不灵活。

  1. # bridge 桥接(docker 默认,
  2. 相当于docker run --net bridge tomcat,自定义的网络也是 bridge 桥接模式)
  3. # none 不配置网络
  4. # host 与宿主机共享网络
  5. docker network ls
  6. NETWORK ID NAME DRIVER SCOPE
  7. ccdc3cb6aaa2 bridge bridge local
  8. 78252cc87d7f host host local
  9. b807057d7b53 none null local

创建自定义网络

  1. docker network create --help
  2. Usage: docker network create [OPTIONS] NETWORK
  3. Create a network
  4. Options:
  5. --attachable Enable manual container attachment
  6. --aux-address map Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
  7. --config-from string The network from which to copy the configuration
  8. --config-only Create a configuration only network
  9. -d, --driver string Driver to manage the Network (default "bridge")
  10. --gateway strings IPv4 or IPv6 Gateway for the master subnet
  11. --ingress Create swarm routing-mesh network
  12. --internal Restrict external access to the network
  13. --ip-range strings Allocate container ip from a sub-range
  14. --ipam-driver string IP Address Management Driver (default "default")
  15. --ipam-opt map Set IPAM driver specific options (default map[])
  16. --ipv6 Enable IPv6 networking
  17. --label list Set metadata on a network
  18. -o, --opt map Set driver specific options (default map[])
  19. --scope string Control the network's scope
  20. --subnet strings Subnet in CIDR format that represents a network segment

创建

  1. # subnet 子网地址 192.168.0.2 ~ 192.168.255.255
  2. # gateway 网关
  3. docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

将两个容器连接到刚创建好的 网络

  1. docker run -d -P --name tomcat-net-01 --net mynet tomcat
  2. docker run -d -P --name tomcat-net-02 --net mynet tomcat

查看网络详情 会发现 Containers 有两个容器的信息

  1. docker network inspect mynet

现在就可以通过容器名字互相 ping 通了

连接容器到另一个网络

  1. docker network connect --help
  2. Usage: docker network connect [OPTIONS] NETWORK CONTAINER
  3. Connect a container to a network
  4. Options:
  5. --alias strings Add network-scoped alias for the container
  6. --driver-opt strings driver options for the network
  7. --ip string IPv4 address (e.g., 172.30.100.104)
  8. --ip6 string IPv6 address (e.g., 2001:db8::33)
  9. --link list Add link to another container
  10. --link-local-ip strings Add a link-local address for the container

tomcat01原本只连接 docker01,现在要连接自定义的 mynet

  1. docker network connect mynet tomcat01

通过 Network Namespace 隔离网络

  1. #查看本机 network namespace
  2. sudo ip netns list
  3. # 添加 netns test
  4. sudo ip netns add test
  5. # 删除 netns
  6. sudo ip netns delete test
  7. # 查看 netns ip
  8. sudo ip netns exec test ip a
  9. # 查看本机 ip link
  10. ip link
  11. # Namespace 间通过 Veth 对连接,创建连接对
  12. sudo ip link add veth-test1 type veth peer name veth-test2
  13. # 查看本机 ip link 会发现 没有ip 有mac地址的 两个连接
  14. # 把 veth-test1 添加到 test1, veth-test2 添加到 test2 实现连接
  15. sudo ip link set veth-test1 netns test1
  16. # 执行完后 查看本机 ip link veth-test1 会没有,查看test1 的 ip link 会发现 veth-test1
  17. # 同里添加 veth-test2 到 test2
  18. # 此时 veth-test1 和 veth-test2 的状态都是 DOWN,没有 ip 地址,需要分别配置 ip 地址
  19. sudo ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1
  20. sudo ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2
  21. # 分配后需要 up 端口, 即可连通 netns test1 和 test2,可互相 ping 通
  22. sudo ip netns exec test1 ip link set dev veth-test1 up
  23. sudo ip netns exev test2 ip link set dev veth-test2 up

容器访问外网:

通过 iptable NAT 实现网络地址转换

Docker bridge:

列出 Docker 本机网络:

  1. docker network ls
  2. NETWORK ID NAME DRIVER SCOPE
  3. b10c9129bbd3 bridge bridge local
  4. 0d6309539bbb host host local
  5. 3163ea18c34f none null local

三个 network :

  • bridge:创建容器默认连接到 bridge
  • host:连接到 host 的容器没有独立的 namespace,只和主机共享
  • none:连接到none的容器只能通过本地命令访问

容器通过 bridge 连接网络,看下 bridge 的网络信息

  1. docker network inspect b10c9129bbd3
  2. [
  3. {
  4. "Name": "bridge",
  5. "Id": "b10c9129bbd397495fb0f9b744274e03a80f927a485b3a2e2aa634c6122f583d",
  6. "Created": "2019-06-09T03:21:28.552026465Z",
  7. "Scope": "local",
  8. "Driver": "bridge",
  9. "EnableIPv6": false,
  10. "IPAM": {
  11. "Driver": "default",
  12. "Options": null,
  13. "Config": [
  14. {
  15. "Subnet": "172.17.0.0/16",
  16. "Gateway": "172.17.0.1"
  17. }
  18. ]
  19. },
  20. "Internal": false,
  21. "Attachable": false,
  22. "Ingress": false,
  23. "ConfigFrom": {
  24. "Network": ""
  25. },
  26. "ConfigOnly": false,
  27. "Containers": {
  28. "3d4b7de92240855d12dd74faab4fb2e72f666c39885afe5cc9237e1021e704f7": {
  29. "Name": "recursing_volhard",
  30. "EndpointID": "9b03e10d275d45a1151f71949d4d72c22b2a17dcb20cda2300b25511e84d8b0f",
  31. "MacAddress": "02:42:ac:11:00:02",
  32. "IPv4Address": "172.17.0.2/16",
  33. "IPv6Address": ""
  34. }
  35. },
  36. "Options": {
  37. "com.docker.network.bridge.default_bridge": "true",
  38. "com.docker.network.bridge.enable_icc": "true",
  39. "com.docker.network.bridge.enable_ip_masquerade": "true",
  40. "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
  41. "com.docker.network.bridge.name": "docker0",
  42. "com.docker.network.driver.mtu": "1500"
  43. },
  44. "Labels": {}
  45. }
  46. ]

在 Containers 里面可以看到 连接中的容器网络信息
执行 ip a 查看 本机 网络信息会发现 有一个 docker0,创建的容器都会创建一个 network namespace 通过 veth 对连接到 docker0

容器连接到自定义 bridge:

创建自定义 bridge:

  1. docker network create -d bridge my-bridge

新建容器时 —network my-bridge 可以指定网络为 my-bridge:

  1. docker run -d --name test --network my-bridge

已运行容器连接到自定义 bridge:

  1. docker network connect my-bridge test2

自此 test 和 test2 能相互 ping 通。但是都连接到系统默认的 docker0 这个bridge 不能 ping 通

端口映射:

创建容器时使用 -p xx(本机):xx(容器) 做端口映射:

  1. docker run --name web -d -p 80:80 nginx