一、前言
本系列是根据 B 站 尚硅谷 Docker 视频 学习记录笔记。因为没有视频课件,部分内容摘自 https://www.yuque.com/tmfl/cloud/dketq0。
本系列仅为自身学习笔记记录使用,记录存在偏差,推荐阅读原视频内容或本文参考笔记。
二、简单介绍
docker安装并启动服务后,会在宿主机中添加一个虚拟网卡。
在Docker服务启动前,使用 ifconfig 或 ip addr 查看网卡信息:
- ens33或eth0:本机网卡
- lo:本机回环网络网卡
- 可能有virbr0(CentOS安装时如果选择的有相关虚拟化服务,就会多一个以网桥连接的私网地址的virbr0网卡,作用是为连接虚拟网卡提供NAT访问外网的功能。如果要移除该服务,可以使用 yum remove libvirt-libs.x86_64)
使用 systemctl start docker启动Docker服务后,会多出一个 docker0 网卡。
作用:
- 容器间的互联和通信以及端口映射
- 容器IP变动时候可以通过服务名直接网络通信而不受到影响
Docker容器的网络隔离,是通过Linux内核特性 namespace和 cgroup 实现的。
Docker 启动后会产生一个 docker0 的虚拟网桥,如下图:
四、基本命令
-
查看docker 网络模式
# 查看 docker 网络 [root@localhost jdk]# docker network ls NETWORK ID NAME DRIVER SCOPE 434c8b2478c5 bridge bridge local 9a997978179d host host local 505d72cea94b none null local # 查看 network 命令帮助 [root@localhost jdk]# docker network --helpUsage: docker network COMMANDManage networksCommands:connect Connect a container to a networkcreate Create a networkdisconnect Disconnect a container from a networkinspect Display detailed information on one or more networksls List networksprune Remove all unused networksrm Remove one or more networksRun 'docker network COMMAND --help' for more information on a command. # 手动创建一个网络,可以看到默认创建网络使用的桥接模式 [root@localhost jdk]# docker network create a_network 0321393ceb8b7ffe1de1bb658ec683e7dba0f8403a0c474ee72c2bd896cf7438 [root@localhost jdk]# docker network ls NETWORK ID NAME DRIVER SCOPE 0321393ceb8b a_network bridge local 434c8b2478c5 bridge bridge local 9a997978179d host host local 505d72cea94b none null local # 删除网络 [root@localhost jdk]# docker network rm a_network a_network [root@localhost jdk]# docker network ls NETWORK ID NAME DRIVER SCOPE 434c8b2478c5 bridge bridge local 9a997978179d host host local 505d72cea94b none null local# 查看网络源数据 [root@localhost jdk]# docker network inspect bridge [{"Name": "bridge","Id": "434c8b2478c521bcbd14e1bdbd9b9e0d6c393c0fc9039b878891ef130f813cb2","Created": "2024-03-28T17:20:21.900870152+08:00","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": {},"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": {}} ]
-
Docker network 作用 :
- 容器间的互联和通信以及端口映射
- 容器IP变动时候可以通过服务名直接网络通信而不受影响。
五、网络分类
1. 简介
网络模式 | 简介 | 使用方式 |
---|---|---|
bridge | 为每个容器分配、设置IP 等,并将容器连接到一个 docker0 虚拟网桥,默认为该模式 | 使用 --network bridge 指定,默认使用 docker0 |
host | 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的 IP 和端口 | 使用 --network host 指定 |
none | 容器有独立的 Network namespace,但并没有对其进行任何网络设置,如分配 veth pair 和网桥连接、IP等 | 使用 --network none 指定 |
container | 新创建的容器不会创建自己Id网络和配置自己的IP,而是和一个指定的容器共享IP,端口范围等 | 使用 --network container:[容器Name 或 容器Id] 指定 |
2. 网络模式的作用
Docker 容器内的IP会改变,当启动多个 Docker 容器后,如果其中一个容器关闭或删除后,新启动的容器可能会占用原容器的IP。
如下:新建u1、u2 两个容器后,将u2 容器移除后新建u3 容器,u3 容器会占用 u2 容器原先的ip
# 启动两个容器 u1 和 u2
[root@192 ~]# docker run --name u1 -it ubuntu /bin/bash
root@a40f76b02f32:/# [root@192 ~]#
[root@192 ~]# docker run --name u2 -it ubuntu /bin/bash
root@28f1845f8908:/# [root@192 ~]#
[root@192 ~]#
[root@192 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
28f1845f8908 ubuntu "/bin/bash" 4 seconds ago Up 3 seconds u2
a40f76b02f32 ubuntu "/bin/bash" 11 seconds ago Up 10 seconds u1
[root@192 ~]#
# 查看 u2 容器的 ip 信息 : 172.17.0.3
[root@192 ~]# docker inspect 28f1845f8908 | tail -n 20"bridge": {"IPAMConfig": null,"Links": null,"Aliases": null,"MacAddress": "02:42:ac:11:00:03","NetworkID": "dd2946f2d5feb529b371f4106d068184117ae41117470754225e28e8403ed46b","EndpointID": "fdd0c6a54e4af8f5636cafe71d07baa870579503e83af1ecec6595e210f6240d","Gateway": "172.17.0.1","IPAddress": "172.17.0.3","IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"DriverOpts": null,"DNSNames": null}}}}
]
# 查看 u1 容器的 ip 信息 : 172.17.0.2
[root@192 ~]# docker inspect a40f76b02f32 | tail -n 20"bridge": {"IPAMConfig": null,"Links": null,"Aliases": null,"MacAddress": "02:42:ac:11:00:02","NetworkID": "dd2946f2d5feb529b371f4106d068184117ae41117470754225e28e8403ed46b","EndpointID": "c01654faf05f3bc8e509ce057f6671a439d6615499f4cfdea74808d50f89948f","Gateway": "172.17.0.1","IPAddress": "172.17.0.2","IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"DriverOpts": null,"DNSNames": null}}}}
]
# 移除 u2 容器
[root@192 ~]# docker rm -f u2
u2
# 新建 u3 容器
[root@192 ~]# docker run --name u3 -it ubuntu /bin/bash
root@cdb7a6902
[root@192 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cdb7a69023b0 ubuntu "/bin/bash" 21 seconds ago Up 19 seconds u3
a40f76b02f32 ubuntu "/bin/bash" 3 minutes ago Up 3 minutes u1
# u3 容器ip已经占用了 u2 容器ip
[root@192 ~]# docker inspect cdb7a69023b0 | tail -n 20"bridge": {"IPAMConfig": null,"Links": null,"Aliases": null,"MacAddress": "02:42:ac:11:00:03","NetworkID": "dd2946f2d5feb529b371f4106d068184117ae41117470754225e28e8403ed46b","EndpointID": "f8374d1ad6e676d80592d0333b53b53c3ec2bdb17176156ff4a38d1798598709","Gateway": "172.17.0.1","IPAddress": "172.17.0.3","IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"DriverOpts": null,"DNSNames": null}}}}
]
3. 详细介绍
3.1 bridge 模式
- Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一个宿主机内的容器接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
- docker run的时候,没有指定–network的话,默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig就苦役看到docker0和自己create的network
- 网桥docker0创建一对对等虚拟设备接口,一个叫veth,另一个叫eth0,成对匹配:
- 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫 veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫做 veth pair)。
- 每个容器实例内部也有一块网卡,容器内的网卡接口叫做eth0。
- docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
如下,可以得知,宿主机的 eth0@if21
和 veth1138365@if20
是一一对应关系, 即上面途中中 eth0 和 veth 的映射关系:
宿主机 通过 ip addr | tail -n 4 命令可以看到 21: veth1138365@if20
内容, 如下
[root@192 ~]# ip addr | tail -n 4
21: veth1138365@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether da:b9:2f:97:a3:b0 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet6 fe80::d8b9:2fff:fe97:a3b0/64 scope link valid_lft forever preferred_lft forever
容器中通过 ip addr
命令可以看到 20: eth0@if21:
的内容,
[root@192 ~]# docker run -it tomcat:7 /bin/bash
root@47ea54bf9136:/usr/local/tomcat# ip addr
1: 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 forever
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/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
3.2 host 模式
- 直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行 NAT 转换。
- 容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network space。
- 容器将不会虚拟出自己的网卡,而是直接使用宿主机的 IP 和端口。
如下:
# 使用 host 模式启用 tomcat,可以直接通过宿主机IP + 8080 端口访问 tomcat
[root@192 ~]# docker run -d --network host --name tom_host tomcat:7
需要注意:
-
通过
docker inspect tom_host
命令查看通过 host 模式启动的容器,可以看到其网络模式为 host,并且因为容器使用的主机的网络IP(可以直接通过宿主机IP + 8080 端口访问 tomcat) ,所以 Gateway、IPAddress 都为空 -
如果在 docker run 命令中同时使用了 --network host 和 -p端口映射,则会出现如下警告:
[root@192 ~]# docker run -d -p 8083:8080 --network host --name tom_host1 tomcat:7 WARNING: Published ports are discarded when using host network mode 1f16087c5322ed824f4ae9068788064dec16fe652f2429e3deb811b659735b3a
因为此时已经使用了host模式,本身就是直接使用的宿主机的IP和端口,此时的-p端口映射就没有了意义,也不会生效,端口号还是会以主机端口号为主。
正确做法是:不再进行-p端口映射,或者改用bridge模式
3.3 none 模式
none 模式会禁用网络功能。在none模式下,并不为docker容器进行任何网络配置。进入容器内,使用 ip addr查看网卡信息,只能看到 lo(本地回环网络127.0.0.1网卡)。
如下:
[root@192 ~]# docker run -d --network none --name tom_none tomcat:7
e41b460b6c11a032f97e4ae8172a434a8832dda98673beb366112c400862a3d1
[root@192 ~]#
[root@192 ~]#
[root@192 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e41b460b6c11 tomcat:7 "catalina.sh run" 3 seconds ago Up 2 seconds tom_none
19929b93c3c1 tomcat:7 "catalina.sh run" 10 minutes ago Up 10 minutes tom_host
[root@192 ~]#
[root@192 ~]#
[root@192 ~]#
[root@192 ~]# docker exec -it tom_none /bin/bash
root@e41b460b6c11:/usr/local/tomcat# ip addr
1: 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 forever
3.4 container 模式
新建的容器和已经存在的一个容器共享网络IP配置,而不是和宿主机共享。
新创建的容器不会创建自己的网卡、IP,而是和一个指定的容器共享IP、端口范围。两个容器除了网络共享,其他的如文件系统、进程列表依然是隔离的。
[root@192 ~]# docker run -it --name alpine_bridge alpine /bin/sh# 指定和 alpine_bridge 容器共享网络
[root@192 ~]# docker run -it --network container:alpine_bridge --name alpine_container alpine /bin/sh
/ # [root@192 ~]#
[root@192 ~]#
[root@192 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5c43081ef94c alpine "/bin/sh" 3 seconds ago Up 3 seconds alpine_container
4f6f1d00e4ca alpine "/bin/sh" 35 seconds ago Up 34 seconds alpine_bridge
此时使用 ip addr
查看两台容器的网络,会发现两台容器的eth0网卡内的IP等信息完全相同。
如果关掉了alpine_bridge 容器,因为alpine_container的网络使用的alpine_bridge 共享网络,所以关掉 alpine_bridge 后,alpine_container的eth0网卡也随之消失了。
需要注意:
- 如下:因为 container 模式下两个容器公用 IP 端口信息,因此启用第二个容器时因为 8080 端口被占用导致启动失败。
[root@192 ~]# docker run -d --name tom_bridge tomcat:7 67e7f5ae6f9ed22f535b975f096dc3d1553c5a6ec1c2e1f5dd8562f83361a987 [root@192 ~]# [root@192 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 67e7f5ae6f9e tomcat:7 "catalina.sh run" 3 seconds ago Up 3 seconds 8080/tcp tom_bridge e41b460b6c11 tomcat:7 "catalina.sh run" 3 minutes ago Up 3 minutes tom_none 19929b93c3c1 tomcat:7 "catalina.sh run" 13 minutes ago Up 13 minutes tom_host [root@192 ~]# docker run -d -p 8081:8080 --network container:tom_bridge --name tom_container tomcat:7 docker: Error response from daemon: conflicting options: port publishing and the container type network mode. See 'docker run --help'.
3.5 自定义网络模式
# 创建两个容器
[root@192 ~]# docker run -d --name tom1 tomcat:7
b1bfe74b3fb47974159ce1c5be9e98a87dfca7467bb0c585b566ae36417ddb64
[root@192 ~]# docker run -d --name tom2 tomcat:7
3c7bd1ccfbc636a48127af15b759eda4858057e9c6f73346d59a34d3b0fb0dbd
[root@192 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c7bd1ccfbc6 tomcat:7 "catalina.sh run" 54 seconds ago Up 53 seconds 8080/tcp tom2
b1bfe74b3fb4 tomcat:7 "catalina.sh run" 58 seconds ago Up 57 seconds 8080/tcp tom1
[root@192 ~]# docker exec -it tom1 /bin/bash
# 通过 容器名无法互相 ping 通,如果通过固定IP则容器的固定IP会变化
root@b1bfe74b3fb4:/usr/local/tomcat# ping tom1
ping: tom1: Name or service not known# 1. 自定义网络模式,默认使用的是桥接模式
[root@192 ~]# docker network create kingfish_network
0e49e8d8480d630ef3d97caf5eec330c9a11a249211f53b49609eeecc2a7ad81
[root@192 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
dd2946f2d5fe bridge bridge local
9a997978179d host host local
0e49e8d8480d kingfish_network bridge local
505d72cea94b none null local# 使用自定义的网络模式创建容器
[root@192 ~]# docker run -d --network kingfish_network --name tom_1 tomcat:7
5492cafbe433e4e47fc0f95a182954eb6a0213dd9838f16df054ff6009e54937
[root@192 ~]# docker run -d --network kingfish_network --name tom_2 tomcat:7
da0cd3f3641aaca58adb2c464f4f1d43e059aec7dcd151fe03aae901f95ab1d5
# 进入其中一个容器
[root@192 ~]# docker exec -it tom_1 /bin/bash
# 可以通过容器名称 PING 通服务
root@5492cafbe433:/usr/local/tomcat# ping tom_2
PING tom_2 (172.18.0.3) 56(84) bytes of data.
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=2 ttl=64 time=0.043 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=3 ttl=64 time=0.142 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=4 ttl=64 time=0.213 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=5 ttl=64 time=0.061 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=6 ttl=64 time=0.059 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=7 ttl=64 time=0.063 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=8 ttl=64 time=0.178 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=9 ttl=64 time=0.637 ms
需要注意:
- docker中还有一个 --link 进行容器网络互联,但是已经被标记为过时的,可能会在将来的版本中移除这个功能,推荐使用自定义网络替换link。Link 命令的使用如下:
# 启动一台mysql容器 # --name 为容器指定一个别名 docker run --name mysql-matomo -p 3308:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.28# 启动另一个容器,通过--link连接到mysql容器 # --link 容器名称:本容器连接对方时的别名 docker run -d -p 8888:80 --link mysql-matomo:db --name matomo matomo:4.9.0# 此时,在matomo容器中,便可以通过 db 这个hostname连接到mysql-matomo容器,而无须再通过ip # 连接地址:db:3306
六、参考内容
B 站 尚硅谷 Docker 视频
https://www.yuque.com/tmfl/cloud/dketq0