原理
核心:
- 使用了 Linux 的虚拟化网络技术 veth-pair,在容器内和 docker0 分别创建虚拟网卡,互相连接
- 容器删除,对应 veth-pair 也会被删除
安装 docker 后,查看本机 ip 信息
lo: 本机回环地址
eth0:内网地址
docker0:docker 地址
只要安装了 docker,就会有 docker0 网卡,通过 veth-pair 桥接
veth-pair:一对虚拟设备接口,一端连着协议,一端彼此相连,用来链接虚拟网络设备
ip addr1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000link/ether 00:16:3e:04:66:39 brd ff:ff:ff:ff:ff:ffinet 172.19.177.207/20 brd 172.19.191.255 scope global dynamic eth0valid_lft 314899514sec preferred_lft 314899514secinet6 fe80::216:3eff:fe04:6639/64 scope linkvalid_lft forever preferred_lft forever3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group defaultlink/ether 02:42:fe:63:be:d4 brd ff:ff:ff:ff:ff:ffinet 172.17.0.1/16 brd 172.17.255.255 scope global docker0valid_lft forever preferred_lft foreverinet6 fe80::42:feff:fe63:bed4/64 scope linkvalid_lft forever preferred_lft forever
启动一个容器
容器内部 docker 会分配 eth0,
这里可以看到宿主机 是 172.17.0.1,容器内是 172.17.0.2,属于同一个网段
ip addr1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever60: eth0@if61: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defaultlink/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0valid_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个
通过 veth-pair 容器和容器之间都能 ping 通ip addr1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000link/ether 00:16:3e:04:66:39 brd ff:ff:ff:ff:ff:ffinet 172.19.177.207/20 brd 172.19.191.255 scope global dynamic eth0valid_lft 314857120sec preferred_lft 314857120secinet6 fe80::216:3eff:fe04:6639/64 scope linkvalid_lft forever preferred_lft forever3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defaultlink/ether 02:42:fe:63:be:d4 brd ff:ff:ff:ff:ff:ffinet 172.17.0.1/16 brd 172.17.255.255 scope global docker0valid_lft forever preferred_lft foreverinet6 fe80::42:feff:fe63:bed4/64 scope linkvalid_lft forever preferred_lft forever61: vethf7c3e9f@if60: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group defaultlink/ether 62:9b:d9:39:17:cb brd ff:ff:ff:ff:ff:ff link-netnsid 0inet6 fe80::609b:d9ff:fe39:17cb/64 scope linkvalid_lft forever preferred_lft forever
—link 根据容器名ping 通(一般不用)
使用—link,容器可以实现通过容器名访问对应容器
# 第一个容器docker run -d -P -it --name tomcat01 tomcat# 第二个容器 --link 连接第一个容器docker run -d -P -it --name tomcat02 --link tomcat01 tomcat# 通过容器名 ping,2 ping 1,可以 ping 通docker exec -it tomcat02 ping tomcat01# 但是 1 ping 2,就不行了docker exec -it tomcat01 ping tomcat02
查看 容器02 的 /etc/hosts 会发现
172.17.0.2 tomcat01 c977b7b29a2c
所以 —link 其实就是修改了 hosts
所以这个配置方法并不灵活,如果 ip 改了,这里不能随之改变。
自定义网络-容器互连(常用)
docker0 不支持容器名访问,通过 —link 实现不灵活。
# bridge 桥接(docker 默认,相当于docker run --net bridge tomcat,自定义的网络也是 bridge 桥接模式)# none 不配置网络# host 与宿主机共享网络docker network lsNETWORK ID NAME DRIVER SCOPEccdc3cb6aaa2 bridge bridge local78252cc87d7f host host localb807057d7b53 none null local
创建自定义网络
docker network create --helpUsage: docker network create [OPTIONS] NETWORKCreate a networkOptions:--attachable Enable manual container attachment--aux-address map Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])--config-from string The network from which to copy the configuration--config-only Create a configuration only network-d, --driver string Driver to manage the Network (default "bridge")--gateway strings IPv4 or IPv6 Gateway for the master subnet--ingress Create swarm routing-mesh network--internal Restrict external access to the network--ip-range strings Allocate container ip from a sub-range--ipam-driver string IP Address Management Driver (default "default")--ipam-opt map Set IPAM driver specific options (default map[])--ipv6 Enable IPv6 networking--label list Set metadata on a network-o, --opt map Set driver specific options (default map[])--scope string Control the network's scope--subnet strings Subnet in CIDR format that represents a network segment
创建
# subnet 子网地址 192.168.0.2 ~ 192.168.255.255# gateway 网关docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
将两个容器连接到刚创建好的 网络
docker run -d -P --name tomcat-net-01 --net mynet tomcatdocker run -d -P --name tomcat-net-02 --net mynet tomcat
查看网络详情 会发现 Containers 有两个容器的信息
docker network inspect mynet
连接容器到另一个网络
docker network connect --helpUsage: docker network connect [OPTIONS] NETWORK CONTAINERConnect a container to a networkOptions:--alias strings Add network-scoped alias for the container--driver-opt strings driver options for the network--ip string IPv4 address (e.g., 172.30.100.104)--ip6 string IPv6 address (e.g., 2001:db8::33)--link list Add link to another container--link-local-ip strings Add a link-local address for the container
tomcat01原本只连接 docker01,现在要连接自定义的 mynet
docker network connect mynet tomcat01
通过 Network Namespace 隔离网络
#查看本机 network namespacesudo ip netns list# 添加 netns testsudo ip netns add test# 删除 netnssudo ip netns delete test# 查看 netns ipsudo ip netns exec test ip a# 查看本机 ip linkip link# Namespace 间通过 Veth 对连接,创建连接对sudo ip link add veth-test1 type veth peer name veth-test2# 查看本机 ip link 会发现 没有ip 有mac地址的 两个连接# 把 veth-test1 添加到 test1, veth-test2 添加到 test2 实现连接sudo ip link set veth-test1 netns test1# 执行完后 查看本机 ip link veth-test1 会没有,查看test1 的 ip link 会发现 veth-test1# 同里添加 veth-test2 到 test2# 此时 veth-test1 和 veth-test2 的状态都是 DOWN,没有 ip 地址,需要分别配置 ip 地址sudo ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1sudo ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2# 分配后需要 up 端口, 即可连通 netns test1 和 test2,可互相 ping 通sudo ip netns exec test1 ip link set dev veth-test1 upsudo ip netns exev test2 ip link set dev veth-test2 up
容器访问外网:
Docker bridge:
列出 Docker 本机网络:
→ docker network lsNETWORK ID NAME DRIVER SCOPEb10c9129bbd3 bridge bridge local0d6309539bbb host host local3163ea18c34f none null local
三个 network :
- bridge:创建容器默认连接到 bridge
- host:连接到 host 的容器没有独立的 namespace,只和主机共享
- none:连接到none的容器只能通过本地命令访问
容器通过 bridge 连接网络,看下 bridge 的网络信息
→ docker network inspect b10c9129bbd3[{"Name": "bridge","Id": "b10c9129bbd397495fb0f9b744274e03a80f927a485b3a2e2aa634c6122f583d","Created": "2019-06-09T03:21:28.552026465Z","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": null,"Config": [{"Subnet": "172.17.0.0/16","Gateway": "172.17.0.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {"3d4b7de92240855d12dd74faab4fb2e72f666c39885afe5cc9237e1021e704f7": {"Name": "recursing_volhard","EndpointID": "9b03e10d275d45a1151f71949d4d72c22b2a17dcb20cda2300b25511e84d8b0f","MacAddress": "02:42:ac:11:00:02","IPv4Address": "172.17.0.2/16","IPv6Address": ""}},"Options": {"com.docker.network.bridge.default_bridge": "true","com.docker.network.bridge.enable_icc": "true","com.docker.network.bridge.enable_ip_masquerade": "true","com.docker.network.bridge.host_binding_ipv4": "0.0.0.0","com.docker.network.bridge.name": "docker0","com.docker.network.driver.mtu": "1500"},"Labels": {}}]
在 Containers 里面可以看到 连接中的容器网络信息
执行 ip a 查看 本机 网络信息会发现 有一个 docker0,创建的容器都会创建一个 network namespace 通过 veth 对连接到 docker0
容器连接到自定义 bridge:
创建自定义 bridge:
docker network create -d bridge my-bridge
新建容器时 —network my-bridge 可以指定网络为 my-bridge:
docker run -d --name test --network my-bridge
已运行容器连接到自定义 bridge:
docker network connect my-bridge test2
自此 test 和 test2 能相互 ping 通。但是都连接到系统默认的 docker0 这个bridge 不能 ping 通
端口映射:
创建容器时使用 -p xx(本机):xx(容器) 做端口映射:
docker run --name web -d -p 80:80 nginx
